2012-06-10 2 views
1

Мне нужно создать ~ 110 ковариационных матриц размером в 19347 x 19347, а затем добавить их все вместе.Создание большой ковариационной матрицы

Это само по себе не очень сложно, и для меньших матриц следующий код работает нормально.

covmat <- matrix(0, ncol=19347, nrow=19347) 
files<-list.files("path/to/folder/") 
for(name in files){ 
    text <- readLines(paste("path/to/folder/", name, sep=""), n=19347, encoding="UTF-8") 
    for(i in 1:19347){ 
    for(k in 1:19347){ 
     covmat[i, k] <- covmat[i,k] + (as.numeric(text[i]) * as.numeric(text[k])) 
    } 
    } 
} 

Для сохранения памяти Я не вычисляю каждую отдельную матрицу, а добавляю ее вместе, когда она проходит через каждый файл.

Проблема заключается в том, что я запускаю ее на реальных данных, которые мне нужны, чтобы использовать это слишком долго. На самом деле данных не так много, но я думаю, что это работа с процессором и памятью. Таким образом, его запуск в течение ~ 10 часов не вычисляет результат.

Я искал попытку использования Map Reduce (AWS EMR), но я пришел к выводу, что я не верю, что это проблема с уменьшением карты, поскольку это не большая проблема с данными. Однако вот код для моего картографа и редуктора, с которым я играл, если я только делал это неправильно.

#Mapper 
text <- readLines("stdin", n=4, encoding="UTF-8") 
covmat <- matrix(0, ncol=5, nrow=5) 

for(i in 1:5){ 
    for(k in 1:5){ 
    covmat[i, k] <- (as.numeric(text[i]) * as.numeric(text[k])) 
    } 
} 

cat(covmat) 

#Reducer 
trimWhiteSpace <- function(line) gsub("(^ +)|(+$)", "", line) 
splitIntoWords <- function(line) unlist(strsplit(line, "[[:space:]]+")) 
final <- matrix(0, ncol=19347, nrow=19347) 
## **** could wo with a single readLines or in blocks 
con <- file("stdin", open = "r") 
while (length(line <- readLines(con, n = 1, warn = FALSE)) > 0) { 

    line <- trimWhiteSpace(line) 
    words <- splitIntoWords(line) 
    final <- final + matrix(as.numeric(words), ncol=19347, nrow=19347) 
} 
close(con) 
cat(final) 

Может кто-нибудь предложить, как решить эту проблему?

Заранее спасибо

EDIT

Благодаря большой помощи со стороны некоторых комментаторов ниже я пересмотрел код, чтобы он намного эффективнее.

files<-list.files("path/to/file") 
covmat <- matrix(0, ncol=19347, nrow = 19347) 
for(name in files){ 
    invec <- scan(paste("path/to/file", name, sep="")) 
    covmat <- covmat + outer(invec,invec, "*") 
} 

Вот пример файла, который я пытаюсь обработать.

1  0.00114582882882883 
2  -0.00792611711711709 
...      ... 
19346 -0.00089507207207207 
19347 -0.00704709909909909 

При запуске программы все равно требуется ~ 10 минут на файл. Есть ли у кого-нибудь советы о том, как это можно ускорить?

У меня 8 ГБ ОЗУ, и когда программа запускается R, она использует только 4,5 ГБ, и есть небольшая сумма бесплатно.

Я бегу Mac OS X Snow Leopard и R 64-битной ст. 2,15

+0

