【问题标题】:Adding a column that counts sequential numbers添加计算序号的列
【发布时间】:2018-08-28 13:16:35
【问题描述】:

我想添加一个计算连续值数量的列。我在这里看到的大部分内容是如何计算重复值 (1,1,1,1,1),我想在数字增加 1 时计算 a (5,6,7,8,9) . ID 列是我所拥有的,而计数器列是我想要创建的。谢谢!

ID Counter  
5  1  
6  2  
7  3  
8  4  
10 1  
11 2  
13 1  
14 2  
15 3  
16 4 

【问题讨论】:

  • 你能添加一个有效输出的样本吗?
  • sequence(rle(c(0, cumsum(!diff(df$Counter) %in% 0:1)))$lengths) 可以工作
  • 试试ave(dat$ID,cumsum(c(FALSE,diff(dat$ID)!=1)),FUN=seq_along)。
  • 1 1 1 1 2 3 4 类型的向量的期望输出是什么?
  • @DavidArenburg 与原版相同。 1 1 1 1 2 3 4 只有最后 4 个不同。如果它是 2 2 2 2 3 4 5 所需的输出仍然是 1 1 1 1 2 3 4

标签: r


【解决方案1】:

使用dplyr 包的解决方案。想法是计算每个数字之间的差异来创建一个分组列,然后将计数器分配给每个组。

library(dplyr)

dat2 <- dat %>%
  mutate(Diff = ID - lag(ID, default = 0),
         Group = cumsum(Diff != 1)) %>%
  group_by(Group) %>%
  mutate(Counter = row_number()) %>%
  ungroup() %>%
  select(-Diff, -Group)
dat2
# # A tibble: 10 x 2
#       ID Counter
#    <int>   <int>
#  1     5       1
#  2     6       2
#  3     7       3
#  4     8       4
#  5    10       1
#  6    11       2
#  7    13       1
#  8    14       2
#  9    15       3
# 10    16       4

数据

dat <- read.table(text = "ID
5   
6  
7  
8  
10  
11  
13  
14  
15  
16",
                  header = TRUE, stringsAsFactors = FALSE)

【讨论】:

    【解决方案2】:

    循环版本很简单:

    for (i in 2:length(ID)) 
      if (diff(ID)[i-1] == 1) 
        counter[i] <- counter[i-1] +1
      else
        counter[i] <- 1
    

    但是这个循环在 n > 10^4 时会执行得很糟糕!我会尝试考虑一个矢量解决方案!

    【讨论】:

    • 你可以在循环外计算diff(ID),而不是为每个i计算它。
    • 有超过 100 万行,非常感谢您的帮助!
    • @StéphaneLaurent 是的,你是对的!找到一个超快的矢量解决方案,一会就贴出来!
    • @StéphaneLaurent 当我尝试这样做时,它给了我一个错误,说替换有 1564109 行,数据有 1564110。我想我可能是因为它无法计算第一个?有没有办法解决这个问题?
    • @user10256905 是的,第一个值必须是 1!但请查看我的其他答案以获得更有效的算法!
    【解决方案3】:

    你可以使用

    s=df$ID-shift(df$ID)
    s[is.na(s)]=1   
    ave(s,cumsum(s!=1),FUN=seq_along)
    [1] 1 2 3 4 1 2 1 2 3 4
    

    【讨论】:

      【解决方案4】:

      这个仅使用高效的向量算术。思路如下:

      1.取ID差的累计和

      2.如果跳转大于一,则减去该值

      cum <- c(0, cumsum(diff(ID)))  # take the cumulative difference of ID
      ccm <- cum * c(1, (diff(ID) > 1))  # those with jump > 1 will remain its value
      
      # subtract value with jump > 1 for all following numbers (see Link for reference)
      # note: rep(0, n) is because ccm[...] starts at first non null value
      
      counter <- cum - c(rep(0, which(diff(dat) != 1)[1]),
                         ccm[which(ccm != 0)][cumsum(ccm != 0)]) + 1
      enter code here
      

      注意事项:

      这应该可以有效地处理您的数百万数据!

      【讨论】:

        【解决方案5】:

        另一种解决方案:

          breaks <- c(which(diff(ID)!=1), length(ID))
          x <- c(breaks[1], diff(breaks))
          unlist(sapply(x, seq_len))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-05-18
          • 2021-08-06
          • 1970-01-01
          • 2017-12-31
          • 1970-01-01
          • 1970-01-01
          • 2018-01-05
          相关资源
          最近更新 更多