重塑篮子数据框以分离篮子中的物品
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>
我一直在尝试使用 dplyr
和 summarise
来做到这一点,但没有成功。
如有任何帮助,我们将不胜感激!
这是来自 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')]
我处理客户购买篮子的数据集。这是一个示例:
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
来做到这一点,但没有成功。
如有任何帮助,我们将不胜感激!
这是来自 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')]