2011-08-23 11 views
6

Załóżmy, że mam naprawdę dużą macierz rzadkich danych, ale interesuje mnie tylko oglądanie jej próbki, co czyni ją jeszcze bardziej rzadką. Przypuśćmy, że mam również ramkę danych z trójek, w tym kolumny dla wiersza/kolumny/wartości danych (importowane z pliku csv). Wiem, że mogę wykorzystać macierz rzadka() funkcji biblioteki (Matrix), aby utworzyć macierz rzadką korzystającDodawanie wartości do macierzy za pomocą wektorów indeksu, które zawierają nazwy wierszy i kolumn.

sparseMatrix(i=df$row,j=df$column,x=df$value) 

Jednakże, ze względu na moje wartości I skończyć z rozrzedzony matrycy, która jest miliony wierszy przez dziesiątki tysięcy kolumny (z których większość jest pusta, ponieważ mój podzbiór wyklucza większość wierszy i kolumn). Wszystkie te zerowe wiersze i kolumny kończą się przekrzywianiem niektórych z moich funkcji (na przykład klastrowaniem - kończę na jednym klastrze, który zawiera pochodzenie, gdy punkt początkowy nie jest nawet prawidłowym punktem). Chciałbym wykonać tę samą operację, ale używając i i j jako rownów i nazw kolorów. Próbowałem tworząc gęstą wektor, próbkowanie w dół do maksymalnej wielkości i dodawanie wartości używając

denseMatrix <- matrix(0,nrows,ncols,dimnames=c(df$row,df$column)) 
denseMatrix[as.character(df$row),as.character(df$column)]=df$value 

(faktycznie byłem ustawienie to równy 1, ponieważ nie jestem zainteresowany wartość w tym przypadku) ale znalazłem to wypełnia całą macierzy, ponieważ bierze krzyż wszystkich wierszy i kolumn, a nie tylko wiersz1 * col1, wiersz2 * col2 ... Czy ktoś zna sposób, aby osiągnąć to, co próbuję zrobić? Alternatywnie byłoby dobrze z wypełnieniem rzadkiej macierzy i po prostu po to, by w jakiś sposób odrzucić wszystkie zerowe wiersze i kolumny, aby zagęścić się w gęstszą formę (ale chciałbym zachować pewne odniesienie do oryginalnego wiersza i kolumny) Doceniam wszelkie sugestie!

Oto przykład:

> rows<-c(3,1,3,5) 
> cols<-c(2,4,6,6) 
> mtx<-sparseMatrix(i=rows,j=cols,x=1) 
> mtx 
5 x 6 sparse Matrix of class "dgCMatrix" 

[1,] . . . 1 . . 
[2,] . . . . . . 
[3,] . 1 . . . 1 
[4,] . . . . . . 
[5,] . . . . . 1 

Chciałbym pozbyć colums 1,3 i 5, a także wierszy 2 i 4. Jest to dość banalny przykład, ale wyobraźcie sobie, że zamiast liczby rzędów 1, 3 i 5 wynosiły 1000, 3000 i 5000. Wtedy między nimi byłoby o wiele więcej pustych rzędów. Oto co się dzieje, gdy za pomocą gęstej matrycy z wymienionych wierszy/kolumn

> dmtx<-matrix(0,3,3,dimnames=list(c(1,3,5),c(2,4,6))) 
> dmtx 
    2 4 6 
1 0 0 0 
3 0 0 0 
5 0 0 0 
> dmtx[as.character(rows),as.character(cols)]=1 
> dmtx 
    2 4 6 
1 1 1 1 
3 1 1 1 
5 1 1 1 
+0

Czy możesz pokazać mały przykład, powiedzmy 10x10, rzadką macierz, plus tryplety, których możesz użyć w tej sytuacji i jaki podzbiór chcesz? –

+1

Czy sprawdziłeś pakiet SparseM? – Spacedman

+0

Dodaję przykład powyżej – dscheffy

Odpowiedz

4

Kiedy mówisz „pozbyć się” niektórych kolumn/wierszy, masz na myśli właśnie to:

> mtx[-c(2,4), -c(1,3,5)] 
3 x 3 sparse Matrix of class "dgCMatrix" 

[1,] . 1 . 
[2,] 1 . 1 
[3,] . . 1 

prace podzbiorów, więc potrzebujesz sposobu na sprawdzenie, które wiersze i kolumny są puste? Jeśli jest to poprawne, możesz użyć colSums() i rowSums(), ponieważ zostały one ulepszone przez pakiet Matrix, aby uzyskać odpowiednie metody dla rzadkich macierzy. To powinno zachować rozproszenie podczas operacji

> dimnames(mtx) <- list(letters[1:5], LETTERS[1:6]) 
> mtx[which(rowSums(mtx) != 0), which(colSums(mtx) != 0)] 
3 x 3 sparse Matrix of class "dgCMatrix" 
    B D F 
a . 1 . 
c 1 . 1 
e . . 1 

lub, być może bezpieczniejszym

> mtx[rowSums(mtx) != 0, colSums(mtx) != 0] 
3 x 3 sparse Matrix of class "dgCMatrix" 
    B D F 
a . 1 . 
c 1 . 1 
e . . 1 
+0

rozwiązanie dominuje kopalni, mam usunięte kopalni ... –

4

Twój kod niemal działa, wystarczy cbind wraz nazwami wierszy i kolumn. Każdy wiersz wynikowej macierzy jest następnie traktowany jako para zamiast traktowania wierszy i kolumn oddzielnie.

> dmtx <- matrix(0,3,3,dimnames=list(c(1,3,5),c(2,4,6))) 
> dmtx[cbind(as.character(rows),as.character(cols))] <- 1 
> dmtx 
    2 4 6 
