2015-12-18 17 views
5

Sto provando a costruire una adiacenza quadrata matrix da un data.table. Ecco un esempio riproducibile di quello che ho già:Creare una matrice di adiacenza quadrata da data.frame o 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" 

Ora, questo è molto vicino a quello che voglio ottenere, se non che mi piacerebbe avere tutti i nodi rappresentati in entrambe le dimensioni, come:

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

Nota che sto lavorando su dati abbastanza grandi, quindi mi piacerebbe trovare una soluzione efficiente per questo.

Grazie per il vostro aiuto.


SOLUZIONI (EDIT):

Data la qualità delle soluzioni offerte e le dimensioni del mio set di dati, ho benchmark tutte le soluzioni.

#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 

Dato questi dati, l'uscita desiderata è una matrice 2222 * 2222 (2222 * 2223 soluzioni in cui la prima colonna contiene la riga nomi sono ovviamente accettabile).

# 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 

E il risultato del benchmark è ...

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

partire da 'sry', quest'altra domanda è legata/lo stesso http://stackoverflow.com/q/9617348/1191259 – Frank

+1

La domanda è correlata ma sicuramente non è la stessa. Ho già avuto un risultato simile e l'ho dimostrato. Con i dati dell'esempio di quella domanda, il mio punto sarebbe stato quello di ottenere una matrice 5x5 con le dimensioni 'c (" a "," b "," c "," x "," y ")'. – Vongo

risposta

6

Sembra che tu stai solo cercando table, ma si dovrebbe fare in modo che entrambe le colonne hanno gli stessi livelli di fattore:


Non so se offrirebbe miglioramenti di velocità, ma potresti anche usare.210.796.162,31321 milioni da "data.table":

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

Incredibile. Analizzerò la parte relativa alle prestazioni e cercherò di capire come funzionano le tue soluzioni. Grazie! – Vongo

1

Possiamo usare 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

È inoltre possibile utilizzare igraph. Dal momento che lei ha detto che si tratta di dati di grandi dimensioni, igraph ha il vantaggio che utilizza matrici sparse:

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 . . . . 
Problemi correlati