我有一个包含2列的数据框:
Name AvgSalary
Alice 10000
Bob 10000
Charlie 10000
Doug 10000
现在我可以计算id1和id2的组合等于组合id2和id1的所有情况并返回它们,如下所示:
id1 <- c(123,456,789,122,345,678,901,126,567,890,001,002,130,122)
id2 <- c(121,122,123,456,125,126,127,678,129,130,131,132,890,987)
df <- cbind(id1,id2)
df
id1 id2
[1,] 123 121
[2,] 456 122
[3,] 789 123
[4,] 122 456
[5,] 345 125
[6,] 678 126
[7,] 901 127
[8,] 126 678
[9,] 567 129
[10,] 890 130
[11,] 1 131
[12,] 2 132
[13,] 130 890
[14,] 122 987
但是现在,我想要一个新的计数,其中id1只与id2相关,而id2只与id1相关,例如对于df,count将等于4,因为:
forwards<-paste(V1,V2)
backwards<-paste(V2,V1)
#identifying combinations
intersect(forwards, backwards)
[1] "456 122" "122 456" "678 126" "126 678" "890 130" "130 890"
#count combinations
length(intersect(forwards, backwards))
[1] 6
因此,新计数应排除这两种情况并计算如下情况:
id1==122 is related with id2==456 AND id1==456 is related with id2==122,
but id1 ==122 is too related with id2==987,
我该怎么做?
答案 0 :(得分:2)
以下是我使用data.table
解决您问题的方法。也许有人可以帮助我们找到更直接的解决方案。
library(data.table)
df <- data.table(id1,id2) # get vectors as a data.table
# create forwards and backwards columns
df[ , forwards := paste(id1,id2)]
df[ , backwards := paste(id2,id1)]
# count number of intersections between forwards and backwards
df [ forwards %in% backwards, .(count=.N)]
> count
> 1: 6
现在这就是你所要求的,棘手的部分。
# add new column with number of pairs of id1
df[ , pairs :=.N, by= id1]
# get all values that have more than one pair
too_many_pairs <- as.matrix(df[ pairs >1, .(id1,id2) ])
# solution
df[ id1 %in% id2 & id2 %in% id1 & !(id1 %in% too_many_pairs) ]
> id1 id2
> 1: 678 126
> 2: 126 678
> 3: 890 130
> 4: 130 890
解释解决方案:
解决方案id1 %in% id2 & id2 %in% id1
的第一部分表示只保留id2的值,这些值也可以在id2中找到,反之亦然
解决方案!(id1 %in% too_many_pairs)
的第二部分表示删除具有多个对的id1的所有值
答案 1 :(得分:0)
这是一个Hadleyverse方法:
library(dplyr)
library(tidyr)
# make df a data.frame instead of a matrix
data.frame(df) %>%
# add row index
add_rownames() %>%
# melt to long form
gather(id, val, -rowname) %>%
# filter down to values repeated an even number of times
group_by(val) %>% filter(n() %% 2 == 0) %>%
# filter down to rows with two values
group_by(rowname) %>% filter(n() == 2) %>%
# spread back to wide form
spread(id, val)
# Source: local data frame [4 x 3]
# Groups: rowname [4]
#
# rowname id1 id2
# (chr) (dbl) (dbl)
# 1 10 890 130
# 2 13 130 890
# 3 6 678 126
# 4 8 126 678