代码之家  ›  专栏  ›  技术社区  ›  Milad

重塑篮子数据框,用于分离篮子中的项目

  •  1
  • Milad  · 技术社区  · 6 年前

    我处理客户购物篮的数据集。以下是一个示例:

      basket item quant
    1      1    B     1
    2      1    A     2
    3      1    C     1
    4      2    A     1
    5      2    C     1
    6      3    A     2
    7      4    B     1
    8      4    C     1
    

    下面是复制它的代码:

    input <- data.frame(
        basket = c(1,1,1,2,2,3,4,4),
        item = c("B","A","C","A","C","A","B","C"),
        quant=c(1,2,1,1,1,2,1,1)
    )
    

    因此,在第一个篮子中有三个指定数量的项目。我有一个自定义函数,只适用于特定格式的输入;我们定义了最大篮子大小。假设是5。现在,该函数的输入应如下所示:

      basket item_1 item_2 item_3 item_4 item_5
    1      1      B      A      A      C    <NA>
    2      2      A      C   <NA>   <NA>    <NA>
    3      3      A      A   <NA>   <NA>    <NA>
    4      4      B      C   <NA>   <NA>    <NA>
    

    我一直在尝试使用 dplyr summarise 但是没有运气。 任何帮助都将不胜感激!

    2 回复  |  直到 6 年前
        1
  •  2
  •   Jaap    6 年前

    另一种可能的解决方案:

    library(dplyr)
    library(tidyr)
    
    input[rep(1:nrow(input), input$quant),] %>% 
      group_by(basket) %>% 
      mutate(item2 = paste0('item_', row_number())) %>% 
      complete(item2 = paste0('item_', 1:5)) %>% 
      select(-quant) %>% 
      spread(item2, item)
    

    其中给出:

    # A tibble: 4 x 6
      basket item_1 item_2 item_3 item_4 item_5
       <dbl> <fct>  <fct>  <fct>  <fct>  <fct> 
    1     1. B      A      A      C      NA    
    2     2. A      C      NA     NA     NA    
    3     3. A      A      NA     NA     NA    
    4     4. B      C      NA     NA     NA
    

    使用相同的逻辑,但 data.table -包装:

    library(data.table)
    setDT(input)
    
    input[input[, rep(.I, quant)]
          ][, .(basket, item, item2 = paste0('item_', rowid(basket)))
            ][CJ(basket = basket, item2 = paste0('item_', 1:5), unique = TRUE)
              , on = .(basket, item2)
              ][, dcast(.SD, basket ~ item2, value.var = 'item')]
    
        2
  •  2
  •   Sotos    6 年前

    这里有一个想法 tidyverse 。这里的技巧是根据 quant ,然后移除 数量 变量,这样就不会影响对宽数据帧的重塑。然后创建 new 变量,它将处理重复项,当然最后 spread 以获得所需的宽数据帧。

    library(tidyverse)
    
    df[rep(rownames(df), df$quant),] %>% 
     select(-quant) %>% 
     group_by(basket) %>% 
     mutate(new = paste0('item_', row_number())) %>% 
     spread(new, item)
    

    因此,

    # A tibble: 4 x 5
    # Groups:   basket [4]
      basket item_1 item_2 item_3 item_4
       <dbl> <fct>  <fct>  <fct>  <fct> 
    1     1. B      A      A      C     
    2     2. A      C      NA     NA    
    3     3. A      A      NA     NA    
    4     4. B      C      NA     NA