用于创建条纹列的for循环的替代

时间:2017-10-14 01:58:58

标签: r

我有一个如下所示的数据框:

 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. 如何从底部开始计数,以便输出反映出所需的条纹?

感谢您的帮助。

2 个答案:

答案 0 :(得分:4)

您可以使用rle函数(运行长度编码)...

在基数R中执行此操作
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