1 0 1 0 
3 1 0 1 
5 0 0 1 

Może być szybszy, jeśli użyjesz czynników.

> rowF <- factor(rows) 
> colF <- factor(cols) 
> dmtx <- matrix(0, nlevels(rowF), nlevels(colF), 
       dimnames=list(levels(rowF), levels(colF))) 
> dmtx[cbind(rowF,colF)] <- 1 
> dmtx 
    2 4 6 
1 0 1 0 
3 1 0 1 
5 0 0 1 

Można również użyć tych czynników w połączeniu z numerem sparseMatrix.

> sparseMatrix(i=as.integer(rowF), j=as.integer(colF), x=1, 
+    dimnames = list(levels(rowF), levels(colF))) 
3 x 3 sparse Matrix of class "dgCMatrix" 
    2 4 6 
1 . 1 . 
3 1 . 1 
5 . . 1 

Należy pamiętać, że jedno z pozostałych rozwiązań może być szybsze; przeliczanie na czynniki może być powolne, jeśli jest dużo danych.

+0

drát, nie powinien wygładzony tak długo, po prostu mnie pokonać! – joran

+0

Dzięki! Strony pomocy są świetne, gdy szukasz funkcji, która nie jest tak pomocna, gdy jest podstawowa składnia rdzenia ... Teraz już wiem, że dwa wektory pozwolą ci uzyskać submatrix - wskazywałem na submatrix, która jest pełna matryca. Dobrze wiedzieć, że powiązanie dwóch wektorów pozwoli mi wektoryzować operację. Wciąż wiem do R, ale szybko się uczę ... – dscheffy

1

Twój pierwszy problem wynika z faktu, że coordinate list (COO) ma nieciągłych wartości dla wierszy i kolumn indeksów. W obliczu tego, lub nawet w przypadku większości rzadkich macierzy, staram się zmienić kolejność wierszy i kolumn za ich wsparcie.

Można to zrobić na dwa sposoby:

  1. produkować rzadki matrycy i zrobić colSums i rowSums z logical(yourMatrix) aby uzyskać wartości wsparcia lub
  2. użyć funkcji jak table lub bigtabulate (od bigmemory pakiet), aby obliczyć liczbę unikalnych czasów, w których każda wartość wystąpiła na liście współrzędnych. (Moje preferencje to bigtabulate.)

Gdy masz wsparcie, można użyć funkcji rank (faktycznie, rank(-1 * support, ties = "first")) mapować oryginalne indeksów do nowych, opartych na ich szeregach.

W tym momencie, jeśli utworzysz matrycę z sparseMatrix, utworzy ona tylko macierz o wymiarach takich, że wszystkie twoje wiersze i kolumny mają wsparcie. Nie będzie mapował do niczego większego.

Jest to podejście podobne do podejścia @GavinSimpson, chociaż jego metoda powoduje jedynie pominięcie brakujących wierszy i kolumn, podczas gdy moje podejście zmienia kolejność, aby umieścić maksymalną gęstość w lewym górnym rogu matrycy, z malejącą gęstością podczas przechodzenia do większych indeksów dla wierszy i kolumn. W celu mapowania z powrotem do oryginalnych wskaźników w moim podejściu, wystarczy utworzyć parę odwzorowań: „oryginalne do rankingu” i „rankingu do oryginału”, a można doskonale odtworzyć oryginalne dane, jeśli zdecydujemy.

0

@ odpowiedź iterator jest bardzo pomocny dla mojej aplikacji, ale szkoda, że ​​jego/jej odpowiedź nie zawierała przykład ilustrujący ideę. Oto moja realizacja pomysłu na zmianę kolejności wierszy i kolumn macierzy rzadkiej bardzo ogromny (na przykład z około jednego miliona wierszy i kilka tysięcy kolumn na superkomputer o wystarczającej pamięci do załadowania rzadki macierzy).

library(Matrix) 

sparseY <- sparseMatrix(i=sample(2000, 500, replace=TRUE), j=sample(1000,500, replace=TRUE), x=sample(10000,500)) 

# visualize the original sparse matrix 
image(sparseY, aspect=1, colorkey=TRUE, main="The original sparse matrix") 

numObs <- length([email protected]) 
# replace all non-zero entries with 1 to calculate #non-zero entries per row/column and use rank() to sort based on supports 
logicalY <- sparseY; [email protected] <- rep(1, numObs) 

# calculate the number of observed entries per row/column 
colObsFreqs <- colSums(logicalY) 
rowObsFreqs <- rowSums(logicalY) 

colObsFreqs 
rowObsFreqs 

# get the rank of supports for rows and columns 
colRanks <- rank(-1*colObsFreqs, ties="first") 
rowRanks <- rank(-1*rowObsFreqs, ties="first") 

# Sort the ranks from small to large 
sortColInds <- sort(colRanks, index.return=TRUE) 
sortRowInds <- sort(rowRanks, index.return=TRUE) 

# reorder the original sparse matrix so that the maximum density data block is placed in the upper left corner of the matrix, with decreasing density as you move to larger indices for the rows and columns. 
sparseY <- sparseY[ sortRowInds$ix, sortColInds$ix ] 

# visualize the reordered sparse matrix 
image(sparseY, aspect=1, colorkey=TRUE, main="The sparse matrix after reordering") 

logicalY <- sparseY; [email protected] <- rep(1, numObs) 
# Check whether the resulting sparse matrix is what's expected, i.e. with the maximum density data block placed in the upper left corner of the matrix 
colObsFreqs <- colSums(logicalY) 
rowObsFreqs <- rowSums(logicalY) 

colObsFreqs 
rowObsFreqs 
Powiązane problemy