使用 expand.grid() 生成的数据框中的逻辑比较

logical comparison in a data frame generated with expand.grid()

希望大家能帮我想出解决办法,因为我的结果真的出乎意料...

我使用函数 expand.grid() 从提供的向量的所有组合创建数据框。

vector1=seq(from=0.8,to=1.6,by=0.2)
vector2=c(seq(from=0.8,to=1.8,by=0.2),2.6)
vector3=seq(from=0.6,to=1.2,by=0.2)

data=expand.grid(F1= vector1,F2= vector2,F3= vector3)
data
    F1  F2  F3
1   0.8 0.8 0.6
2   1.0 0.8 0.6
3   1.2 0.8 0.6
4   1.4 0.8 0.6
5   1.6 1.0 0.6
6   0.8 1.0 0.6
7   1.0 1.0 0.6 
…   …   …   …

现在我想通过逻辑比较删除一些行。

data_remove=which(data[,1]-data[,2]>0.2)
data_remove
[1] 3   4   5   8   …   110 113 114 115 120

让我们看一下第 113 行,因为这是错误的 - 也许 data_remove 中的其他一些条目也是如此。

data
    F1  F2  F3
…   …   …   …
113 1.2 1.0 1.2
…   …   …   …

data[113,1]- data[113,2]
[1] 0.2

(data[113,1]- data[113,2])>0.2
[1] TRUE

这个结果让我感到困惑,因为

0.2>0.2
[1] FALSE

mode(data[113,1])
[1] “numeric”
mode(data[113,2])
[1] “numeric”

你能解释一下我哪里错了吗?

非常感谢!

一般问题:浮点运算

正如 RHertel 在他的评论中提到的,这与浮点运算有关,您可以在 this question 的答案中阅读更多相关信息。你会在那里找到你需要的一切,我不会进一步讨论这个,因为我没有任何有意义的补充。

你的具体例子的解决方案

您的具体示例可以通过处理整数并最终仅转换为您实际想要的数字来解决。这种方法也有其局限性,我将在最后回过头来讨论。

所以,我基本上是从定义三个向量和网格开始的,如下所示:

vector1 <- seq(from = 8, to = 16, by = 2)
vector2 <- c(seq(from = 8, to = 18, by = 2), 26)
vector3 <- seq(from = 6, to = 12, by = 2)
data <- expand.grid(F1 = vector1, F2 = vector2, F3 = vector3)

这样,我得到的数值比你定义的数值大10倍。但这最终很容易通过简单地除以 10 来纠正。优点是对于整数,比较按预期进行:

data_remove = which(data[,1] - data[,2] > 2)
head(data[data_remove, ])
##    F1 F2 F3
## 3  12  8  6
## 4  14  8  6
## 5  16  8  6
## 9  14 10  6
## 10 16 10  6
## 15 16 12  6

可以看到在所有情况下都满足条件。特别是,您问题中提到的第113行这次没有被删除。要获得您真正想要的数据,您只需除以 10:

data_new <- data[-data_remove, ]/10
head(data_new)
##     F1  F2  F3
## 1  0.8 0.8 0.6
## 2  1.0 0.8 0.6
## 6  0.8 1.0 0.6
## 7  1.0 1.0 0.6
## 8  1.2 1.0 0.6

此方法的局限性

我答应回到这个方法的局限性。从数学的角度来看,只要您只使用有理数,它总是有效的。例如,

seq(1/3, 5, by = 1/4)

可以用整数改写为

seq(4, 60, by = 3)/12

因为12是3和4的least common multiple,所以出现因数12。但是,这个序列不能用整数改写,因为其中有无理数:

seq(sqrt(2), 7*sqrt(3), by = pi/5)

没有因数 q 使得 q * sqrt(2)q * pi/5 都是整数。但是您仍然可以通过四舍五入来解决问题。逗号后四舍五入到两位数,整数表示的序列为

seq(141, 1212, by = 63)/100

对于非常大的数字,可能会出现另一个限制。如果您有很多相关数字,因此需要将序列乘以非常大的数字,比较将再次失败:

(1e18 + 1) > 1e18
## [1] FALSE

除了Stibus的详细解答(非常感谢)...

我的答案是RHertel的提示——两种解决方案。

让我们看一下向量 data_remove 并指定错误的条目 (8, 43, 78, 113)。

data_remove
[1]   3   4   5   8   9  10  15  38  39  40  43  44  45  50  73  74  75  78  79  80  85 108 109 110 113 114 115 120
length(data_remove)
[1]  28

我的第一个解决方案是使用round函数。在这里你必须定义 digits-argument.

data_remove1=which(round(data[,1]-data[,2],4)>0.2)
data_remove1
[1]   3   4   5   9  10  15  38  39  40  44  45  50  73  74  75  79  80  85 108 109 110 114 115 120
length(data_remove1)
[1] 24

当您将 digits-argument 增加到 16 或更高时,向量中再次出现四个错误条目。

data_remove1=which(round(data[,1]-data[,2],16)>0.2)
data_remove1
[1]   3   4   5   8   9  10  15  38  39  40  43  44  45  50  73  74  75  78  79  80  85 108 109 110 113 114 115 120
length(data_remove1)
[1] 28

data_remove1=which(round(data[,1]-data[,2],22)>0.2)
data_remove1
[1]   3   4   5   8   9  10  15  38  39  40  43  44  45  50  73  74  75  78  79  80  85 108 109 110 113 114 115 120
length(data_remove1)
[1] 28

我的第二个解决方案使用函数all.equal的矢量化。在这里也可以根据您的需要更改容差。

data_critical 是一个包含条目的向量,其中 data[1] 和 data[2] 的减法几乎精确为 0.2。

elementwise.all.equal=Vectorize(function(x,y,z) {isTRUE(all.equal(x,y,z))})
data_critical=which(elementwise.all.equal(data[,1]-data[,2],rep(0.2,length.out=length(data[,1])),1e-15)==TRUE)
data_critical
[1]   2   8  14  20  37  43  49  55  72  78  84  90 107 113 119 125
data_remove_correct=match(data_critical,data_remove)
data_remove_correct
[1] NA  4 NA NA NA 11 NA NA NA 18 NA NA NA 25 NA NA
data_remove_correct=data_remove_correct[!is.na(data_remove_correct)]
data_remove_correct
[1]  4 11 18 25
data_remove_perfect=data_remove[-data_remove_correct]
data_remove_perfect
[1]   3   4   5   9  10  15  38  39  40  44  45  50  73  74  75  79  80  85 108 109 110 114 115 120
length(data_remove_perfect)
[1] 24

为什么不是所有 data_critical 都出现在 data_remove 中?观察减法的结果——只有正结果出现在向量 data_remove.

data[2,1]-data[2,2]-0.2
[1] -5.551115e-17
data[8,1]-data[8,2]-0.2
[1] 1.665335e-16