Значения индекса из матрицы с использованием строки, столбца - PullRequest
23 голосов
/ 03 августа 2011

Это, вероятно, просто решить.У меня есть 2D-матрица mat с 500 строками × 335 столбцов и data.frame dat с 120425 строками.Data.frame dat имеет два столбца I и J, которые являются целыми числами для индексации строки, столбец из mat.Я хотел бы добавить значения из mat в строки dat.

Вот мой концептуальный сбой:

> dat$matval <- mat[dat$I, dat$J]
Error: cannot allocate vector of length 1617278737

(я использую R 2.13.1 на Win32).Углубившись немного глубже, я вижу, что неправильно использую матричную индексацию, поскольку кажется, что я получаю только субматрицу mat, а не одномерный массив значений, как я ожидал, то есть:

> str(mat[dat$I[1:100], dat$J[1:100]])
 int [1:100, 1:100] 20 1 1 1 20 1 1 1 1 1 ...

Я ожидал что-то вроде int [1:100] 20 1 1 1 20 1 1 1 1 1 ....Как правильно индексировать 2D матрицу, используя индексы строки, столбца для получения значений?

Ответы [ 4 ]

39 голосов
/ 03 августа 2011

Почти.Требуется предложить "[" в виде матрицы из двух столбцов:

dat$matval <- mat[ cbind(dat$I, dat$J) ] # should do it.

Существует предостережение: хотя это также работает для информационных кадров, они сначала приводятся к классу матрицы и, если они есть, не числовыевся матрица становится классом "наименьшего знаменателя".

10 голосов
/ 03 августа 2011

Использование матрицы для индексации, как предлагает DWin, конечно, намного чище, но по какой-то странной причине делать это вручную с использованием 1-D индексов на самом деле немного быстрее:

# Huge sample data
mat <- matrix(sin(1:1e7), ncol=1000)
dat <- data.frame(I=sample.int(nrow(mat), 1e7, rep=T), 
                  J=sample.int(ncol(mat), 1e7, rep=T))

system.time( x <- mat[cbind(dat$I, dat$J)] )     # 0.51 seconds
system.time( mat[dat$I + (dat$J-1L)*nrow(mat)] ) # 0.44 seconds

Часть dat$I + (dat$J-1L)*nrow(m) превращает двумерные индексы в одномерные. 1L - это способ указать целое число вместо двойного значения. Это позволяет избежать некоторых принуждений.

... Я также попробовал решение на основе применения gsk3. Это почти в 500 раз медленнее:

system.time( apply( dat, 1, function(x,mat) mat[ x[1], x[2] ], mat=mat ) ) # 212
1 голос
/ 03 августа 2011

Вот одна строка, использующая apply операции на основе строк

> dat <- as.data.frame(matrix(rep(seq(4),4),ncol=2))
> colnames(dat) <- c('I','J')
> dat
   I  J
1  1  1
2  2  2
3  3  3
4  4  4
5  1  1
6  2  2
7  3  3
8  4  4
> mat <- matrix(seq(16),ncol=4)
> mat
     [,1] [,2] [,3] [,4]
[1,]    1    5    9   13
[2,]    2    6   10   14
[3,]    3    7   11   15
[4,]    4    8   12   16

> dat$K <- apply( dat, 1, function(x,mat) mat[ x[1], x[2] ], mat=mat )
> dat
  I J  K
1 1 1  1
2 2 2  6
3 3 3 11
4 4 4 16
5 1 1  1
6 2 2  6
7 3 3 11
8 4 4 16
0 голосов
/ 27 февраля 2015
n <- 10
mat <- cor(matrix(rnorm(n*n),n,n))
ix <- matrix(NA,n*(n-1)/2,2)
k<-0
for (i in 1:(n-1)){
    for (j in (i+1):n){
    k <- k+1
    ix[k,1]<-i
    ix[k,2]<-j
    }
}
o <- rep(NA,nrow(ix))
o <- mat[ix]
out <- cbind(ix,o)
...