重塑篮子数据框以分离篮子中的物品

Reshaping basket data frame for separating items in a basket

我处理客户购买篮子的数据集。这是一个示例:

  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>

我一直在尝试使用 dplyrsummarise 来做到这一点,但没有成功。 如有任何帮助,我们将不胜感激!

这是来自 tidyverse 的想法。这里的技巧是根据 quant 复制您的行,然后删除 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 

另一种可能的解决方案:

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-package:

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')]