【问题标题】:Concatenating rows and dropping the successive repetitions or repeating elements连接行并删除连续重复或重复元素
【发布时间】:2016-11-30 22:54:48
【问题描述】:

我有一个如下的数据框,我想根据票号连接序列中的行(如果有连续重复,则删除它们)并确定它们是如何传递给人们的。

    ticket<- c("1", "1", "1", "2", "2", "2", "2")
    name<- c("Olg", "Jan", "Jan", "Olg", "Jan", "Jan","Olg")
    df<- data.frame(ticket, name)

我想创建一个名为序列的变量列,它提供路径并抑制连续重复,如图所示(Olg-Jan-Jan 到 Olg-Jan 和 Olg-Jan-Jan-Olg 到 Olg-Jan-Olg)。有什么建议么?谢谢!

   seq<- c("Olg-Jan", "Olg-Jan", ""Olg-Jan", "Olg-Jan-Olg","Olg-Jan-Olg","Olg-Jan-Olg" )

【问题讨论】:

    标签: r dplyr plyr string-matching


    【解决方案1】:

    name 是一个因子(如果不是,我们可以将其转换为因子),因此我们使用底层数字因子代码来检查连续重复并删除它们。我们使用dplyr,以便我们可以轻松地按ticket 进行分组,并使用链接运算符(%&gt;%)将函数链接在一起。

    library(dplyr) 
    
    df %>% group_by(ticket) %>%
       filter(c(1, diff(as.numeric(name))) !=0) %>%
       summarise(sequence = paste(name, collapse="-"))
    
      ticket    sequence
    1      1     Olg-Jan
    2      2 Olg-Jan-Olg
    

    如果你想保留原始数据框的所有行并且只添加序列,那么你可以left_join上面的输出到你的原始数据框:

    df = df %>% 
      left_join(df %>% group_by(ticket) %>%
                  filter(c(1, diff(as.numeric(name))) !=0) %>%
                  summarise(sequence = paste(name, collapse="-")))
    
      ticket name    sequence
    1      1  Olg     Olg-Jan
    2      1  Jan     Olg-Jan
    3      1  Jan     Olg-Jan
    4      2  Olg Olg-Jan-Olg
    5      2  Jan Olg-Jan-Olg
    6      2  Jan Olg-Jan-Olg
    7      2  Olg Olg-Jan-Olg
    

    【讨论】:

      【解决方案2】:

      如果我理解正确的话......

      > df_to_list <- split(df, df$ticket)
      > df_to_list
      $`1`
        ticket name
      1      1  Olg
      2      1  Jan
      3      1  Jan
      
      $`2`
        ticket name
      4      2  Olg
      5      2  Jan
      6      2  Jan
      7      2  Olg
      

      现在我们将遍历并取消列出名称,然后删除连续出现相同名称的情况并绑定。

      new_df <- lapply(df_to_list, function(i){
      
        a <- as.character(unlist(i[['name']]))
      
        endr <- length(a) - 1
        b <- sapply(1:endr, function(x){
          a[x] != a[x+1]
        })
      
        c <- a[b]
      
        paste0(c, collapse = "-")
      
      }) %>% melt %>% select(ticket = L1, seq = value)
      
      > new_df
        ticket         seq
      1      1     Olg-Jan
      2      2 Olg-Jan-Olg
      

      这就是你所追求的吗?

      注意:使用 group_by 方法与这种方式的速度差异产生了有趣的输出时序。我将集合复制到 14000 行并将新数据框命名为 addf 并将两个解决方案包装到单独的函数 using_group 和 `no_group.

      > system.time(using_group(addf))
         user  system elapsed 
        0.012   0.000   0.011 
      > system.time(no_group(addf))
         user  system elapsed 
        0.004   0.000   0.004
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-09
        • 2023-01-02
        • 2020-03-30
        • 1970-01-01
        • 2018-12-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多