Добавление значений в матрицу с использованием индексных векторов, включающих имена строк и столбцов - PullRequest
6 голосов
/ 23 августа 2011

Предположим, у меня действительно большая матрица разреженных данных, но я заинтересован только в том, чтобы взглянуть на образец, делающий их еще более разреженными. Предположим, у меня также есть фрейм данных с тройками, включая столбцы для строки / столбца / значения данных (импортированные из файла CSV). Я знаю, что могу использовать функцию библиотеки (Matrix) sparseMatrix () для создания разреженной матрицы, используя

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

Однако из-за моих значений я получаю разреженную матрицу, которая состоит из миллионов строк на десятки тысяч столбцов (большинство из которых пустые, поскольку мое подмножество исключает большинство строк и столбцов). Все эти нулевые строки и столбцы в конечном итоге искажают некоторые из моих функций (например, кластеризацию - я получаю один кластер, который включает в себя источник, когда источник даже не является допустимой точкой). Я хотел бы выполнить ту же операцию, но используя i и j в качестве имен строк и имен столбцов. Я попытался создать плотный вектор, сэмплировать до максимального размера и добавить значения, используя

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

(на самом деле я установил его равным 1, потому что в данном случае меня не интересует значение), но я обнаружил, что оно заполняет всю матрицу, потому что оно принимает пересечение всех строк и столбцов а не просто row1 * col1, row2 * col2 ... Кто-нибудь знает способ достичь того, что я пытаюсь сделать? В качестве альтернативы мне было бы хорошо заполнить разреженную матрицу и просто заставить ее как-то отбросить все нулевые строки и столбцы, чтобы сжать себя в более плотную форму (но я бы хотел сохранить некоторую ссылку на исходные номера строк и столбцов ) Я ценю любые предложения!

Вот пример:

> 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

Я бы хотел избавиться от столбцов 1,3 и 5, а также от строк 2 и 4. Это довольно тривиальный пример, но представьте, что вместо строк с номерами 1, 3 и 5 они были 1000, 3000 и 5000. Тогда между ними будет намного больше пустых строк. Вот что происходит, когда я использую плотную матрицу с именованными строками / столбцами

> 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

Ответы [ 4 ]

4 голосов
/ 23 августа 2011

Ваш код почти работает, вам просто нужно cbind собрать вместе имена строк и столбцов. Каждая строка результирующей матрицы затем обрабатывается как пара вместо отдельной обработки строк и столбцов.

> 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

Это может быть быстрее, если вы используете факторы.

> 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

Вы также можете использовать эти факторы при вызове 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

Обратите внимание, что одно из других решений может быть быстрее; преобразование в коэффициенты может быть медленным, если данных много.

4 голосов
/ 23 августа 2011

Когда вы говорите «избавиться» от определенных столбцов / строк, вы имеете в виду именно это:

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

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

Подмножество работает, так что вам просто нужен способ выяснить, какие строки и столбцы пусты? Если это правильно, то вы можете использовать colSums() и rowSums(), поскольку они были улучшены пакетом Matrix , чтобы иметь соответствующие методы для разреженных матриц. Это должно сохранить разреженность во время операции

> 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

или, возможно, безопаснее

> 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
1 голос
/ 23 августа 2011

Ваша первая проблема связана с тем, что список координат (COO) имеет несмежные значения для индексов строк и столбцов.Столкнувшись с этим или даже имея дело с большинством разреженных матриц, я склонен переупорядочивать строки и столбцы по их поддержке.

Вы можете сделать это двумя способами:

  1. Производитьразреженная матрица и do colSums и rowSums из logical(yourMatrix), чтобы получить значения поддержки, или
  2. Используйте функцию типа table или bigtabulate (из набора bigmemory) длявычислите количество уникальных моментов, когда каждое значение встречалось в списке координат.(Я предпочитаю bigtabulate.)

Получив поддержку, вы можете использовать функцию rank (на самом деле rank(-1 * support, ties = "first")), чтобы сопоставить исходные индексы с новыми, основываясь наих ранги.

На этом этапе, если вы создадите матрицу с sparseMatrix, она создаст матрицу только с такими размерами, что все ваши строки и столбцы будут иметь поддержку.Он не будет отображаться ни с чем большим.

Это похоже на подход @ GavinSimpson, хотя его метод отбрасывает только недостающие строки и столбцы, в то время как мой подход меняет порядок размещения максимальной плотности в верхнем левом углу матрицы.с уменьшением плотности при переходе к большим индексам для строк и столбцов.Чтобы отобразить исходные индексы в моем подходе, просто создайте пару отображений: «от оригинала к ранжированию» и «ранжирование к оригиналу», и вы можете идеально воссоздать исходные данные, если захотите.

0 голосов
/ 02 февраля 2017

@ Ответ Итератора очень полезен для моего приложения, но жаль, что в его / ее ответе не было примера, иллюстрирующего эту идею. Вот моя реализация идеи переупорядочения строк и столбцов очень большой разреженной матрицы (например, с около миллиона строк и нескольких тысяч столбцов на суперкомпьютере с достаточным объемом памяти для загрузки разреженной матрицы).

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( sparseY@x )
# 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; logicalY@x <- 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; logicalY@x <- 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
...