数据框和使用字符列时非常常见的错误

Ali*_*Ali 1 r character dataframe

data.frameR中有用的非常意外的行为来自于将character列保持为因子.如果不考虑,这会导致许多问题.例如,假设以下代码:

foo=data.frame(name=c("c","a"),value=1:2)
#   name val
# 1    c   1
# 2    a   2

bar=matrix(1:6,nrow=3)
rownames(bar)=c("a","b","c")
#   [,1] [,2]
# a    1    4
# b    2    5
# c    3    6
Run Code Online (Sandbox Code Playgroud)

那你对跑步的期望是bar[foo$name,]什么?它通常应该返回bar根据foo$name行'c'和'a' 命名的行.但结果却不同:

bar[foo$name,]
#   [,1] [,2]
# b    2    5
# a    1    4
Run Code Online (Sandbox Code Playgroud)

原因在于:foo$name不是字符向量,而是整数向量.

foo$name
# [1] c a
# Levels: a c
Run Code Online (Sandbox Code Playgroud)

为了获得预期的行为,我手动将其转换为字符向量:

foo$name = as.character(foo$name)
bar[foo$name,]
#   [,1] [,2]
# c    3    6
# a    1    4
Run Code Online (Sandbox Code Playgroud)

但问题是我们可能很容易错过执行此操作,并在我们的代码中隐藏了错误.有没有更好的解决方案?

Rei*_*son 6

这是一个功能,R正在记录中工作.这可以通过以下几种方式来处理:

  1. stringsAsFactors = TRUE在调用中使用参数data.frame().看到?data.frame
  2. 如果你厌恶这种行为,请通过全局设置选项

    options(stringsAsFactors = FALSE)
    
    Run Code Online (Sandbox Code Playgroud)
  3. (正如@JoshuaUlrich在评论中所指出的)第三种选择是将字符变量包装在中I(....).这会改变要分配给要包含的数据框组件的对象的类"AsIs".一般来说,这应该不是问题,因为对象继承(在这种情况下)类,"character"所以应该像以前一样工作.

您可以通过以下方式检查stringsAsFactors当前正在运行的R进程的默认值:

> default.stringsAsFactors()
[1] TRUE
Run Code Online (Sandbox Code Playgroud)

问题略宽data.frame()于范围,因为这也会影响read.table().在该函数中,以及上面的两个选项中,您还可以通过参数告诉R变量的所有类是什么colClasses,R将尊重它,例如

> tmp <- read.table(text = '"Var1","Var2"
+ "A","B"
+ "C","C"
+ "B","D"', header = TRUE, colClasses = rep("character", 2), sep = ",")
> str(tmp)
'data.frame':   3 obs. of  2 variables:
 $ Var1: chr  "A" "C" "B"
 $ Var2: chr  "B" "C" "D"
Run Code Online (Sandbox Code Playgroud)

  • 如果您采用此行为的全局更改方法,请务必在_all_中向您的帖子中包含警告,以达到此效果.你观察到的结果会不同于那些曾经试图这样做但却遭到抵制的人. (2认同)