我刚在剧本中发现这个警告有点奇怪。
# Warning message:
# In rbindlist(list(DT.1, DT.2)) : NAs introduced by coercion
观察1:这是一个可重现的例子:
require(data.table)
DT.1 <- data.table(x = letters[1:5], y = 6:10)
DT.2 <- data.table(x = LETTERS[1:5], y = 11:15)
# works fine
rbindlist(list(DT.1, DT.2))
# x y
# 1: a 6
# 2: b 7
# 3: c 8
# 4: d 9
# 5: e 10
# 6: A 11
# 7: B 12
# 8: C 13
# 9: D 14
# 10: E 15
但是,现在如果我将列x
转换为factor
(已订购或未订购)并执行相同操作:
DT.1[, x := factor(x)]
rbindlist(list(DT.1, DT.2))
# x y
# 1: a 6
# 2: b 7
# 3: c 8
# 4: d 9
# 5: e 10
# 6: NA 11
# 7: NA 12
# 8: NA 13
# 9: NA 14
# 10: NA 15
# Warning message:
# In rbindlist(list(DT.1, DT.2)) : NAs introduced by coercion
但rbind
做得很好!
rbind(DT.1, DT.2) # where DT.1 has column x as factor
# do.call(rbind, list(DT.1, DT.2)) # also works fine
# x y
# 1: a 6
# 2: b 7
# 3: c 8
# 4: d 9
# 5: e 10
# 6: A 11
# 7: B 12
# 8: C 13
# 9: D 14
# 10: E 15
如果列x
也是ordered factor
,则可以重现相同的行为。由于帮助页?rbindlist
说:Same as do.call("rbind",l), but much faster.
,我猜这不是理想的行为?
这是我的会话信息:
# R version 3.0.0 (2013-04-03)
# Platform: x86_64-apple-darwin10.8.0 (64-bit)
#
# locale:
# [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
#
# attached base packages:
# [1] stats graphics grDevices utils datasets methods base
#
# other attached packages:
# [1] data.table_1.8.8
#
# loaded via a namespace (and not attached):
# [1] tools_3.0.0
观察2:关注@ AnandaMahto的另一个有趣的观察,颠倒了顺序:
# column x in DT.1 is still a factor
rbindlist(list(DT.2, DT.1))
# x y
# 1: A 11
# 2: B 12
# 3: C 13
# 4: D 14
# 5: E 15
# 6: 1 6
# 7: 2 7
# 8: 3 8
# 9: 4 9
# 10: 5 10
此处,DT.1
中的列被静默强制转换为numeric
修改:为了澄清,这与rbind(DT2, DT1)
的行为相同,DT1的列x是一个因素。 rbind
似乎保留了第一个参数的类。我将在此处留下这一部分并提及在这种情况下,这是所需的行为,因为rbindlist
是rbind
的更快实现。
观察3:如果现在,两个列都会转换为因子:
# DT.1 column x is already a factor
DT.2[, x := factor(x)]
rbindlist(list(DT.1, DT.2))
# x y
# 1: a 6
# 2: b 7
# 3: c 8
# 4: d 9
# 5: e 10
# 6: a 11
# 7: b 12
# 8: c 13
# 9: d 14
# 10: e 15
此处,来自x
的{{1}}列丢失(/替换为DT.2
的列)。如果订单相反,则会发生完全相反的情况(DT.1
的第x列将替换为DT.1
的第x列)。
通常,处理DT.2
中的factor
列似乎存在问题。
答案 0 :(得分:7)
我认为rbindlist
应用于因子时,会将因子的数值组合在一起,并仅使用与第一个列表元素关联的级别。
在此错误报告中: http://r-forge.r-project.org/tracker/index.php?func=detail&aid=2650&group_id=240&atid=975
# Temporary workaround:
levs <- c(as.character(DT.1$x), as.character(DT.2$x))
DT.1[, x := factor(x, levels=levs)]
DT.2[, x := factor(x, levels=levs)]
rbindlist(list(DT.1, DT.2))
另一种观点是:
DT3 <- data.table(x=c("1st", "2nd"), y=1:2)
DT4 <- copy(DT3)
DT3[, x := factor(x, levels=x)]
DT4[, x := factor(x, levels=x, labels=rev(x))]
DT3
DT4
# Have a look at the difference:
rbindlist(list(DT3, DT4))$x
# [1] 1st 2nd 1st 2nd
# Levels: 1st 2nd
do.call(rbind, list(DT3, DT4))$x
# [1] 1st 2nd 2nd 1st
# Levels: 1st 2nd
至于观察1,发生的事情类似于:
x <- factor(LETTERS[1:5])
x[6:10] <- letters[1:5]
x
# Notice however, if you are assigning a value that is already present
x[11] <- "S" # warning, since `S` is not one of the levels of x
x[12] <- "D" # all good, since `D` *is* one of the levels of x
答案 1 :(得分:2)
rbindlist
超快,因为它不会检查rbindfill
或do.call(rbind.data.frame,...)
您可以使用这样的解决方法来确保将因子强制转换为字符。
DT.1 <- data.table(x = factor(letters[1:5]), y = 6:10)
DT.2 <- data.table(x = LETTERS[1:5], y = 11:15)
for(ii in seq_along(DDL)){
ff <- Filter(function(x) is.factor(DDL[[ii]][[x]]), names(DDL[[ii]]))
for(fn in ff){
set(DDL[[ii]], j = fn, value = as.character(DDL[[ii]][[fn]]))
}
}
rbindlist(DDL)
或(内存效率较低)
rbindlist(rapply(DDL, classes = 'factor', f= as.character, how = 'replace'))
答案 2 :(得分:0)
该错误未在R 4.0.2
和data.table 1.13.0
中修复。当我尝试rbindlist()
的两个DT,其中一个具有因子列时,另一个空,最终结果使该列损坏,并且因子值被破坏(\ n随机出现;级别被破坏,引入了NA)。
解决方法是不要用空的DT重新列出DT,而用也有有效载荷数据的其他DT重新列出DT。尽管这需要一些样板代码。