4

我想对 0 到 1 之间的值向量进行分类。低于 0.001 的值,高于 0.10 或不感兴趣的值。因此,我希望这些范围内的值是 NA。

当我运行下面的代码时,我收到一个警告:

Error in if (x[i] > 0.001 & x[i] <= 0.01) x[i] = 0.01 :  missing value where TRUE/FALSE needed

如何修复我的代码?

for (i in 1:length(x))
  {
    if (x[i] <= .001)
      x[i] = NA
    if (x[i] > .001 & x[i] <= .01)
      x[i] = .01
    if (x[i] > .01 & x[i] <= .02)
      x[i] = .02
    if (x[i] > .02 & x[i] <= .03)
      x[i] = .03
    if (x[i] > .03 & x[i] <= .04)
      x[i] = .04
    if (x[i] > .04 & x[i] <= .05)
      x[i] = .05
    if (x[i] > .05 & x[i] <= .06)
      x[i] = .06
    if (x[i] > .06 & x[i] <= .07)
      x[i] = .07
    if (x[i] > .07 & x[i] <= .08)
      x[i] = .08
    if (x[i] > .08 & x[i] <= .09)
      x[i] = .09
    if (x[i] > .09 & x[i] <= .10)
      x[i] = .10
    if (x[i] > .10 & x[i] <= 1)
      x[i] = NA
  }
4

4 回答 4

6

首先,一些测试数据:

set.seed(1); x = dnorm(rnorm(100))/(sample(1:100, 100, replace=TRUE))

子集可以通过以下方式完成:

x[x < .001] = NA
x[x > .1] = NA

或者,您可以将其组合在一个语句中:

x[x < .001 | x > .1] = NA

更新:回答为什么您的代码不起作用

如果它确实在那里找到了一个,你就会遇到问题NA,所以从你的for循环中删除它们,但是在你运行循环之前索引它们,以便你以后可以删除它们。

temp = which(x < .001 | x > .1) # Index the values you want to set as NA

for从循环中删除以下条件:

if (x[i] > .10 & x[i] <= 1)
  x[i] = NA
if (x[i] <= .001)
  x[i] = NA

运行你的for循环,然后使用temp将值设置为NA应该是NA.

x[temp] = NA

希望这可以帮助!

更新 2:两行

x[x < .001 | x > .1] = NA
out <- ceiling(x*100)/100

与 AKE 使用地板的建议几乎相同。

这应该会得到与循环相同的结果。

于 2012-06-23T13:06:38.217 回答
1

您应该尝试使用矢量化函数,而不是使用显式for循环,例如非常方便的ifelse. 以下是如何NAs在您的示例中重新编码:

> x <- ifelse(x <= 0.001 | x > 0.1, NA, x)

要重新编码其他值,您可以尝试一些“聪明”的使用cut

> x <- (cut(x, breaks=seq(0.01, 0.09, 0.01), labels=FALSE) / 100) + 0.01

尽管可能有更好(和更透明)的方法。在 R中避免显式循环的原因for是,与矢量化替代方案相比,它们的效率非常低。R Inferno很好地讨论了这个和其他 R 技巧和技巧 。

于 2012-06-23T13:19:04.143 回答
0

虽然您的解决方案在概念上有效,但它是“蛮力”,这意味着大量输入,不会扩展到稍微不同的问题,并且执行起来也很慢。

R 允许使用向量,因此如果您的逻辑适用于 0 到 1 之间的任意数字,那么它应该适用于值介于 0 和 1 之间的向量。

尝试以下操作:

      y=((floor(100*x))       # all values < 0.01 map to 0
      if y>10 then y=0        # force values > 0.1 to 0
      if y>0, then (y+1)/100  # for non-zero values, map to the upper interval, then return to original scale.

第一行将所有小于 0.01 的值压缩为 0。第二行将所有大于 0.1 的值压缩为 0。第三行将剩余的非零值提升到范围的最大值(向上舍入)并将它们返回到原始值规模。

于 2012-06-23T13:12:34.613 回答
0

findInterval函数可以有效地用于这个非常结构化的选择问题。它生成一个索引,可以“查找”或为特定间隔中的值选择所需的结果:

x <- rnorm(1000)
x <- c(NA, seq(0.1, 1, by=0.1), NA)[
            1+ findInterval(x, c(0.001, seq(0.1, 1, by=0.1)) ,rightmost.closed=TRUE) ]
#---------------
table(x)
x
0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9   1 
 34  38  48  44  29  30  26  20  17  31 
> table(is.na(x))

FALSE  TRUE 
  317   683

rightmost.closed 参数改变了通常最左边的区间闭包,尽管在这个例子中它并不重要,因为没有随机抽取在边界上。不过,销毁输入数据通常不是一个好主意。我希望x是您原始数据的副本。这样做的另一种方法是省略第二个参数1+中的间隔,而是使用间隔,例如findIntervalc(-Inf, 0.001, seq(0.1, 1, by=0.1) , Inf)

于 2012-06-23T13:51:49.903 回答