【问题标题】:Merge rows by pattern in R在R中按模式合并行
【发布时间】:2021-02-21 15:14:16
【问题描述】:

我正在尝试按模式合并行。

数据框只有一列(字符串),通常应遵循日期、公司名称和薪水的模式。但是,有些情况就是没有薪水。

有没有一种方法可以按日期模式合并行?通过这样做,我可以稍后将它们拆分为列。我不想早点做 pivot_wider 的原因是公司名称和薪水之间可能不匹配 - 不平衡的行。所以我认为最好按日期模式合并行,因为日期永远不会丢失并遵循模式。

数据集:

# A tibble: 10 x 1
   detail                                        
   <chr>                                         
 1 26 January 2021                               
 2 NatWest Group - Bristol, BS2 0PT              
 3 26 January 2021                               
 4 NatWest Group - Manchester, M3 3AQ            
 5 15 February 2021                              
 6 Brook Street - Liverpool, Merseyside, L21AB   
 7 £13.84 per hour                               
 8 16 February 2021                              
 9 Anglo Technical Recruitment - London, WC2N 5DU
10 £400.00 per day   

数据集的输入:

structure(list(detail = c("26 January 2021", "NatWest Group - Bristol, BS2 0PT", 
"26 January 2021", "NatWest Group - Manchester, M3 3AQ", "15 February 2021", 
"Brook Street - Liverpool, Merseyside, L21AB", "£13.84 per hour", 
"16 February 2021", "Anglo Technical Recruitment - London, WC2N 5DU", 
"£400.00 per day")), row.names = c(NA, -10L), class = c("tbl_df", 
"tbl", "data.frame"))

预期结果:

 detail                                                                         
 <chr>                                                                          
1 26 January 2021 NatWest Group - Bristol, BS2 0PT                               
2 26 January 2021 NatWest Group - Manchester, M3 3AQ                             
3 15 February 2021 Brook Street - Liverpool, Merseyside, L21AB £13.84 per hour   
4 16 February 2021 Anglo Technical Recruitment - London, WC2N 5DU £400.00 per day

预期结果的输入:

df <- structure(list(detail = c("26 January 2021 NatWest Group - Bristol, BS2 0PT", 
                          "26 January 2021 NatWest Group - Manchester, M3 3AQ", "15 February 2021 Brook Street - Liverpool, Merseyside, L21AB £13.84 per hour", 
                          "16 February 2021 Anglo Technical Recruitment - London, WC2N 5DU £400.00 per day")), row.names = c(NA, -4L), class = c("tbl_df", 
                                                                                  "tbl", "data.frame"))

