按组编号

时间:2012-01-25 03:57:27

标签: r

假设我们有以下数据库:

ID  Shoot  hit
1     10    2
1      9    3
1      8    1
2     10    8
2      8    8
2     11   10
2      7    2
3      9    2
4      6    6
4      6    5
.
.

我希望在每个组中分配数字,在这种情况下,每个ID如:

ID Shoot hit number.in.group
1   10     2    1
1    9     3    2
1    8     1    3
2   10     8    1
2    8     8    2 
2   11    10    3
2    7     2    4
3    9     2    1
4    6     6    1
4    6     5    2
    .
    .

我可以使用循环轻松完成。像这样的东西会起作用:

df$number.in.group = rep(1,nrow(df))

for(i in 2:nrow(df))
    if(df$ID[i]==df$ID[i-1]){
     df$number.in.group[i] = df$number.in.group[i-1] + 1 }  

我的问题是,除了使用循环之外,还有其他功能或更优雅的方法吗?

7 个答案:

答案 0 :(得分:8)

您可以使用rlesequence

dat <- read.table(text = "ID  Shoot  hit
+ 1     10    2
+ 1      9    3
+ 1      8    1
+ 2     10    8
+ 2      8    8
+ 2     11   10
+ 2      7    2
+ 3      9    2
+ 4      6    6
+ 4      6    5",sep = "",header = TRUE)

> sequence(rle(dat$ID)$lengths)
 [1] 1 2 3 1 2 3 4 1 1 2

的确,我认为sequence的目的只是为了这个目的。

答案 1 :(得分:6)

> dat$number.in.group <- ave(dat$ID,dat$ID, FUN=seq_along)
> dat
   ID Shoot hit number.in.group
1   1    10   2               1
2   1     9   3               2
3   1     8   1               3
4   2    10   8               1
5   2     8   8               2
6   2    11  10               3
7   2     7   2               4
8   3     9   2               1
9   4     6   6               1
10  4     6   5               2

答案 2 :(得分:2)

可能有更好的方法,但可以在ID上使用tapply并在返回序列的函数中进行折腾。

# Example data
dat <- data.frame(ID = rep(1:3, c(2, 3, 5)), val = rnorm(10))

# Using tapply with a function that returns a sequence
dat$number.in.group <- unlist(tapply(dat$ID, dat$ID, function(x){seq(length(x))}))
dat

导致

> dat
   ID          val number.in.group
1   1 -0.454652118               1
2   1 -2.391824247               2
3   2  0.530832021               1
4   2 -1.671043812               2
5   2 -0.045261549               3
6   3  2.311162484               1
7   3 -0.525635803               2
8   3  0.008588811               3
9   3  0.078942033               4
10  3  0.324156111               5

答案 3 :(得分:2)

df$number.in.group <- unlist(lapply(as.vector(unlist(rle(df$ID)[1])), function(x) 1:x))

答案 4 :(得分:2)

使用dplyr

dat <- data.frame(ID = rep(1:3, c(2, 3, 5)), val = rnorm(10))

library(dplyr)
dat %>% group_by(ID) %>%
    mutate(number.in.group = 1:n())

答案 5 :(得分:1)

这是另一种解决方案

require(plyr)
ddply(dat, .(ID), transform, num_in_grp = seq_along(hit))

答案 6 :(得分:0)

我比较了你的anwsers和IShouldBuyABoat是最有希望的。我发现即使数据集没有根据分组变量进行排序,也可以应用函数ave。

让我们考虑数据集:

dane<-data.frame(g1=c(-1,-2,-2,-2,-3,-3,-3,-3,-3),
             g2=c('reg','pl','reg','woj','woj','reg','woj','woj','woj'))

Joran anwser并应用于我的例子:

> sequence(rle(as.character(dane$g2))$lengths)
[1] 1 1 1 1 2 1 1 2 3

Simon Urbanek的主张和结果:

> unlist(lapply(table(dane$g2),seq.int))
  pl reg1 reg2 reg3 woj1 woj2 woj3 woj4 woj5 
   1    1    2    3    1    2    3    4    5 

IShouldBuyABoat代码提供正确的anwser:

> as.numeric(ave(as.character(dane$g1),as.character(dane$g1),FUN=seq_along))
[1] 1 1 2 3 1 2 3 4 5