在R中将多个data.table列转换为因子

18

当我试图将数据表的多列转换为因子列时,遇到了一个意外的问题。 我已经复制了如下:

library(data.table)
tst <- data.table('a' = c('b','b','c','c'))
class(tst[,a])
tst[,as.factor(a)]  #Returns expected result
tst[,as.factor('a'),with=FALSE] #Returns error

后面的命令会返回'Error in Math.factor(j) : abs not meaningful for factors'。我在试图将一组行转换为因子时,使用了tst[,lapply(cols, as.factor),with=FALSE],其中cols是我尝试转换为因子的行的集合。是否有任何解决方案或解决方法?


3
我已经增加了:Gracefully catch internal abs() error on j when with=FALSE but j is wrongly factor。需要对当with=FALSE但是j错误地被因子化时,捕获内部abs()错误的情况进行优雅的处理。 - Matt Dowle
2个回答

36

我找到了一个解决方案:

library(data.table)
tst <- data.table('a' = c('b','b','c','c'))
class(tst[,a])
cols <- 'a'
tst[,(cols):=lapply(.SD, as.factor),.SDcols=cols]

不过,前面提到的行为似乎有漏洞。


你试图使用因子作为数据表的索引 - 因子既不是字符也不是数值(它们是没有明确大小的分类值),因此数据表会报错。 - thelatemail
1
另外,tst[,as.factor(a)] 只是返回 as.factor(tst$a),并没有对数据表进行索引。尝试使用 tst[,1:5] 查看我的意思。 - thelatemail
1
如果您只有一列,可以尝试tst[, a := as.factor(a)],或者按照您所展示的方式操作,也可以在每个列上使用set进行循环。 - Arun
1
你的错误是因为你使用了 with=FALSE,而 j 只有很少的可能性。data.table 通过检查 j 是否为 逻辑字符 等来计算它,然后检查它们是否为列数... 因此检查 if (abs(j) > ncol(.)),其中 jfactor(a)。在这里,你对一个因子调用了 abs - Arun
我最初尝试使用 cols:=as.factor(cols) 快速更改多个列的类型。Arun建议使用for循环中的set,这种方法更受欢迎/更快吗? - tresbot
1
@tresbot,请看一下?set。 - Arun

4
这个问题已经在v1.8.11中得到了解决,但实现的方式可能不是你所期望的。从NEWS中可以看到:

FR#4867现在已经被实现。当xDT中的一列时,DT [,as.factor('x'),with=FALSE]现在等同于DT [,“x”,with=FALSE],而不是出现错误。感谢tresbot在Stack Overflow上的报告


部分解释:当使用with = FALSE时,不再将data.table的列视为变量。也就是说:

tst[, as.factor(a), with=FALSE] # would give "a" not found!

如果直接执行会出现错误"a" not found,但你可以采取以下方法:

tst[, as.factor('a'), with=FALSE]

实际上,您正在使用level="a"创建一个名为"a"的因子,并要求对其进行子集操作。这并没有太多意义。以data.frame为例:

DF <- data.frame(x=1:5, y=6:10)
DF[, c("x", "y")] # gives back DF

DF[, factor(c("x", "y"))] # gives back DF again, not factor columns
DF[, factor(c("x", "x"))] # gives back two columns of "x", still integer, not factor!

所以,当你使用with=FALSE时,基本上你要应用一个因子的是不是那一列的元素,而只是那一列的列名... 我希望我已经成功地传达了这个差异。如果有任何困惑,请随意编辑/评论。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接