2012-11-08 12 views
23

Próbuję rozwiązać problem macierzy współwystępowania. Mam plik danych transakcji i przedmiotów i chcę zobaczyć matrycę liczby transakcji, w których elementy pojawiają się razem.Tworzenie macierzy współwystępowania

Jestem początkującym programistą w języku R i dobrze się bawię, znajdując wszystkie skróty, które R ma, zamiast tworzyć specjalne pętle (używałem C lat temu i trzymałem się jedynie makr Excela i SPSS). Sprawdziłem tutaj rozwiązania, ale nie znalazłem takiego, który działa (najbliższe jest to rozwiązanie podane tutaj: Co-occurrence matrix using SAC? - ale wygenerowało komunikat o błędzie, gdy użyłem projecting_tm, podejrzewałem, że proces cbind nie powiódł się w moim przypadku.

Zasadniczo mam tabelę zawierającą następujące elementy:

TrxID Items Quant 
Trx1 A 3 
Trx1 B 1 
Trx1 C 1 
Trx2 E 3 
Trx2 B 1 
Trx3 B 1 
Trx3 C 4 
Trx4 D 1 
Trx4 E 1 
Trx4 A 1 
Trx5 F 5 
Trx5 B 3 
Trx5 C 2 
Trx5 D 1, etc. 

chcę stworzyć coś takiego:

A B C D E F 
A 0 1 1 0 1 1 
B 1 0 3 1 1 0 
C 1 3 0 1 0 0 
D 1 1 1 0 1 1 
E 1 1 0 1 0 0 
F 0 1 1 1 0 0 

co zrobiłem było (i można by prawdopodobnie śmiać się z moim podejściem debiutanckim R):

library(igraph) 
library(tnet) 

trx <- read.table("FileName.txt", header=TRUE) 
transID <- t(trx[1]) 
items <- t(trx[2]) 

id_item <- cbind(items,transID) 
item_item <- projecting_tm(id_item, method="sum") 
item_item <- tnet_igraph(item_item,type="weighted one-mode tnet") 
item_matrix <-get.adjacency(item_item,attr="weight") 
item_matrix 

Jak wspomniano powyżej, proces cbind prawdopodobnie zakończył się niepowodzeniem, więc projecting_tm nie dał mi żadnego wyniku.

Jakieś alternatywne podejście lub korekta mojej metody?

Twoja pomoc byłaby bardzo cenna!

+0

Powiązany wątek [tutaj] (http://stackoverflow.com/questions/14332233/using-graph-adjacency-in-r). – hhh

+0

Mam do czynienia z podobnymi danymi dotyczącymi transakcji teraz i chciałem tylko podziękować @jacatra (i powiązany wątek wysłany przez hhh jest również bardzo pomocny) – EconomiCurtis

+0

jest mały błąd w przykładzie tego, co chcesz stworzyć - B wiersz i kolumna F mówi 0. powinno powiedzieć 1. Pomylić mnie przez jakiś czas. – vagabond

Odpowiedz

17

bym użyć kombinacji pakietu reshape2 i algebry macierzowej:

#read in your data 
dat <- read.table(text="TrxID Items Quant 
Trx1 A 3 
Trx1 B 1 
Trx1 C 1 
Trx2 E 3 
Trx2 B 1 
Trx3 B 1 
Trx3 C 4 
Trx4 D 1 
Trx4 E 1 
Trx4 A 1 
Trx5 F 5 
Trx5 B 3 
Trx5 C 2 
Trx5 D 1", header=T) 

#making the boolean matrix 
library(reshape2) 
dat2 <- melt(dat) 
w <- dcast(dat2, Items~TrxID) 
x <- as.matrix(w[,-1]) 
x[is.na(x)] <- 0 
x <- apply(x, 2, function(x) as.numeric(x > 0)) #recode as 0/1 
v <- x %*% t(x)         #the magic matrix 
diag(v) <- 0          #repalce diagonal 
dimnames(v) <- list(w[, 1], w[,1])    #name the dimensions 
v 

Dla wykresów może ...

g <- graph.adjacency(v, weighted=TRUE, mode ='undirected') 
g <- simplify(g) 
# set labels and degrees of vertices 
V(g)$label <- V(g)$name 
V(g)$degree <- degree(g) 
plot(g) 
3

To jest rzeczywiście bardzo proste i czyste Jeśli utworzysz najpierw wykres dwudzielny, w którym górne węzły są transakcjami, a dolne węzły są pozycjami. Następnie tworzysz rzut do dolnych węzłów.

dat <- read.table(text="TrxID Items Quant 
Trx1 A 3 
Trx1 B 1 
Trx1 C 1 
Trx2 E 3 
Trx2 B 1 
Trx3 B 1 
Trx3 C 4 
Trx4 D 1 
Trx4 E 1 
Trx4 A 1 
Trx5 F 5 
Trx5 B 3 
Trx5 C 2 
Trx5 D 1", header=T) 

library(igraph) 
bip <- graph.data.frame(dat) 
V(bip)$type <- V(bip)$name %in% dat[,1] 

## sparse=TRUE is a good idea if you have a large matrix here 
v <- get.adjacency(bipartite.projection(bip)[[2]], attr="weight", sparse=FALSE) 

## Need to reorder if you want it alphabetically 
v[order(rownames(v)), order(colnames(v))] 

# A B C D E F 
# A 0 1 1 1 1 0 
# B 1 0 3 1 1 1 
# C 1 3 0 1 0 1 
# D 1 1 1 0 1 1 
# E 1 1 0 1 0 0 
# F 0 1 1 1 0 0 
13

Używanie "dat" od jednej z odpowiedzi powyżej, spróbuj crossprod i table:

V <- crossprod(table(dat[1:2])) 
diag(V) <- 0 
V 
#  Items 
# Items A B C D E F 
#  A 0 1 1 1 1 0 
#  B 1 0 3 1 1 1 
#  C 1 3 0 1 0 1 
#  D 1 1 1 0 1 1 
#  E 1 1 0 1 0 0 
#  F 0 1 1 1 0 0 
11

W celu zapewnienia skuteczności, zwłaszcza na danych nielicznych, polecam użyciu rzadki matrycy.

dat <- read.table(text="TrxID Items Quant 
Trx1 A 3 
Trx1 B 1 
Trx1 C 1 
Trx2 E 3 
Trx2 B 1 
Trx3 B 1 
Trx3 C 4 
Trx4 D 1 
Trx4 E 1 
Trx4 A 1 
Trx5 F 5 
Trx5 B 3 
Trx5 C 2 
Trx5 D 1", header=T) 

library("Matrix") 

# factors for indexing matrix entries and naming dimensions 
trx.fac <- factor(dat[,1]) 
itm.fac <- factor(dat[,2]) 

s <- sparseMatrix(
     as.numeric(trx.fac), 
     as.numeric(itm.fac), 
     dimnames = list(
       as.character(levels(trx.fac)), 
       as.character(levels(itm.fac))), 
     x = 1) 

# calculating co-occurrences 
v <- t(s) %*% s 

# setting transactions counts of items to zero 
diag(v) <- 0 
v 

Próbowałem każdemu rozwiązaniu zamieszczonemu w tym wątku. Żadna z nich nie działała z dużymi matrycami (pracowałem z matrycą 1500 x 2 000 000).

Nieco poza tematem: po obliczeniu matrycy współwystępowania zwykle chcę obliczyć odległość między poszczególnymi pozycjami.Cosinus podobieństwa/odległość można obliczyć efektywnie na macierzy współwystępowania tak:

# cross-product of vectors (numerator) 
num <- v %*% v 

# square root of square sum of each vector (used for denominator) 
srss <- sqrt(apply(v^2, 1, sum)) 

# denominator 
den <- srss %*% t(srss) 

# cosine similarity 
v.cos.sim <- num/den 

# cosine distance 
v.cos.dist <- 1 - v.cos.sim 
6

użyłbym xtabs na to:

dat <- read.table(text="TrxID Items Quant 
Trx1 A 3 
Trx1 B 1 
Trx1 C 1 
Trx2 E 3 
Trx2 B 1 
Trx3 B 1 
Trx3 C 4 
Trx4 D 1 
Trx4 E 1 
Trx4 A 1 
Trx5 F 5 
Trx5 B 3 
Trx5 C 2 
Trx5 D 1", header=T) 


term_doc <- xtabs(~ TrxID + Items, data=dat, sparse = TRUE) 
co_occur <- crossprod(term_doc, term_doc) 
diag(co_occur) <- 0 
co_occur 

wrzuciłem w sparse = TRUE, aby pokazać, że można pracować dla bardzo dużych zestawów danych.

Powiązane problemy