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

时间:2009-10-08 00:48:13

标签: r r-faq

是否有某种R-gotcha让你有一天真的感到惊讶?我想我们都可以分享这些。

以下是我的:在列表索引中,my.list[[1]]不是my.list[1]。在R的早期就已经了解到这一点。

29 个答案:

答案 0 :(得分:42)

[哈德利指出了这一点in a comment。]

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

这里我创建了一个向量,两种方法都返回相同的东西:

> 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

现在制作向量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)
>

答案 1 :(得分:35)

加载数据时自动创建因子。您不假思索地将数据框中的列视为字符,这样做很有效,直到您尝试将值更改为不是某个级别的值。这将生成一个警告,但保留数据框中包含NA ...

如果您的R脚本出现意外错误,请检查因素是否应该受到指责。

答案 2 :(得分:32)

忘记将矩阵子集化为单维度的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> 

答案 3 :(得分:32)

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

> 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,因此rownames为c(1,2,3,4)

  2. 删除第三行,因此rownames为c(1,2,4)

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

答案 4 :(得分:23)

首先,让我说我理解在二进制系统中表示数字的基本问题。然而,我认为可以轻易改进的一个问题是当十进制值超出R的典型呈现范围时数字的表示。

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

我不介意结果是否真的可以表示为整数时表示为整数。例如,如果值真的是1020那么打印x就可以了。但是在这种情况下,当打印x时,像1020.0这样简单的事情会使得这个值不是一个整数并且不能表示为一个更明显。当存在未呈现的极小十进制分量时,R应该默认为某种指示。

答案 5 :(得分:20)

必须允许NANaNInf的组合,这可能很烦人。它们的行为不同,对其中一种的测试不一定适用于其他人:

> 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

然而,测试任何这些麻烦制造者最安全的方法是:

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

答案 6 :(得分:18)

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

我总是需要特别注意(在经历了许多痛苦的经历之后)NA值。 R函数易于使用,但没有任何编程方式可以克服数据问题。

例如,任何NA的净矢量运算都等于NA。从表面上看,这是“令人惊讶的”:

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

这可以推断到其他更高级别的功能。

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

编辑1:马雷克提出了一个很好的观点。 NA值也可能导致索引中出现令人困惑的行为。例如:

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

当您尝试创建条件表达式(对于if语句)时也是如此:

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

当这些NA值最终作为矢量索引时,可能会出现许多意外情况。这对R来说都是很好的行为,因为这意味着你必须小心缺少值。但它可能会在一开始就引起严重的麻烦。

答案 7 :(得分:13)

忘记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> 

答案 8 :(得分:13)

round函数始终舍入到偶数。

> round(3.5)
[1] 4  

> round(4.5)
[1] 4

答案 9 :(得分:12)

整数的数学与双打略有不同(有时复杂也很奇怪)

更新他们修复了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

答案 10 :(得分:11)

我很惊讶没人提这个,但是:

T&amp; F可以覆盖TRUE&amp; FALSE没有。

示例:

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

[edit] ctrf+F欺骗我。 Shane mention about this in his comment

答案 11 :(得分:8)

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))) {
    ...
}

我有多少次阅读all.equals()说明...

答案 12 :(得分:8)

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

我现在用

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

当您导入数据时,请检查您是否正在执行您实际认为自己正在做的事情一次又一次......

答案 13 :(得分:7)

这个受到了太大的伤害,我花了好几个小时为bug-report添加评论。我没有达到我的愿望,但至少下一版本的R会产生错误。

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

答案 14 :(得分:6)

  1. 忘记包含空括号,意外地列出了函数的源代码:例如“ls”与“ls()”

  2. true&amp; false不要将它剪切为预定义的常量,如Matlab,C ++,Java,Python;必须使用TRUE&amp; FALSE

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

答案 15 :(得分:5)

零长度向量有一些怪癖:

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

答案 16 :(得分:5)

$运算符中的部分匹配: 这适用于列表,但也适用于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标记,但值得庆幸的是TRUE默认情况。

部分匹配也会影响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)

答案 17 :(得分:5)

例如,数字3.14是数字常量,但表达式+3.14和-3.14是对函数+-的调用:

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

参见约翰钱伯斯书中的第13.2节Software for Data Analysis - Programming with R

答案 18 :(得分:4)

使用列表时,有一些不直观的事情:

