我正在学习使用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的每个值并将结果字符串放入新列。
答案 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可能不会优化循环的内容。