【问题标题】:numbering by groups [duplicate]按组编号[重复]
【发布时间】:2012-02-18 08:06:02
【问题描述】:

假设我们有以下数据库:

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 }  

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

【问题讨论】:

  • 在将问题标记为重复问题时,我们通常不会担心日期。另一个问题有更多、更高质量的答案。

标签: r


【解决方案1】:

如果你想要单线,类似

df$number.in.group = unlist(lapply(table(df$ID),seq.int))

【讨论】:

  • 这与sequence 的代码非常接近,不是吗?
  • 好吧,sequence(X) 被定义为 unlist(lapply(X,seq_len)) 所以,是的,你可以把它写成 sequence(table(df$ID)) - 我只是更喜欢使用直接函数而不是包装器 - 节省时间 ;) [而且更少要记住的功能:P]。
  • 你就像 Neo;你从源代码的角度来思考!
  • 相信我,当你对 R 进行黑客攻击时,你必须这样做;)
  • unlist(lapply()) 相比sapply() 有类似的优势吗?
【解决方案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】:

    您可以只使用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 正是为了这个目的。

    【讨论】:

      【解决方案4】:
      df$number.in.group <- unlist(lapply(as.vector(unlist(rle(df$ID)[1])), function(x) 1:x))
      

      【讨论】:

      • 老鼠我看到 joran 也比我更有效地击败了我
      【解决方案5】:
      > 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
      

      【讨论】:

        【解决方案6】:

        这是另一个解决方案

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

        【讨论】:

        • val 对应于hit。查看编辑后的答案
        【解决方案7】:

        我比较了您的回答,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 代码给出了正确的答案:

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

        【讨论】:

          【解决方案8】:

          使用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())
          

          【讨论】:

            猜你喜欢
            • 2013-06-06
            • 2017-06-20
            • 2021-06-04
            • 1970-01-01
            • 2018-01-26
            • 2018-05-08
            • 1970-01-01
            • 2013-10-20
            • 2019-05-11
            相关资源
            最近更新 更多