当然,[[[之间的差异需要一些时间来适应。对于列表,[返回(可能是1个)元素的列表,而[[返回列表中的元素。

创建列表:

# 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)

答案 19 :(得分:4)

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

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?

答案 20 :(得分:4)

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 doesn't drop factor levels in data.frame while in vector it does

答案 21 :(得分:3)

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

答案 22 :(得分:3)

来自编译语言和Matlab,我偶尔会对函数式语言中函数的一个基本方面感到困惑:它们在使用之前必须定义 !仅仅让他们被R解释器解析是不够的。当您使用嵌套函数时,这主要是它的头部。

在Matlab中你可以这样做:

function f1()
  v1 = 1;
  v2 = f2();
  fprintf('2 == %d\n', v2);

  function r1 = f2()
    r1 = v1 + 1 % nested function scope
  end
end

如果您尝试在R中执行相同的操作,则必须先放置嵌套函数,否则会出错!仅仅因为你已经定义了这个函数,它就不会在命名空间中被分配给变量了!另一方面,该函数可以引用尚未定义 的变量。

f1 <- function() {
  f2 <- function() {
    v1 + 1
  }

  v1 <- 1

  v2 = f2()

  print(sprintf("2 == %d", v2))
}

答案 23 :(得分:3)

对我来说,这是一种反直觉的方式,当你使用write.csv将data.frame导出到文本文件时,然后要导入它,你需要添加一个额外的参数来获得完全相同的数据。框架,像这样:

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

我还在SO中发布了this question,并建议@BenBolker回答这个问题。

答案 24 :(得分:1)

apply函数集不仅适用于矩阵,而且适用于多维数组。在我的研究中,我经常有一个数据集,例如大气温度。它存储在维度为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)
#     x     y     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 ...

这使得margin的{​​{1}}参数看起来更不直观了。我首先说,为什么不使用“row”和“col”而不是1和2.但事实上它也适用于具有更多维度的数组,这清楚地表明为什么首选使用apply这是首选。

答案 25 :(得分:0)

您可以使用options(warn = 2),根据手册:

如果警告为两个或更大,则所有警告都将变为错误。

确实,警告变成了错误,但是,加油!发生此类错误后,代码仍继续运行!!!

source("script.R")
# ...
# Loading required package: bayesmeta
# Failed with error:  ‘(converted from warning) there is no package called ‘bayesmeta’’
# computing posterior (co)variances ... 
# (script continues running)
...

PS:但是从警告 do 转换而来的其他一些错误会停止脚本...所以我不知道,我很困惑。这确实停止了脚本:

Error in optimise(psiline, c(0, 2), adiff, a, as.matrix(K), y, d0, mn,  :
  (converted from warning) NA/Inf replaced by maximum positive value

答案 26 :(得分:0)

which.minwhich.max在使用比较运算符时的功能与预期相反,甚至可能给出错误的答案。因此,例如,尝试找出排序数字列表中的哪个元素是小于阈值的最大数字。 (即从100到200的顺序,这是小于110的最大数字)

set.seed(420)
x = seq(100, 200)
which(x < 110)
> [1]  1  2  3  4  5  6  7  8  9 10
which.max(x < 110)
> [1] 1
which.min(x < 110)
> [1] 11
x[11]
> [1] 110
max(which(x < 110))
>[1] 10
x[10]
> [1] 109

答案 27 :(得分:-1)

很难找到的脏污陷阱!剪切这样的多行表达式:

K <- hyperpar$intcept.sigma2
        + cov.NN.additive(x1$env, x2 = NULL, sigma2_int = hyperpar$env.sigma2_int, sigma2_slope = hyperpar$env.sigma2_slope)
        + hyperpar$env.sigma2 * K.cache$k.env

R仅会评估第一行,而其他两行只会浪费!它不会说任何警告,什么也没有!对于毫无戒心的用户,这是非常讨厌的背信弃义。实际上必须这样写:

K <- hyperpar$intcept.sigma2 +
        cov.NN.additive(x1$env, x2 = NULL, sigma2_int = hyperpar$env.sigma2_int, sigma2_slope = hyperpar$env.sigma2_slope) +
        hyperpar$env.sigma2 * K.cache$k.env

这不是很自然的写作方式。

答案 28 :(得分:-1)

这个!

all(c(1,2,3,4) == NULL)
$[1] TRUE

我在代码中进行了检查,我确实需要两个表都具有相同的列名:

stopifnot(all(names(x$x$env) == names(x$obsx$env)))

但是当x$x$env根本不存在时,检查通过了(评估为TRUE)!