我有不同类别(食品和食品)不同地点(城市)销售的产品(苹果,梨,香蕉)数据框。
我想知道任何一对产品在任何类别中出现的次数。
这是我正在努力实现此目的的示例数据集:
category <- c('food','food','food','food','food','food','edibles','edibles','edibles','edibles', 'edibles')
location <- c('houston, TX', 'houston, TX', 'las vegas, NV', 'las vegas, NV', 'philadelphia, PA', 'philadelphia, PA', 'austin, TX', 'austin, TX', 'charlotte, NC', 'charlotte, NC', 'charlotte, NC')
item <- c('apple', 'banana', 'apple', 'pear', 'apple', 'pear', 'pear', 'apple', 'apple', 'pear', 'banana')
food_data <- data.frame(cbind(category, location, item), stringsAsFactors = FALSE)
例如,“apple&amp; banana”一起出现在“las vegas,NV”的“食物”类别中,但也出现在“charlotte,NC”的“食物”类别中。因此,“apple&amp; banana”对的计数为2。
我想要的输出是这样的对数:
(无序)计数 apple&amp;香蕉
2
(无序)计数 apple&amp;梨
4
任何人都知道如何实现这一目标?相对较新的R并且已经混淆了一段时间。
我正在尝试使用它来计算不同项目之间的亲和力。
关于产出的补充说明: 我的完整数据集包含数百个不同的项目。想得到一个数据框,其中第一列是该对,第二列是每对的计数。
答案 0 :(得分:7)
以下是使用tidyverse
和crossprod
的一种方法;通过使用spread
,它将所有 item / fruit 从同一类别 - 位置组合转换为一行,其中项作为标题(这要求您没有重复每个类别 - 国家/地区项,否则您需要预先汇总步骤),表示存在的值; crossprod
基本上评估了项列对的内积,并给出了共生次数。
library(tidyverse)
food_data %>%
mutate(n = 1) %>%
spread(item, n, fill=0) %>%
select(-category, -location) %>%
{crossprod(as.matrix(.))} %>%
`diag<-`(0)
# apple banana pear
#apple 0 2 4
#banana 2 0 1
#pear 4 1 0
要将其转换为数据框:
food_data %>%
mutate(n = 1) %>%
spread(item, n, fill=0) %>%
select(-category, -location) %>%
{crossprod(as.matrix(.))} %>%
replace(lower.tri(., diag=T), NA) %>%
reshape2::melt(na.rm=T) %>%
unite('Pair', c('Var1', 'Var2'), sep=", ")
# Pair value
#4 apple, banana 2
#7 apple, pear 4
#8 banana, pear 1
答案 1 :(得分:2)
来自tidyverse
的解决方案。我们的想法是创建food_data2
,这是food_data
的宽格式。之后,在每个唯一项目之间创建组合,并使用map2_int
循环浏览每个项目组合以计算数字。此解决方案适用于任何数量的项目。
library(tidyverse)
food_data2 <- food_data %>%
mutate(count = 1) %>%
spread(item, count, fill = 0)
food_combination <- food_data %>%
pull(item) %>%
unique() %>%
combn(2) %>%
t() %>%
as_data_frame() %>%
mutate(count = map2_int(V1, V2,
~sum(apply(food_data2 %>% select(.x, .y), 1, sum) == 2)))
# View the result
food_combination
# A tibble: 3 x 3
V1 V2 count
<chr> <chr> <int>
1 apple banana 2
2 apple pear 4
3 banana pear 1
如果您只想让一列显示最后的项目组合,则可以进一步使用unite
功能。
food_combination2 <- food_combination %>%
unite(Pair, V1, V2)
# View the result
food_combination2
# A tibble: 3 x 2
Pair count
* <chr> <int>
1 apple_banana 2
2 apple_pear 4
3 banana_pear 1
答案 2 :(得分:1)
这是一个可以满足您需求的小功能。它可以推广到dplyr::
评估系统described here的任意分组列。可能更好的方法,但这有效:p
评论/解释是内联的~~
library("dplyr")
# a function to apply to `food_data` from the original post
count_combos <- function(df, group_col1, group_col2, count_col){
# use `combn()` to get all the unique pairs from the `$items` col
combos <- t(combn(sort(unique(df[[count_col]])), 2)) %>%
as_data_frame() %>%
# initialize an empty column to catch the counts
mutate(count=NA)
# create a new df from the colnames passed as args,
# (it would be more general to just use the dplyr evaluation system (@_@))
df <- data_frame(
group_col1 = df[[group_col1]],
group_col2 = df[[group_col2]],
count_col = df[[count_col]]
)
# for each combo of the grouping vars, get a pipe-seperated string of items
df <- df %>%
group_by(group_col1, group_col2) %>% summarize(
items = paste(unique(count_col), collapse="|")
) %>% ungroup()
# for each item pair/combo, get the number of rows of `df` with both items
combos$count <- sapply(1:nrow(combos), function(x){
sum(grepl(combos$V1[x], df$items) & grepl(combos$V2[x], df$items))
})
# and return it in a nice df
return(combos)
}
# apply the function
count_combos(food_data,
group_col1="category", group_col2="location", count_col="item")