【问题标题】:Modifiy Table with R: Grouping of data 'intelligent'使用 R 修改表:数据“智能”分组
【发布时间】:2020-02-06 17:19:09
【问题描述】:

我有一个场景,即使使用 Excel,我也不确定如何实现自动化而不是手动完成。

我的 Excel 图表如下所示:

Country      Customer     Device     Level       DueDate
Germany      Aldi         XYZ        3           12.12.20
Germany      Aldi         ABC        3           08.12.20
Germany      Aldi         ZUI        4           08.12.20
USA          LIDL         XYZ        2           12.12.20
USA          LIDL         ABC        2           12.12.20
Jordan       Netto        XYZ        4           12.12.20
Jordan       Netto        ZUI        3           01.11.20

我希望我能正确地重现这种情况。 我的目标是总结CountryCustomer 相同且在Device 属性中不同的行。 这些应该通过创建额外的行(或替换现有的行?)以下列条件分组到一行/项目中:

  • Device 列中列出所有提到的设备,以; 或类似名称分隔
  • 对于Level,选择最大值
  • 对于DueDate选择最小值

例如,将三个起始元素组合为一个可以采用以下格式:

Country          Customer         Device          Level          DueDate
Germany          Aldi          XYZ;ABC;ZUI        4              08.12.20  <--- NEW
USA              LIDL             XYZ             2              12.12.20
USA              LIDL             ABC             2              12.12.20
Jordan           Netto            XYZ             4              12.12.20
Jordan           Netto            ZUI             3              01.11.20

所以分组的行被新的行替换。 我目前知道我必须做什么,但不知道如何执行此操作。也许这在Excel中也是可能的?我不知道有任何智能可以检查不同的单元格是否包含相同的值,然后使用模式将它们组合起来。 这可以用 R 更容易完成还是应该手动完成?

【问题讨论】:

    标签: r excel vba dataframe grouping


    【解决方案1】:

    这样的事情(在 R 中)有用吗?这使用了data.table 库,它非常适合像这样的聚合/分组。

    如果您只想要唯一的设备列表,请检查第二种方法:

    library(data.table)
    dt <- data.table(
      Country = c('G', 'G', 'G', 'U', 'U', 'J', 'J', 'G'),
      Customer = c('A', 'A', 'A', 'B', 'B', 'C', 'C', 'A'),
      Device = c('XYZ', 'ABC', 'ZUI', 'XYZ', 'ABC', 'XYZ', 'ZUI', 'XYZ'),
      Level = c(3, 3, 4, 2, 2, 4, 3, 3),
      Date = as.Date(c('2020-12-12', '2020-12-08', '2020-12-08', '2020-12-12',
                       '2020-12-12', '2020-12-12', '2020-11-01', '2020-12-12'))
    )
    
    # All devices (duplicates)
    dt[ , 
        .(Device = paste0(Device, collapse = ';'), 
          Level = max(Level), 
          Date = min(Date)), 
        by = .(Country, Customer)]
    #   Country Customer          Device Level       Date
    #1:       G        A XYZ;ABC;ZUI;XYZ     4 2020-12-08
    #2:       U        B         XYZ;ABC     2 2020-12-12
    #3:       J        C         XYZ;ZUI     4 2020-11-01
    
    # No duplicate devices - Note the use of unique()
    dt[ , 
        .(Device = paste0(unique(Device), collapse = ';'),
          Level = max(Level),
          Date = min(Date)),
        by = .(Country, Customer)]
    #   Country Customer      Device Level       Date
    #1:       G        A XYZ;ABC;ZUI     4 2020-12-08
    #2:       U        B     XYZ;ABC     2 2020-12-12
    #3:       J        C     XYZ;ZUI     4 2020-11-01
    

    【讨论】:

    • 我只是想选择一个例子,另一个应该以相同的方式分组。我会检查你的答案:)
    • 好的。另请注意,这可能会在设备中产生重复项。为了解决这个问题,我将对我的答案进行一些调整。
    • 乐于助人!根据我的经验,R几乎总是优于 Excel。
    • 我想根据我的真实数据调整你的代码,但是我收到一个错误,上面写着 Error in [.data.frame(df_short, , .(System.Type = paste0(unique(System.Type), : unsued Argument (by = .(Country, Customer)) 我的数据框看起来像这样:df_short &lt;- df %&gt;% select(Country, Customer, System.Type, NFC.Customer, Certification.Board.Level)%&gt;% 和我的代码:grouped_fd &lt;-df_short[,.(System.Type=paste0(unique(System.Type),collapse=';'),Certification.Board.Level=max(Certification.Board.Level)),by=.(Country, Customer)] 我用谷歌搜索但没有没有找到任何有关该消息的有用信息
    • @SRel 此语法适用于 data.tables,而不适用于 data.frames。你能先用其他结构给它吗?
    【解决方案2】:

    为了完整起见,并且因为 OP 似乎在 comment 中使用了 dplyr 动词,这里也是一个 dplyr 解决方案:

    library(dplyr)
    readr::read_table(
      "Country      Customer     Device     Level       DueDate
    Germany      Aldi         XYZ        3           12.12.20
    Germany      Aldi         ABC        3           08.12.20
    Germany      Aldi         ZUI        4           08.12.20
    USA          LIDL         XYZ        2           12.12.20
    USA          LIDL         ABC        2           12.12.20
    Jordan       Netto        XYZ        4           12.12.20
    Jordan       Netto        ZUI        3           01.11.20"
    ) %>% 
      mutate(DueDate = lubridate::dmy(DueDate)) %>% 
      group_by(Country, Customer) %>% 
      summarise(Device = Device %>% unique() %>% toString(),
                Level = max(Level),
                DueDate = min(DueDate))
    
    # A tibble: 3 x 5
    # Groups:   Country [3]
      Country Customer Device        Level DueDate   
      <chr>   <chr>    <chr>         <dbl> <date>    
    1 Germany Aldi     XYZ, ABC, ZUI     4 2020-12-08
    2 Jordan  Netto    XYZ, ZUI          4 2020-11-01
    3 USA     LIDL     XYZ, ABC          2 2020-12-12
    

    请注意,此处使用的是 OP 发布的原始数据集。为了找到最小日期,这需要将字符日期转换为日期类。此外,为简洁起见,使用toString() 代替paste0()

    【讨论】:

    • 关于日期转换的要点。我专注于获得一个更简单的答案,所以只是为我的解决方案预先创建了 Date 值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    • 1970-01-01
    • 2021-03-02
    • 2010-10-17
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    相关资源
    最近更新 更多