Что-то не так; Я не могу сказать вам, что, но не должно занимать более 10 часов, чтобы выполнять умножения и дополнения на 44E9. Как долго он обрабатывает только одну матрицу? Также рассмотрите преобразование каждого вектора из текста в числовой * один раз *, а не внутри цикла. Кроме того, вы пытались переставить свой порядок вложения в петлю? Я не знаю, является ли R [основным или крупным] (http://en.wikipedia.org/wiki/Row_major), но если вам не повезло, вы будете пропускать кеш при каждом обновлении на 'covmat'. –

+3

Вы НЕ должны добавлять элемент матрицы по элементу. Просто используйте «+». Не имеет смысла преобразовывать числовые в текст и использовать 'readLines'. Если вы знаете размеры файла и все его числовые, вы можете просто использовать 'scan()' для ввода. В pkg MASS есть функция 'write.matrix', которая может сэкономить накладные расходы на хранение. Возможно, вам захочется просмотреть ваши старые вопросы. Есть некоторая нерешительность в том, чтобы тратить много времени, когда есть послужной список непринятия. –

+0

Спасибо за ответ. Я ждал час для одной матрицы, но он не вычислил результат, поэтому я отменил работу. – TrueWheel

ответ

1

Возможно

covmat <- matrix(0, ncol=19347, nrow = 19347) 
files <- paste("path/to/folder/", list.files("path/to/folder/"), sep = '') 
for(name in files){ 
    vec <- scan(name, nlines = 19347) 
    mat <- outer(vec, vec, '*') 
    covmat <- covmat + mat 
} 

Я предполагаю, но, возможно, вы действительно хотите что-то вроде ...

numFiles <- 110 
mat <- matrix(0, ncol= numFiles, nrow = 19347) 
files <- paste("path/to/folder/", list.files("path/to/folder/"), sep = '') 
for(i in 1:numFiles){ 
    mat[i,] <- scan(files[i], nlines = 19347) 
} 
covmat <- cov(mat) 
+0

спасибо за ответ. Я отвел вам первый ответ только на один файл, и он не вычислил ответ в 20 минут. Я пробовал по суммарным фиктивным данным матрицы 10x10 и отлично работает. Даже если он закончил в 21 минуту для 110 файлов, потребуется около 38 часов. Есть ли у вас какие-либо предложения о том, как я могу ускорить это? Благодарю. – TrueWheel

+0

Это команда sapply, которая требует много времени для вычисления. Это должно быть намного быстрее, чем то, что вы написали. Действительно ли моя вторая версия действительно делает то, что вы действительно хотите? Это вычисление ковариационной матрицы всех ваших файлов. – John

+0

Нет, я играл с cov, но я не на 100% на то, что он рассчитывает. Я пытаюсь создать ковариационную матрицу, используя это уравнение http://en.wikipedia.org/wiki/Principal_component_analysis#Find_the_covariance_matrix и не верю, что это то, что он делает. – TrueWheel

4

У меня есть проблемы с логикой в ​​вашей петле. Вы вычисляете результат, который по существу является covmat + external (in.vec).

text <- c("1", "5", "8") 
    for(i in 1:3){ 
    for(k in 1:3){ 
     covmat[i, k] <- (as.numeric(text[i]) * as.numeric(text[k])) 
    } 
    } 
covmat 
    [,1] [,2] [,3] 
[1,] 1 5 8 
[2,] 5 25 40 
[3,] 8 40 64 
outer(as.numeric(text),as.numeric(text), "*") 
    [,1] [,2] [,3] 
[1,] 1 5 8 
[2,] 5 25 40 
[3,] 8 40 64 

Это не делает это неправильно, просто что-то, что может быть значительно упрощено в R, и если это то, что вы действительно хотите, то это векторизация функция может заменить целые внутренние две петли:

invec <- scan(paste("path/to/folder/", name, sep="") 
covmat <- outer(invec,invec, "*") 

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

matlist <- list() 
files<-list.files("path/to/folder/") 
    for(name in files){ 
     invec <- scan(paste("path/to/folder/", name, sep="") 
     covmat <- outer(invec,invec, "*") 
     matlist[[name]] <- covmat 
         } 

Теперь «matlist» должен иметь столько же матриц, сколько файлов в этом каталоге. Вы можете получить к ним доступ по имени или по порядку ввода. Вы можете получить имена с:

names(matlist) 
+0

Спасибо за ответ, я очень ценю ваш совет. Я понимаю, как это происходит намного быстрее и эффективнее. При обработке 2 файлов потребовалось 20 минут, что намного быстрее, чем исходный код. Чтобы спасти меня, чтобы запустить программу в течение ~ 18 часов, у 110 файлов есть какие-то советы о том, как я могу ускорить это? Благодарю. – TrueWheel

+0

Вы должны изменить свой вопрос выше, чтобы включить свой текущий код. На моей 4-летней машине потребовалось около 3 секунд для запуска: 'mat <- outer (1: 19347,1: 19347," * ")' Еще несколько _fractional_seconds_ сделали аналогичную проблему с "double" числовые векторы. Я предполагаю, что вы переходите в виртуальную память. У меня много оперативной памяти, и это довольно большой объект. –

+0

@TrueWheel: вам, вероятно, следует добавить информацию о вашей ОС, версии R и установленной оперативной памяти для решения проблемы системных ресурсов. –