我想对0到1之间的值向量进行分类。值低于.001,值高于.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
}
答案 0 :(得分:5)
首先,一些测试数据:
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
希望这有帮助!
x[x < .001 | x > .1] = NA
out <- ceiling(x*100)/100
与AKE使用地板的建议几乎相同。
这样可以获得与循环相同的结果。
答案 1 :(得分: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技巧和提示的良好讨论。
答案 2 :(得分: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。 第三行将剩余的非零值提升到范围的最高值(向上舍入)并将它们返回到原始比例。
答案 3 :(得分: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
最右边的闭合参数移动了通常最左边的区间闭包,尽管在这个例子中它并不重要,因为没有随机抽取是在边界上。但是,破坏输入数据通常不是一个好主意。我希望x
是原始数据的副本。另一种方法是省略1+
,而是使用findInterval
第二个参数中的间隔,例如c(-Inf, 0.001, seq(0.1, 1, by=0.1) , Inf)