【问题标题】:logical comparison in a data frame generated with expand.grid()使用 expand.grid() 生成的数据框中的逻辑比较
【发布时间】:2017-01-26 08:25:08
【问题描述】:

希望你能帮我找到解决办法,因为我的结果实在是出乎意料……

我使用函数 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”

你能解释一下我的错误在哪里吗?

非常感谢!

【问题讨论】:

  • 这是这个经典问题stackoverflow.com/q/9508518 的变体。由于数值不准确,差异不完全是0.2。尝试显示(data[113,1]- data[113,2]) - 0.2。结果不会完全为零。
  • 感谢您的评论。但是我该如何处理这个问题呢?在您提到的经典问题中,他们正在谈论all.equal……好吧,我可以四舍五入data[113,1]-data[113,2]。但是有没有更优雅的方式呢?

标签: r logical-operators


【解决方案1】:

一般问题:浮点运算

正如 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 是因为 12 是 3 和 4 的least common multiple。但是,由于其中的无理数,这个数列不能用整数重写:

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

【讨论】:

  • “优点是整数 [...]”——在 R 术语中,这些不是整数。此外,如果“整数”足够大,比较再次失败(我猜你知道):1e44+1L &gt; 1e44 # FALSE
  • @Frank 感谢您的评论。我知道它们不是数据类型意义上的整数。我想改写“整数”,但不确定这个词是否会被理解。你怎么看?我真的没有考虑过非常大的整数,但你当然是对的。我将在讨论该方法的局限性时添加评论。
  • 是否有可能克服数字非常大的问题?
  • 如果你的问题中有非常大的数字,你可以通过相反的过程使它们变小:除以某个数字使它们变小,最后再乘以。如果这是不可能的,这可能意味着您的向量非常大,当您尝试使用grid.expand() 时,您可能会遇到内存问题。如果您绝对需要使用大整数,可以使用 gmp 包,例如 gmp::as.bigz(123456789012345678901234567890)
【解决方案2】:

除了 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-函数。在这里你必须定义数字参数。

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

当您将数字参数增加到 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

【讨论】:

    猜你喜欢
    • 2021-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多