我有一个如下所示的数据框:
x <- data.frame("Name" = c("Jorge", "Jorge", "Jorge", "Tom", "Tom", "Jerry", "Tom", "Tom", "Jorge"),
"Date" = c("10-13-2017", "10-12-2017", "10-11-2017", "10-10-2017", "10-09-2017",
"10-08-2017", "10-07-2017", "10-06-2017", "10-05-2017"))
我想制作一个列有&#34; Streak&#34;名称在名称列中。我希望的最终结果如下:
Name Date Streak
Jorge 10-13-2017 3
Jorge 10-12-2017 2
Jorge 10-11-2017 1
Tom 10-10-2017 2
Tom 10-09-2017 1
Jerry 10-08-2017 1
Tom 10-07-2017 2
Tom 10-06-2017 1
Jorge 10-05-2017 1
我目前拥有的是:
streak <- 1
for(i in NROW(x):2){
j <- i - 1
if(as.character(x[i, "Name"]) == as.character(x[j, "Name"])){
streak = streak + 1
x[i, "Streak"] = streak
}
else{
x[i, "Streak"] = 1
streak <- 1
}
}
这给出了:
Name Date Streak
Jorge 10-13-2017 3
Jorge 10-12-2017 3
Jorge 10-11-2017 2
Tom 10-10-2017 1
Tom 10-09-2017 2
Jerry 10-08-2017 1
Tom 10-07-2017 1
Tom 10-06-2017 2
Jorge 10-05-2017 1
这是不对的,我正在努力弄清楚如何获得预期的输出。理想情况下,我不需要使用for循环,因为这是一个包含数万行的大型数据集,所以它非常慢。
所以我的问题:
1。有没有办法在不使用for循环的情况下执行此操作? 2. 如何从底部开始计数,以便输出反映出所需的条纹?
感谢您的帮助。
答案 0 :(得分:4)
您可以使用rle
函数(运行长度编码)...
x$Streak <- unlist(sapply(rle(as.character(x$Name))$lengths, seq, 1, -1))
x
Name Date Streak
1 Jorge 10-13-2017 3
2 Jorge 10-12-2017 2
3 Jorge 10-11-2017 1
4 Tom 10-10-2017 2
5 Tom 10-09-2017 1
6 Jerry 10-08-2017 1
7 Tom 10-07-2017 2
8 Tom 10-06-2017 1
9 Jorge 10-05-2017 1
这将获取每个名称的运行长度,为每个名称生成一个向下计数的序列,然后(通过不列出)将它们转换为向量。
答案 1 :(得分:1)
我们可以使用data.table
。将'data.frame'转换为'data.table'(setDT(x)
),按'Name'的run-length-id(rleid
)分组,得到与行数序列相反的行并指定(:=
)来创建'Streak'列
library(data.table)
setDT(x)[, Streak := rev(seq_len(.N)), rleid(Name)]
x
# Name Date Streak
#1: Jorge 10-13-2017 3
#2: Jorge 10-12-2017 2
#3: Jorge 10-11-2017 1
#4: Tom 10-10-2017 2
#5: Tom 10-09-2017 1
#6: Jerry 10-08-2017 1
#7: Tom 10-07-2017 2
#8: Tom 10-06-2017 1
#9: Jorge 10-05-2017 1