计算值 A 在没有值 B 的情况下出现的次数,反之亦然
Count the amount of times value A occurs without value B and vice versa
我无法弄清楚如何做与这个问题的答案相反的事情(在 R 中不是 python)。
基本上我有一个包含很多列对组合的数据框,如下所示:
df <- data.frame(id1 = c("1","1","1","1","2","2","2","3","3","4","4"),
id2 = c("2","2","3","4","1","3","4","1","4","2","1"))
我想计算一下,A 列中的所有值在整个数据框中出现的频率,而没有 B 列中的值。因此,这个小示例的结果将是以下输出:
df_result <- data.frame(id1 = c("1","1","1","2","2","2","3","3","4","4"),
id2 = c("2","3","4","1","3","4","1","4","2","1"),
count = c("4","5","5","3","5","4","2","3","3","3"))
这方面的重要标准是,最终结果数据帧按对折叠(因此在我的示例中,第 1 行和第 2 行是重复的,并且它们被折叠并按总频率求和,观察到 1 而没有观察到 2) .为了计算出现次数,检查两列很重要。 IE。列的顺序对于计算频率无关紧要 - 如果 A 列有 1,B 有 2,这与 A 列有 2,B 有 1 的计数相同。
我可以通过对每一对进行过滤来非常缓慢地执行此操作,但对于我有很多不同对的真实数据来说,这并不真正可行。
非常感谢任何指导。
首先paste
将两个id列拼起来id12
,以便后面匹配。然后使用 sapply
遍历所有行以查看 id1
出现在 id12
而 id2
没有出现的记录。 sum
那个值,只输出 distinct
条记录。最后,删除 id12
列。
library(dplyr)
df %>% mutate(id12 = paste0(id1, id2),
count = sapply(1:nrow(.),
function(x)
sum(grepl(id1[x], id12) & !grepl(id2[x], id12)))) %>%
distinct() %>%
select(-id12)
或完全以 R 为基础:
id12 <- paste0(df$id1, df$id2)
df$count <- sapply(1:nrow(df), function(x) sum(grepl(df$id1[x], id12) & !grepl(df$id2[x], id12)))
df <- df[!duplicated(df),]
输出
id1 id2 count
1 1 2 4
2 1 3 5
3 1 4 5
4 2 1 3
5 2 3 5
6 2 4 4
7 3 1 2
8 3 4 3
9 4 2 3
10 4 1 3
完整 tidyverse
版本:
library(tidyverse)
df %>%
mutate(id = paste(id1, id2),
count = map(cur_group_rows(), ~ sum(str_detect(id, id1[.x]) & str_detect(id, id2[.x], negate = T))))
一种更有效的方法是使用表格格式:
tab = crossprod(table(rep(seq_len(nrow(df)), ncol(df)), c(df$id1, df$id2)))
#tab
#
# 1 2 3 4
# 1 7 3 2 2
# 2 3 6 1 2
# 3 2 1 4 1
# 4 2 2 1 5
所以,现在,我们有了每个值与另一个值一起出现的时间(不管它们在两列中的顺序如何)。在这里,我们需要一种方法将上述 table 按每对进行子集化,并从每个 id 的总外观值中减去它们的共现值。
制作所有组合的网格:
gr = expand.grid(id1 = colnames(tab), id2 = rownames(tab), stringsAsFactors = FALSE)
创建 2 列矩阵以对 table:
进行子集化
id1.ij = cbind(match(gr$id1, colnames(tab)),
match(gr$id1, rownames(tab)))
id2.ij = cbind(match(gr$id1, colnames(tab)),
match(gr$id2, rownames(tab)))
减去各自的值:
cbind(gr, count = tab[id1.ij] - tab[id2.ij])
# id1 id2 count
#1 1 1 0
#2 2 1 3
#3 3 1 2
#4 4 1 3
#5 1 2 4
#6 2 2 0
#7 3 2 3
#8 4 2 3
#9 1 3 5
#10 2 3 5
#11 3 3 0
#12 4 3 4
#13 1 4 5
#14 2 4 4
#15 3 4 3
#16 4 4 0
当然,如果我们不需要完整的网格值,我们可以设置:
gr = unique(df)
这导致:
# id1 id2 count
#1 1 2 4
#3 1 3 5
#4 1 4 5
#5 2 1 3
#6 2 3 5
#7 2 4 4
#8 3 1 2
#9 3 4 3
#10 4 2 3
#11 4 1 3
我无法弄清楚如何做与这个问题的答案相反的事情(在 R 中不是 python)。
基本上我有一个包含很多列对组合的数据框,如下所示:
df <- data.frame(id1 = c("1","1","1","1","2","2","2","3","3","4","4"),
id2 = c("2","2","3","4","1","3","4","1","4","2","1"))
我想计算一下,A 列中的所有值在整个数据框中出现的频率,而没有 B 列中的值。因此,这个小示例的结果将是以下输出:
df_result <- data.frame(id1 = c("1","1","1","2","2","2","3","3","4","4"),
id2 = c("2","3","4","1","3","4","1","4","2","1"),
count = c("4","5","5","3","5","4","2","3","3","3"))
这方面的重要标准是,最终结果数据帧按对折叠(因此在我的示例中,第 1 行和第 2 行是重复的,并且它们被折叠并按总频率求和,观察到 1 而没有观察到 2) .为了计算出现次数,检查两列很重要。 IE。列的顺序对于计算频率无关紧要 - 如果 A 列有 1,B 有 2,这与 A 列有 2,B 有 1 的计数相同。
我可以通过对每一对进行过滤来非常缓慢地执行此操作,但对于我有很多不同对的真实数据来说,这并不真正可行。
非常感谢任何指导。
首先paste
将两个id列拼起来id12
,以便后面匹配。然后使用 sapply
遍历所有行以查看 id1
出现在 id12
而 id2
没有出现的记录。 sum
那个值,只输出 distinct
条记录。最后,删除 id12
列。
library(dplyr)
df %>% mutate(id12 = paste0(id1, id2),
count = sapply(1:nrow(.),
function(x)
sum(grepl(id1[x], id12) & !grepl(id2[x], id12)))) %>%
distinct() %>%
select(-id12)
或完全以 R 为基础:
id12 <- paste0(df$id1, df$id2)
df$count <- sapply(1:nrow(df), function(x) sum(grepl(df$id1[x], id12) & !grepl(df$id2[x], id12)))
df <- df[!duplicated(df),]
输出
id1 id2 count
1 1 2 4
2 1 3 5
3 1 4 5
4 2 1 3
5 2 3 5
6 2 4 4
7 3 1 2
8 3 4 3
9 4 2 3
10 4 1 3
完整 tidyverse
版本:
library(tidyverse)
df %>%
mutate(id = paste(id1, id2),
count = map(cur_group_rows(), ~ sum(str_detect(id, id1[.x]) & str_detect(id, id2[.x], negate = T))))
一种更有效的方法是使用表格格式:
tab = crossprod(table(rep(seq_len(nrow(df)), ncol(df)), c(df$id1, df$id2)))
#tab
#
# 1 2 3 4
# 1 7 3 2 2
# 2 3 6 1 2
# 3 2 1 4 1
# 4 2 2 1 5
所以,现在,我们有了每个值与另一个值一起出现的时间(不管它们在两列中的顺序如何)。在这里,我们需要一种方法将上述 table 按每对进行子集化,并从每个 id 的总外观值中减去它们的共现值。
制作所有组合的网格:
gr = expand.grid(id1 = colnames(tab), id2 = rownames(tab), stringsAsFactors = FALSE)
创建 2 列矩阵以对 table:
进行子集化id1.ij = cbind(match(gr$id1, colnames(tab)),
match(gr$id1, rownames(tab)))
id2.ij = cbind(match(gr$id1, colnames(tab)),
match(gr$id2, rownames(tab)))
减去各自的值:
cbind(gr, count = tab[id1.ij] - tab[id2.ij])
# id1 id2 count
#1 1 1 0
#2 2 1 3
#3 3 1 2
#4 4 1 3
#5 1 2 4
#6 2 2 0
#7 3 2 3
#8 4 2 3
#9 1 3 5
#10 2 3 5
#11 3 3 0
#12 4 3 4
#13 1 4 5
#14 2 4 4
#15 3 4 3
#16 4 4 0
当然,如果我们不需要完整的网格值,我们可以设置:
gr = unique(df)
这导致:
# id1 id2 count
#1 1 2 4
#3 1 3 5
#4 1 4 5
#5 2 1 3
#6 2 3 5
#7 2 4 4
#8 3 1 2
#9 3 4 3
#10 4 2 3
#11 4 1 3