2017-11-29 2 views
4

내가큰 데이터

df <- data.frame(group= c("a","a","b","b","b","c"), 
      person = c("Tom","Jerry","Tom","Anna","Sam","Nic"), stringsAsFactors = FALSE) 

df 
    group person 
1  a Tom 
2  a Jerry 
3  b Tom 
4  b Anna 
5  b Sam 
6  c Nic 

같은 큰 dataframe이 결과적으로 좀하고 싶습니다 설정에 공통 셋째 찾기

df.output 
    pers1 pers2 person_in_common 
1 Anna Jerry    Tom 
2 Jerry Sam    Tom 
3 Sam Tom    Anna 
4 Anna Tom    Sam 
6 Anna Sam    Tom 

결과 dataframe은 기본적으로 사람의 모든 쌍있는 테이블을 제공합니다 누가 공통점이있는 사람인지. SQL에서 할 수있는 방법을 찾았지만 오랜 시간이 걸리므로 효율적인 방법이 있는지 궁금합니다.

답변

2

여기에 igraph 패키지를 사용하는 것이 있습니다. 기본 아이디어는 그래프를 생성 한 다음 각 노드에 대해 인접한 두 노드를 추출하는 것입니다.

library(igraph) 
X1 = split(df$person, df$group) 
X2 = X1[lengths(X1) >= 2] 
dat = data.frame(do.call(rbind, unlist(lapply(X2, function(x) 
      combn(x, 2, sort, FALSE)), recursive = FALSE))) 
g = graph.data.frame(dat, directed = FALSE) 
mydf = data.frame(as.matrix(get.adjacency(g))) 
mydf = mydf[colSums(mydf) > 1] 
ANS = sapply(mydf, function(x) t(combn(row.names(mydf)[which(x == 1)], 2))) 
do.call(rbind, lapply(names(ANS), function(nm) data.frame(ANS[[nm]], nm))) 
#  X1 X2 nm 
#1 Sam Tom Anna 
#2 Anna Tom Sam 
#3 Jerry Anna Tom 
#4 Jerry Sam Tom 
#5 Anna Sam Tom 

또는

mynames = unique(do.call(c, X2)) 
do.call(rbind, 
     lapply(mynames, function(x){ 
      L = V(g)$name[unlist(adjacent_vertices(graph = g, v = x))] 
      if(length(L) >= 2){ 
       setNames(data.frame(t(combn(L, 2)), x), c("P1", "P2", "P3")) 
      }else{ 
       setNames(data.frame(NA, NA, x), c("P1", "P2", "P3")) 
      } 
     })) 
#  P1 P2 P3 
#1 Jerry Anna Tom 
#2 Jerry Sam Tom 
#3 Anna Sam Tom 
#4 <NA> <NA> Jerry 
#5 Sam Tom Anna 
#6 Anna Tom Sam 
+0

그것은 설정 정상적인 크기의 데이터에 대해 잘 작동하지만'mydf' 인접 행렬을 설정하려고 할 때 내 실제 데이터와 메모리 문제로 실행이 ('g' 거의이다 1gb 크기). – user6617454

+1

나는 그것을 시도했지만 매트릭스가 너무 큽니다. 스파 스 매트릭스로 주변을 조롱하고 있었지만 알아 내지 못했습니다. 좀 더 시도해보고 일반적인 문제를 해결할 때 대답을 받아 들일 것입니다. – user6617454

+0

두 번째 버전 @ d.b에서 충돌이 발생하지 않지만 계속 실행 중입니다. 나는 그것이 어떻게되는지 알려줄 것이다 – user6617454