在data.table中使用`by`参数

时间:2014-11-17 10:30:38

标签: r data.table

我正在学习使用R,更具体地说是data.table包。 现在我发现有时候我会尝试以不能使用data.table的方式直观地解决问题。 特别是当我尝试将相同的操作应用于data.table中的每一行并经常使用该操作来填充新列或修改现有列时。 例如,我创建了下一个命令,以应用于我粘贴在下面的表格。在开始时,列C不存在,但我通过应用正确的方法创建了它。

DT[,C:=ifelse(nchar(unlist(strsplit(B,"-"))[1]) == 4,paste("0",unlist(strsplit(B,"-"))[1],sep=""),unlist(strsplit(B,"-"))[1])]

但是应用此命令只会在C的每一行中给出10:00的值。 表:

Id          A           B         C
 1         41 10:00-10:15     10:00
 2         38   9:15-9:30     09:15
 3         39   9:30-9:45     09:30
 4         40  9:45-10:00     09:45
 5         57 14:00-14:15     14:00
 6         59 14:30-14:45     14:30
 7         58 14:15-14:30     14:15
 8         56 13:45-14:00     13:45
 9         91 22:30-22:45     22:30
10         89 22:00-22:15     22:00

然后在StackOverflow上的某个地方(对不起,我丢失了链接)我发现有人在做同样的事情但使用了by参数。这将使我的命令如下:“

DT[,C:=ifelse(nchar(unlist(strsplit(B,"-"))[1]) == 4,paste("0",unlist(strsplit(B,"-"))[1],sep=""),unlist(strsplit(B,"-"))[1]),by=1:nrow(DT)]

这给了我正确的结果。基本上与:

相同
for (row in 1:nrow(DT))
{
  DT[row,C:=ifelse(nchar(unlist(strsplit(DT[row,B],"-"))[1]) == 4,paste("0",unlist(strsplit(DT[row,B],"-"))[1],sep=""),unlist(strsplit(DT[row,B],"-"))[1])]
}

这使我感到困惑,因为阅读有关by的data.table的帮助页面,它说:

  

单个未加引号的列名,列名表达式的列表(),包含逗号分隔列名的单个字符串(其中空格很重要,因为列名称甚至在开头或结尾可能包含空格)或字符列名称的向量。

所以这让我觉得by只是指向列,但在这里我用它来表示行...有人可以解释发生了什么吗?


评论后的其他问题: 当我使用以下代码时

test <- data.table(matrix(1:10))
test[,V2:=V1+2]

# V1 V2
#  1  3
#  2  4
#  3  5
#  4  6
#  5  7
#  6  8
#  7  9
#  8 10
#  9 11
# 10 12

我得到了预期的结果。 V2包含V1的值,加上2。 为什么同样的方法在我上面的初始代码的情况下不起作用,我要求data.table分割列B的每个值并将结果字符串放入新列。

1 个答案:

答案 0 :(得分:2)

strsplit返回一个列表,您需要每个列表元素的第一个元素。这可以使用lapply或其中一个亲戚来实现。这里我使用vapply,它返回一个向量。零填充是在单独的步骤中完成的,因为ifelse不是此类性能的最佳选择。

DT <- read.table(text="Id          A           B         C
 1         41 10:00-10:15     10:00
 2         38   9:15-9:30     09:15
 3         39   9:30-9:45     09:30
 4         40  9:45-10:00     09:45
 5         57 14:00-14:15     14:00
 6         59 14:30-14:45     14:30
 7         58 14:15-14:30     14:15
 8         56 13:45-14:00     13:45
 9         91 22:30-22:45     22:30
10         89 22:00-22:15     22:00", header=TRUE, stringsAsFactors=FALSE)



library(data.table)
setDT(DT)
#extract first entry in each list element
DT[, C := vapply(strsplit(B,"-"), `[`, "string", i = 1)]
#pad with zero 
DT[nchar(C) == 4, C := paste0(0, C)]
#    Id  A           B     C
# 1:  1 41 10:00-10:15 10:00
# 2:  2 38   9:15-9:30 09:15
# 3:  3 39   9:30-9:45 09:30
# 4:  4 40  9:45-10:00 09:45
# 5:  5 57 14:00-14:15 14:00
# 6:  6 59 14:30-14:45 14:30
# 7:  7 58 14:15-14:30 14:15
# 8:  8 56 13:45-14:00 13:45
# 9:  9 91 22:30-22:45 22:30
#10: 10 89 22:00-22:15 22:00

在问题显示中使用by是在此处使用*apply的替代方法。但是,我不希望它在这个例子中更快,因为data.table可能不会优化循环的内容。