什么是你遇到的最大的R-gotcha?

有一天你真的感到惊讶吗? 我想我们都会从分享中获益。

这是我的:在列表索引中, my.list[[1]]不是my.list[1] 。 在R的早期学会了这一点。

删除数据框中的行将导致添加非唯一命名的行,然后出错:

 > a<-data.frame(c(1,2,3,4),c(4,3,2,1)) > a<-a[-3,] > a c.1..2..3..4. c.4..3..2..1. 1 1 4 2 2 3 4 4 1 > a[4,1]<-1 > a Error in data.frame(c.1..2..3..4. = c("1", "2", "4", "1"), c.4..3..2..1. = c(" 4", : duplicate row.names: 4 

那么这里发生了什么:

  1. 一个四行的data.frame被创build,所以rownames是c(1,2,3,4)

  2. 第三行被删除,所以rownames是c(1,2,4)

  3. 第四行被添加,R自动设置行号等于索引,即4,所以行名称是c(1,2,4,4)。 这是非法的,因为行名应该是唯一的。 我不明白为什么R应该允许这种行为。在我看来,R应该提供一个唯一的行名。

[哈德利在评论中指出这一点。]

当使用序列作为迭代的索引时,最好使用seq_along()函数,而不是像1:length(x)那样的东西。

在这里我创build了一个向量,两种方法都返回相同的结果:

 > x <- 1:10 > 1:length(x) [1] 1 2 3 4 5 6 7 8 9 10 > seq_along(x) [1] 1 2 3 4 5 6 7 8 9 10 

现在使vector为NULL

 > x <- NULL > seq_along(x) # returns an empty integer; good behavior integer(0) > 1:length(x) # wraps around and returns a sequence; this is bad [1] 1 0 

这会在循环中造成一些混淆:

 > for(i in 1:length(x)) print(i) [1] 1 [1] 0 > for(i in seq_along(x)) print(i) > 

加载数据时自动创build因子。 你不假思索地把一个数据框中的一列当作字符来处理,而且这样做很好,直到你做了一些尝试将值更改为一个不是某个值的值。 这将产生一个警告,但留下你的数据框中的NA …

当你的R脚本中出现意想不到的错误时,检查一下因素是不能责怪的。

在将matrix子集化到单个维度时遗忘drop = FALSE参数,从而丢弃对象类:

 R> X <- matrix(1:4,2) R> X [,1] [,2] [1,] 1 3 [2,] 2 4 R> class(X) [1] "matrix" R> X[,1] [1] 1 2 R> class(X[,1]) [1] "integer" R> X[,1, drop=FALSE] [,1] [1,] 1 [2,] 2 R> class(X[,1, drop=FALSE]) [1] "matrix" R> 

首先,让我说,我理解在二进制系统中表示数字的基本问题。 不过,我认为可以轻易改进的一个问题是,如果十进制值超出了R的典型范围,则表示数字。

 x <- 10.2 * 100 x 1020 as.integer(x) 1019 

我不介意结果是否表示为一个整数,当它真的可以表示为一个整数。 例如,如果该值确实是1020,那么打印x的值就可以了。 但是在这种情况下,当打印x时,像1020.0这样简单的东西就会使这个值更加明显,该值不是一个整数,也不能表示为一个整数。 当存在一个非常小的小数部分时,R应该默认为某种指示。

必须允许NANaNInf组合可能是令人讨厌的。 他们的行为有所不同,而testing一个人不一定会为其他人工作:

 > x <- c(NA,NaN,Inf) > is.na(x) [1] TRUE TRUE FALSE > is.nan(x) [1] FALSE TRUE FALSE > is.infinite(x) [1] FALSE FALSE TRUE 

然而,testing这些问题的最安全的方法是:

 > is.finite(x) [1] FALSE FALSE FALSE 

总是testing当你有NA时会发生什么!

我经常需要注意的一件事(在许多痛苦的经历之后)是NA值。 R函数易于使用,但没有任何编程方式可以解决您的数据问题。

例如,具有NA任何净向量操作等于NA 。 这是令人惊讶的表面:

 > x <- c(1,1,2,NA) > 1 + NA [1] NA > sum(x) [1] NA > mean(x) [1] NA 

这可以推断出其他更高级别的function。

换句话说, 缺省值通常与默认的测量值一样重要 。 许多函数具有na.rm=TRUE/FALSE默认值; 值得花一些时间来决定如何解释这些默认设置。

编辑1:马雷克说得很好。 NA值也会导致索引中的混淆行为。 例如:

 > TRUE && NA [1] NA > FALSE && NA [1] FALSE > TRUE || NA [1] TRUE > FALSE || NA [1] NA 

当您尝试创build条件expression式(对于if语句)时,也是如此:

 > any(c(TRUE, NA)) [1] TRUE > any(c(FALSE, NA)) [1] NA > all(c(TRUE, NA)) [1] NA 

当这些NA值最终成为向量索引时,可能会出现许多意想不到的事情。 这对于R来说都是很好的行为,因为这意味着你必须小心谨慎。 但一开始可能会引起重大的麻烦。

忘记strptime()和朋友返回POSIXt POSIXlt其中length()总是九 – 转换为POSIXct有助于:

 R> length(strptime("2009-10-07 20:21:22", "%Y-%m-%d %H:%M:%S")) [1] 9 R> length(as.POSIXct(strptime("2009-10-07 20:21:22", "%Y-%m-%d %H:%M:%S"))) [1] 1 R> 

round函数总是循环到偶数。

 > round(3.5) [1] 4 > round(4.5) [1] 4 

整数的math与双打有细微的差别(有时候复杂也是奇怪的)

更新他们在R 2.15中修正了一些事情

 1^NA # 1 1L^NA # NA (1+0i)^NA # NA 0L %/% 0L # 0L (NA from R 2.15) 0 %/% 0 # NaN 4L %/% 0L # 0L (NA from R 2.15) 4 %/% 0 # Inf 

我很惊讶,没有人提到这一点,但:

TF可以被覆盖, TRUEFALSE不可以。

例:

 x <- sample(c(0,1,NA), 100, T) T <- 0:10 mean(x, na.rm=T) # Warning in if (na.rm) x <- x[!is.na(x)] : # the condition has length > 1 and only the first element will be used # Calls: mean -> mean.default # [1] NA plot(rnorm(7), axes=T) # Warning in if (axes) { : # the condition has length > 1 and only the first element will be used # Calls: plot -> plot.default # Warning in if (frame.plot) localBox(...) : # the condition has length > 1 and only the first element will be used # Calls: plot -> plot.default 

ctrf+F欺骗我。 Shane在他的评论中提到了这一点 。

阅读数据可能会比您想象的更成问题。 今天我发现,如果你使用read.csv() ,如果.csv文件中的一行是空的, read.csv()会自动跳过它。 这对大多数应用程序是有意义的,但是如果你从几千个文件中自动提取(例如)27行的数据,而且前面的一些行可能是也可能不是空白的,如果你不小心,事情可能会非常糟糕错误。

我现在用

 data1 <- read.table(file_name, blank.lines.skip = F, sep = ",") 

当你导入数据时,请检查你是否在做你以前一直在做的事情。

all.equal()函数的棘手行为。

我的连续性错误之一是比较一组浮点数。 我有一个CSV像:

 ... mu, tau, ... ... 0.5, 1.7, ... 

读取文件并尝试对数据进行子集化有时可能有效,但有时会失败 – 当然,由于一次又一次陷入浮点陷阱。 首先,数据只包含整数值,然后它总是转换成实际值,你知道这个故事。 比较应该用all.equal()函数来代替==运算符,但是当然,我第一次写的代码使用了后一种方法。

是的,酷,但all.equal()为相同的数字返回TRUE ,但如果失败的文本错误消息:

 > all.equal(1,1) [1] TRUE > all.equal(1:10, 1:5) [1] "Numeric: lengths (10, 5) differ" > all.equal(1:10, c(1:5,1:5)) [1] "Mean relative difference: 0.625" 

解决方法是使用isTRUE()函数:

 if (!isTRUE(all.equal(x, y, tolerance=doubleErrorRate))) { ... } 

我有多less次阅读all.equals()描述…

这个受到很大的伤害,所以我花了好几个小时给bug报告添加评论。 我没有得到我的意愿,但至lessR的下一个版本将产生一个错误。

 R> nchar(factor(letters)) [1] 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 

更新:从R 3.2.0(可能更早)开始,此示例现在生成一条错误消息。 正如在下面的评论中提到的,一个因子不是一个向量,nchar()需要一个向量。

 R> nchar(factor(letters)) Error in nchar(factor(letters)) : 'nchar()' requires a character vector R> is.vector(factor(letters)) [1] FALSE 
  1. 通过忘记包含空括号意外地列出函数的源代码:例如“ls”与“ls()”

  2. 真假不要把它作为预定义的常量,像Matlab,C ++,Java,Python; 必须使用TRUE&FALSE

  3. 不可见的返回值:例如“.packages()”不返回任何内容,而“(.packages())”返回包名称的字符向量

例如,数字3.14是一个数字常量,但expression式+3.14和-3.14是对函数+-

 > class(quote(3.14)) [1] "numeric" > class(quote(+3.14)) [1] "call" > class(quote(-3.14)) [1] "call" 

请参阅John Chambers书中的第13.2节“ 用于数据分析的软件 – 用R编程”

零长度vector有一些怪癖:

 R> kk=vector(mode="numeric",length=0) R> kk numeric(0) R> sum(kk) [1] 0 R> var(kk) [1] NA 

$运算符中的部分匹配:这适用于列表,但也适用于data.frame

 df1 <- data.frame(foo=1:10, foobar=10:1) df2 <- data.frame(foobar=10:1) df1$foo # Correctly gets the foo column df2$foo # Expect NULL, but this returns the foobar column!!! # So, should use double bracket instead: df1[["foo"]] df2[["foo"]] 

[[运算符也有一个exact标志,但是在默认情况下它是幸运的。

部分匹配也会影响attr

 x1 <- structure(1, foo=1:10, foobar=10:1) x2 <- structure(2, foobar=10:1) attr(x1, "foo") # Correctly gets the foo attribute attr(x2, "foo") # Expect NULL, but this returns the foobar attribute!!! # So, should use exact=TRUE attr(x1, "foo", exact=TRUE) attr(x2, "foo", exact=TRUE) 

使用列表,有一些不直观的东西:

当然, [[[需要一些习惯。 对于列表, [返回(可能是1)元素的列表,而[[返回列表中的元素]。

列表创build:

 # When you're used to this: x <- numeric(5) # A vector of length 5 with zeroes # ... this might surprise you x <- list(5) # A list with a SINGLE element: the value 5 # This is what you have to do instead: x <- vector('list', 5) # A vector of length 5 with NULLS 

那么,如何将NULL插入到列表中?

 x <- list("foo", 1:3, letters, LETTERS) # A sample list x[[2]] <- 1:5 # Put 1:5 in the second element # The obvious way doesn't work: x[[2]] <- NULL # This DELETES the second element! # This doesn't work either: x[2] <- NULL # This DELETES the second element! # The solution is NOT very intuitive: x[2] <- list(NULL) # Put NULL in the second element # Btw, now that we think we know how to delete an element: x <- 1:10 x[[2]] <- NULL # Nope, gives an ERROR! x <- x[-2] # This is the only way for atomic vectors (works for lists too) 

最后是一些高级的东西,比如通过嵌套列表进行索引:

 x <- list(a=1:3, b=list(c=42, d=13, e="HELLO"), f='bar') x[[c(2,3)]] # HELLO (first selects second element and then it's third element) x[c(2,3)] # The second and third elements (b and f) 

R中的一个很大的混淆是[i, drop = TRUE]确实下降了因子水平,但[i, j, drop = TRUE]不是!

 > df = data.frame(a = c("europe", "asia", "oceania"), b = c(1, 2, 3)) > df$a[1:2, drop = TRUE] [1] europe asia Levels: asia europe <---- drops factor levels, works fine > df[1:2,, drop = TRUE]$a [1] europe asia Levels: asia europe oceania <---- does not drops factor levels! 

有关更多信息,请参阅: drop = TRUE不会在data.frame中删除因子级别,而在vector中则会降级

自动重复向量( “回收” )用作索引:

 R> all.numbers <- c(1:5) R> all.numbers [1] 1 2 3 4 5 R> good.idxs <- c(T,F,T) R> #note unfortunate length mismatch R> good.numbers <- all.numbers[good.idxs] R> good.numbers [1] 1 3 4 R> #wtf? R> #why would you repeat the vector used as an index R> #without even a warning? 

从编译语言和Matlab出发,我偶尔会对function语言中函数的一个基本方面感到困惑:它们必须在使用之前被定义 ! R解释器parsing它们是不够的。 当你使用嵌套函数的时候,这大多数都是头脑发热。

在Matlab中,你可以这样做:

 function f1() v1 = 1; v2 = f2(); fprintf('2 == %d\n', v2); function r1 = f2() r1 = v1 + 1 % nested function scope end end 

如果你尝试在R中做同样的事情,你必须先把嵌套的函数,或者你得到一个错误! 只是因为你已经定义了这个函数,直到它被分配给一个variables,它才会在名字空间中! 另一方面,函数可以引用尚未定义的variables。

 f1 <- function() { f2 <- function() { v1 + 1 } v1 <- 1 v2 = f2() print(sprintf("2 == %d", v2)) } 

从今天开始:qnorm()接受概率,pnorm()接受Quantile。

对于我来说,这是一种反直观的方式,当你使用write.csv将data.frame导出到一个文本文件,然后导入它之后,需要添加一个额外的参数来获得完全相同的data.frame,如下所示:

 write.csv(m, file = 'm.csv') read.csv('m.csv', row.names = 1) # Note the row.names argument 

我也在SO中发布了这个问题 ,被@BenBolkerbuild议作为这个Q的答案。

applyfunction集不仅适用于matrix,而且适用于multidimensional array。 在我的研究中,我经常有一个例如大气温度的数据集。 它存储在一个multidimensional array中,其维数为x,y,level,time ,从现在起称为multi_dim_array 。 一个模型的例子是:

 multi_dim_array = array(runif(96 * 48 * 6 * 100, -50, 50), dim = c(96, 48, 6, 100)) > str(multi_dim_array) # xy lev time num [1:96, 1:48, 1:6, 1:100] 42.4 16 32.3 49.5 24.9 ... 

使用apply可以轻松获得:

 # temporal mean value > str(apply(multi_dim_array, 4, mean)) num [1:100] -0.0113 -0.0329 -0.3424 -0.3595 -0.0801 ... # temporal mean value per gridcell (x,y location) > str(apply(multi_dim_array, c(1,2), mean)) num [1:96, 1:48] -1.506 0.4553 -1.7951 0.0703 0.2915 ... # temporal mean value per gridcell and level (x,y location, level) > str(apply(multi_dim_array, c(1,2,3), mean)) num [1:96, 1:48, 1:6] -3.839 -3.672 0.131 -1.024 -2.143 ... # Spatial mean per level > str(apply(multi_dim_array, c(3,4), mean)) num [1:6, 1:100] -0.4436 -0.3026 -0.3158 0.0902 0.2438 ... 

这使得applymargin理由似乎更不直观。 我首先,为什么不使用“行”和“col”,而不是1和2.但事实上,它也适用于数组的更多维度清楚地说明为什么使用这样的margin是优选的。