2015-12-18 1 views
5

data.tableから正方形の隣接を構築しようとしています。matrixです。data.frameまたはdata.tableから正方形の隣接行列を構築します。

require(data.table) 
require(plyr) 
require(reshape2) 
# Build a mock data.table 
dt <- data.table(Source=as.character(rep(letters[1:3],2)),Target=as.character(rep(letters[4:2],2))) 
dt 
# Source Target 
#1:  a  d 
#2:  b  c 
#3:  c  b 
#4:  a  d 
#5:  b  c 
#6:  c  b 
sry <- ddply(dt, .(Source,Target), summarize, Frequency=length(Source)) 
sry 
# Source Target Frequency 
#1  a  d   2 
#2  b  c   2 
#3  c  b   2 
mtx <- as.matrix(dcast(sry, Source ~ Target, value.var="Frequency", fill=0)) 
rownames(mtx) <- mtx[,1] 
mtx <- mtx[,2:ncol(mtx)] 
mtx 
# b c d 
#a "0" "0" "2" 
#b "0" "2" "0" 
#c "2" "0" "0" 

は今、これは私が、私は同じように、両方の次元で表され、すべてのノードを持ちたいことを除いて、手に入れたいものに非常に近いです::ここに は、私がすでに持っているものの再現性の一例である

a b c d 
a 0 0 0 2 
b 0 0 2 0 
c 0 2 0 0 
d 0 0 0 0 

私は非常に大きなデータに取り組んでいることに注意してください。このために効率的なソリューションを探したいと思います。

ありがとうございました。


SOLUTIONS(EDIT):

提供するソリューションの品質と私のデータセットのサイズを考えると、私はすべてのソリューションをベンチマーク。このデータを考慮

#The bench was made with a 1-million-row sample from my original dataset 
library(data.table) 
aa <- fread("small2.csv",sep="^") 
dt <- aa[,c(8,9),with=F] 
colnames(dt) <- c("Source","Target") 
dim(dt) 
#[1] 1000001  2 
levs <- unique(unlist(dt, use.names=F)) 
length(levs) 
#[1] 2222 

、所望の出力2222 * 2222行列(最初の列は明らかにも許容される行名を含む* 2223 2222の溶液)です。

# Ananda Mahto's first solution 
am1 <- function() { 
    table(dt[, lapply(.SD, factor, levs)]) 
} 
dim(am1()) 
#[1] 2222 2222 

# Ananda Mahto's second solution 
am2 <- function() { 
    as.matrix(dcast(dt[, lapply(.SD, factor, levs)], Source~Target, drop=F, value.var="Target", fun.aggregate=length)) 
} 
dim(am2()) 
#[1] 2222 2223 

library(dplyr) 
library(tidyr) 
# Akrun's solution 
akr <- function() { 
    dt %>% 
     mutate_each(funs(factor(., levs))) %>% 
     group_by(Source, Target) %>% 
     tally() %>% 
     spread(Target, n, drop=FALSE, fill=0) 
} 
dim(akr()) 
#[1] 2222 2223 

library(igraph) 
# Carlos Cinelli's solution 
cc <- function() { 
    g <- graph_from_data_frame(dt) 
    as_adjacency_matrix(g) 
} 
dim(cc()) 
#[1] 2222 2222 

ベンチマークの結果は...

library(rbenchmark) 
benchmark(am1(), am2(), akr(), cc(), replications=75) 
# test replications elapsed relative user.self sys.self user.child sys.child 
# 1 am1()   75 15.939 1.000 15.636 0.280   0   0 
# 2 am2()   75 111.558 6.999 109.345 1.616   0   0 
# 3 akr()   75 43.786 2.747 42.463 1.134   0   0 
# 4 cc()   75 46.193 2.898 45.532 0.563   0   0 
+0

、この他の質問はhttp://stackoverflow.com/q同じ/関連です:あなたが大規模なデータを扱っていることを、igraphはそれがスパース行列を使用するという利点を有しているので/ 9617348/1191259 – Frank

+1

質問は関連していますが、間違いなく同じです。私はすでにそのような結果を得てそれを実証しました。その質問の例のデータでは、私の主旨は、次元が 'c(" a "、" b "、" c "、" x "、" y ")の5x5行列を得ることでした。 – Vongo

答えて

6

であるあなただけtableを探している、しかし、あなたは、両方の列が同じ因子レベルを持っていることを確認する必要がありますようですね:

levs <- unique(unlist(dt, use.names = FALSE)) 
table(lapply(dt, factor, levs)) 
#  Target 
# Source a b c d 
#  a 0 0 0 2 
#  b 0 0 2 0 
#  c 0 2 0 0 
#  d 0 0 0 0 

スピードを改善するかどうかは分かりませんが、"data.table" から:

dcast(lapply(dt, factor, levs), Source ~ Target, drop = FALSE, 
     value.var = "Target", fun.aggregate = length) 
+0

素晴らしい。パフォーマンスのパートを調べ、ソリューションの仕組みを理解しようと思います。 ありがとうございました! – Vongo

1

私たちは、あなたがまたigraphを使用することができますdplyr/tidyr

library(dplyr) 
library(tidyr) 
dt %>% 
    mutate_each(funs(factor(., letters[1:4]))) %>% 
    group_by(Source, Target) %>% 
    tally() %>% 
    spread(Target, n, drop=FALSE, fill=0) 
# Source  a  b  c  d 
# (fctr) (dbl) (dbl) (dbl) (dbl) 
#1  a  0  0  0  2 
#2  b  0  0  2  0 
#3  c  0  2  0  0 
#4  d  0  0  0  0 
3

を使用することができます。 sry` `から始まっ

library(igraph) 
g <- graph_from_data_frame(dt) 
as_adjacency_matrix(g) 
4 x 4 sparse Matrix of class "dgCMatrix" 
    a b c d 
a . . . 2 
b . . 2 . 
c . 2 . . 
d . . . . 
関連する問題