【问题讨论】:

    标签: r merge stringr


    【解决方案1】:

    在每一行前加上一个标签,然后使用read.dcf 创建一个3 列字符矩阵mat。最后,我们将其转换为每个逻辑记录一个元素的字符向量,但您可能只想使用mat,因为这似乎是一种更有用的格式。

    我们假设日期具有 %d %B %Y 格式(有关百分比代码,请参见 ?strptime),工资行以 £ 开头,其他行是地址行。

    library(dplyr)
    
    mat <- dat %>%
      mutate(detail = case_when(
        !is.na(as.Date(detail, "%d %B %Y")) ~ paste("\nDate:", detail), 
        grepl("^£", detail) ~ paste("Salary:", detail),
        TRUE ~ paste("Address:", detail))) %>%
      { read.dcf(textConnection(.$detail)) }
    
    mat %>%
      apply(1, toString) %>%
      sub(", NA$", "", .)
    

    更新

    简化的假设和代码。

    【讨论】:

      【解决方案2】:

      另一个解决方案假设仅第一行包含日期。无论两个日期之间的行数如何,它都会起作用..

      library(tidyverse)
      df %>% group_by(d = cumsum(str_detect(detail, "^(^\\d\\d? \\w+ \\d{4})$"))) %>%
             mutate(c = paste0("Col", as.character(row_number()))) %>%
        pivot_wider(id_cols = d, values_from = detail, names_from = c)
      
      # A tibble: 4 x 4
      # Groups:   d [4]
            d Col1             Col2                                           Col3           
        <int> <chr>            <chr>                                          <chr>          
      1     1 26 January 2021  NatWest Group - Bristol, BS2 0PT               NA             
      2     2 26 January 2021  NatWest Group - Manchester, M3 3AQ             NA             
      3     3 15 February 2021 Brook Street - Liverpool, Merseyside, L21AB    £13.84 per hour
      4     4 16 February 2021 Anglo Technical Recruitment - London, WC2N 5DU £400.00 per day
      

      【讨论】:

      • 哇,这太棒了。我不得不说我很难决定我应该接受哪种解决方案,因为一个显然是我问题的答案,但你的显然更进一步,解决了我的终极痛苦。我觉得我应该奖励那些更进一步的人,因为我在我的问题中明确表示,拆分列将是我的下一步。我不知道rleid(),它做得很好。谢谢!
      • @Henrik,是的,你是对的。这里是多余的。感谢您指出。
      【解决方案3】:

      这是一个纯粹的data.table 方法

      library( data.table )
      #make it a data.table
      setDT( df )
      #first, summarise by block separated by days, collapse the text, using @@ as separator
      ans <- df[, .( paste0( detail, collapse = "@@") ), 
                by = .(d = cumsum( ( grepl( "[0-9]{2} [a-zA-Z]+ [0-9]{4}", detail) ) ) ) ]
      #split text again to cols, based on te @@ introduced in the collapse/ Number of cols is dynamic!
      ans[, paste0( "Col", 1:length( tstrsplit(ans$V1, "@@" ))) := tstrsplit( V1, "@@" )][, V1 := NULL ][]
      
      #    d             Col1                                           Col2            Col3
      # 1: 1  26 January 2021               NatWest Group - Bristol, BS2 0PT            <NA>
      # 2: 2  26 January 2021             NatWest Group - Manchester, M3 3AQ            <NA>
      # 3: 3 15 February 2021    Brook Street - Liverpool, Merseyside, L21AB £13.84 per hour
      # 4: 4 16 February 2021 Anglo Technical Recruitment - London, WC2N 5DU £400.00 per day
      

      【讨论】:

        【解决方案4】:

        这是一种 data.table 方法,它使用dcast()rowid() 重塑为宽格式。它返回一个包含四列的 data.table:记录号、日期、 公司名称和薪水。

        library(data.table)
        setDT(df1)[, rn := cumsum(!is.na(lubridate::dmy(detail)))]
        dcast(df1, rn ~ rowid(rn, prefix = "Col"), value.var = "detail")
        
           rn             Col1                                           Col2            Col3
        1:  1  26 January 2021               NatWest Group - Bristol, BS2 0PT            <NA>
        2:  2  26 January 2021             NatWest Group - Manchester, M3 3AQ            <NA>
        3:  3 15 February 2021    Brook Street - Liverpool, Merseyside, L21AB £13.84 per hour
        4:  4 16 February 2021 Anglo Technical Recruitment - London, WC2N 5DU £400.00 per day
        

        为了检测开始新记录的行,即带有日期的行,这种方法借鉴了Anil's answer 以及G.Grothendieck's

        dcast() 允许将所有内容打包成一个“单行”(如果不计算 library() 调用):

        library(data.table)
        library(lubridate)
        dcast(setDT(df1), cumsum(!is.na(dmy(detail))) ~ rowid(cumsum(!is.na(dmy(detail))), prefix = "Col"), 
              value.var = "detail")
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-04-26
          • 2016-07-18
          • 1970-01-01
          • 1970-01-01
          • 2015-03-10
          • 2021-11-29
          • 1970-01-01
          相关资源
          最近更新 更多