在这个一般领域有很多问题都有很好的解决方案,但我很难将它们应用到我的数据中。我有长格式数据,其中一列为我们提供观察结果,另一列为我们提供观察结果中的成员。我想做的就是计算每个成员与其他成员同时出现的次数。
\n假设我有以下数据集:
\ndf <- data.frame(salad = c(rep("Green", 4), rep("Caprese", 3), rep("Fruit", 3)),\n ingredients = c("Lettuce", "Tomato", "Onion", "Olives",\n "Tomato", "Onion", "Mozzarella",\n "Melon", "Orange", "Tomato"))\n\ndf\n\n salad ingredients\n1 Green Lettuce\n2 Green Tomato\n3 Green Onion\n4 Green Olives\n5 Caprese Tomato\n6 Caprese Onion\n7 Caprese Mozzarella\n8 Fruit Melon\n9 Fruit Orange\n10 Fruit Tomato\nRun Code Online (Sandbox Code Playgroud)\n我想要做的是生成一个包含所有可能的成员(成分)组合的表格,并计算它们在观察(沙拉)中同时出现的次数。它看起来像这样:
\nresults\n\n ingredient_A ingredient_B count\n1 Lettuce Tomato 1\n2 Lettuce Onion 1\n3 Lettuce Olives 1\n4 Lettuce Mozzarella 0\n5 Lettuce Melon 0\n6 Lettuce Orange 0\n7 Tomato Onion 2\n8 Tomato Olives 1\n9 Tomato Mozzarella 1\n10 Tomato Melon 1\n\xe2\x80\xa6 \xe2\x80\xa6 \xe2\x80\xa6 \xe2\x80\xa6\nRun Code Online (Sandbox Code Playgroud)\n我觉得答案非常简单,但我现在遇到了困难。任何帮助,将不胜感激。
\n这是 dplyr/tidyr 方法:
library(dplyr)
library(tidyr)
df %>%
left_join(., ., by = join_by(salad, ingredients < ingredients), suffix = c("_A", "_B")) %>%
filter(complete.cases(.)) %>%
count(ingredients_A, ingredients_B, name = "count")
# ingredients_A ingredients_B count
# 1 Lettuce Olives 1
# 2 Lettuce Onion 1
# 3 Lettuce Tomato 1
# 4 Melon Orange 1
# 5 Melon Tomato 1
# 6 Mozzarella Onion 1
# 7 Mozzarella Tomato 1
# 8 Olives Onion 1
# 9 Olives Tomato 1
# 10 Onion Tomato 2
# 11 Orange Tomato 1
Run Code Online (Sandbox Code Playgroud)
这left_join(., ., ...)是一个自连接,使用两个.只是为了意图和清晰。这ingredients < ingredients让我们确信我们没有自连接 ( ) 以及每个 中的配对 (和)Tomato, Tomato的双方。Tomato, LettuceLettuce, Tomatosalad
也许有点忙,基本的 R 变体可能是:
split(df, df$salad) |>
lapply(function(z) merge(z, z, by = "salad", suffix = c("_A", "_B")) |>
subset(ingredients_A < ingredients_B)) |>
do.call(what = rbind.data.frame) |>
xtabs(~ ingredients_A + ingredients_B, data = _) |>
as.data.frame.table(responseName = "count") |>
subset(count > 0)
# ingredients_A ingredients_B count
# 1 Lettuce Olives 1
# 7 Lettuce Onion 1
# 9 Mozzarella Onion 1
# 10 Olives Onion 1
# 14 Melon Orange 1
# 19 Lettuce Tomato 1
# 20 Melon Tomato 1
# 21 Mozzarella Tomato 1
# 22 Olives Tomato 1
# 23 Onion Tomato 2
# 24 Orange Tomato 1
Run Code Online (Sandbox Code Playgroud)
base-R 变体执行完整的笛卡尔连接(在每个沙拉中),这意味着如果实际数据中每个沙拉的成分数量相当大,这可能会变得昂贵。
更重要的是,因为任何行为都不需要只是两种方言;-)
library(data.table)
DT <- as.data.table(df)
DT <- as.data.table(df)
DT[, int := match(ingredients, sort(unique(ingredients)))
][DT, on = .(salad, int < int)
][!is.na(ingredients), .(count = .N), by = .(ingredients, i.ingredients)]
# ingredients i.ingredients count
# <char> <char> <int>
# 1: Lettuce Tomato 1
# 2: Onion Tomato 2
# 3: Olives Tomato 1
# 4: Lettuce Onion 1
# 5: Olives Onion 1
# 6: Lettuce Olives 1
# 7: Mozzarella Tomato 1
# 8: Mozzarella Onion 1
# 9: Melon Orange 1
# 10: Melon Tomato 1
# 11: Orange Tomato 1
Run Code Online (Sandbox Code Playgroud)
我补充说int,因为data.table支持不等式连接,但不支持字符串;因此,int < int类似于 dplyr 的ingredients < ingredients.
sort(.)我在计算中包含的唯一原因int是为了使输出更接近其他两种方言;虽然结果实际上是相同的,但Onion, Tomato也可能是Tomato, Onion。如果这很重要的话就交给你了。