2013-12-04 7 views
-2

Я исхожу из фона теории вычислений Java/Python, поэтому я все еще привык к различным R-пакетам и как они могут экономить время выполнения в функциях.lapply с растущей функцией data.table в R

В принципе, я работаю над несколькими проектами, и все они связаны с использованием отдельных факторов в наборе данных с длинными списками (от 15 000 до 200 000 факторов) и выполнении вычислений по отдельным факторам в столь же большом наборе данных и одновременно сохраняя результаты этих вычислений в экспоненциально более длинном кадре данных.

До сих пор я использовал вложенные петли и конкатенацию в растущий список, но это занимает несколько дней. Ive недавно узнал о «lapply» и «data.frame» вариантов в R, и я хотел бы видеть пример того, как не применять (не каламбур) их к следующей основной функции корреляции:

Corr<-function(miRdf, mRNAdf) 
{ 
j=1 
k=1 
m=1 
n=1 
c=0 
corrList=NULL 
while(n<=71521) 
{ 
    while(m<=1477) 
    {  
    corr=cor(as.numeric(miRdf[k,2:13]), as.numeric(mRNAdf[j,2:13]), use ="complete.obs") 
    corrList<-c(corrList, corr) 
    j=j+1 
    c=c+1 
    print(c) #just a counter to see how far the function has run 
    m=m+1 
} 
k=k+1 
n=n+1 
j=1 
m=1   #to reset the inner while loop 
} 
corrList<-matrix(unlist(corrList), ncol=1477, byrow=FALSE) 
colnames(corrList)<-miRdf[,1] 
rownames(corrList)<-mRNAdf[,1] 
write.csv(corrList, "testCorrWhole.csv") 
} 

Как вы можете видеть, вложенный цикл while дает результаты 105R36517 (71521x1477) miRNA vs mRNA, которые необходимо выполнить и хранить в кадре данных, который составляет 1477 cols x 71521 строк, чтобы генерировать матрицу скоринга.

Мой вопрос в том, может ли кто-нибудь пролить свет на то, как превратить вышеупомянутое чудовище в эффективную функцию, которая использует «lapply» вместо циклов while и использует функцию set.tat.table(), чтобы покончить с неэффективность объединения списка во время каждого прохода через петлю?

Спасибо заранее!

+2

Не могли бы вы добавить некоторые образцы данных, пожалуйста? Это поможет людям легче работать над этим вопросом. –

+0

Как бы я мог добавить сюда эти огромные наборы данных? Это всего лишь кадры данных с 8 столбцами каждый и 1477 и 71 521 строк соответственно. Каждая строка из одного df сравнивается с каждой строкой второй. Я просто пытаюсь выяснить, как «переписать» вышеуказанный код, используя «lapply» и «data.table». Любой, кто знаком с этими функциями, легко сможет понять, что делает мой оригинальный код. –

+0

Предположим, вы googled, и вы уже прочитали статьи, которые могли бы помочь, например, http://www.jstatsoft.org/v40/i01/. Если у вас уже есть, то вы здесь для конкретных советов - вот где воспроизводимый набор кода пригодится, так как это облегчает людям работу и решение проблемы. Чем сложнее вы это сделаете, тем меньше вероятность получить ответ. Что касается того, как это сделать - вам не нужен полный data.frame, просто подмножество, использующее некоторые векторы rnorm(). http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example –

ответ

2

Ваши имена заканчиваются «ФР», что делает его казаться, что ваши данные являются data.frame. Но ответ Трои отвечает матрицей. Матрица подходит, когда данные являются однородными, и, как правило, операции с матрицами намного быстрее, чем операции data.frame. Итак, вы можете видеть, что если бы вы представили небольшой пример своего набора данных (например, dput(mRNAdf[1:10,]), то люди могут быть в лучшем положении, чтобы помочь вам, это то, о чем они просят.

В больших числовых в расчетах имеет смысл «поднять» любые повторные вычисления вне цикла, поэтому они выполняются только один раз. Повторные вычисления в вашем случае включают подстановку в столбцы 2:13 и принуждение к числовому. С этой идеей и угадыванием, что вы на самом деле имеет data.frame, где каждый столбец уже является числовым вектор, я хотел бы начать с

mRNAmatrix <- as.matrix(mRNAdf[,2:13]) 
miRmatrix <- as.matrix(miRdf[,2:13]) 

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

result <- cor(t(mRNAmatrix), t(miRmatrix), use="complete.obs") 

Это достаточно быстро для ваших целей

> m1 = matrix(rnorm(71521 * 12), 71521) 
> m2 = matrix(rnorm(1477 * 12), 1477) 
> system.time(ans <- cor(t(m1), t(m2))) 
    user system elapsed 
    9.124 0.200 9.340 
> dim(ans) 
[1] 71521 1477 

result так же, как ваш corrList - это не список, а матрица; вероятно, имена строк и столбцов перенесены вперед. Вы должны записать это в файл, как вы делаете выше, write.csv(result, "testCorrWhole.csv")

+0

Спасибо! Итак, в коде выше, где сценарий, который выводит отдельные коэффициенты cor в «выходной» кадр данных? Извините, если я не понимаю полностью. –

+1

Я обновил свой ответ. Результат - в матрице, а не в кадре data.frame (в вашем коде тоже, я думаю), и его можно записать в файл с помощью 'write.csv'. –

+0

Этот код прошел от 14hrs (так, как я его написал) до 45 секунд вашего пути. Я не могу поблагодарить вас! –

1

ОБНОВЛЕНО НИЖЕ ПОКАЗАТЬ параллельной обработки - около 60% экономии

Использование apply() не может быть достаточно быстро для вас. Вот как это сделать. Подумайте о производительности, поскольку этот пример (1M выходных корреляций в сетке 1000x1000) занимает минуту на ноутбуке.

miRdf=matrix(rnorm(13000,10,1),ncol=13) 
mRNAdf=matrix(rnorm(13000,10,1),ncol=13) 
miRdf[,1]<-1:nrow(miRdf)  # using column 1 as indices since they're not in the calc. 
mRNAdf[,1]<-1:nrow(mRNAdf) 

corRow<-function(y){ 
    apply(miRdf,1,function(x)cor(as.numeric(x[2:13]), as.numeric(mRNAdf[y,2:13]), use ="complete.obs")) 
    } 

system.time(apply(mRNAdf,1,function(x)corRow(x[1]))) 
# user system elapsed 
# 72.94 0.00 73.39 

И с parallel::parApply на 4 ядра Win64 ноутбук

require(parallel) ## Library to allow parallel processing 

miRdf=matrix(rnorm(13000,10,1),ncol=13) 
mRNAdf=matrix(rnorm(13000,10,1),ncol=13) 
miRdf[,1]<-1:nrow(miRdf)  # using column 1 as indices since they're not in the calc. 
mRNAdf[,1]<-1:nrow(mRNAdf) 

corRow<-function(y){ 
    apply(miRdf,1,function(x)cor(as.numeric(x[2:13]), as.numeric(mRNAdf[y,2:13]), use ="complete.obs")) 
    } 


     # Make a cluster from all available cores 
     cl=makeCluster(detectCores()) 
     # Use clusterExport() to distribute the function and data.frames needed in the apply() call 
     clusterExport(cl,c("corRow","miRdf","mRNAdf")) 
     # time the call 
     system.time(parApply(cl,mRNAdf,1,function(x)corRow(x[[1]]))) 

     # Stop the cluster 
     stopCluster(cl) 

     # time the call without clustering 
     system.time(apply(mRNAdf,1,function(x)corRow(x[[1]]))) 

     ## WITH CLUSTER (4) 
     user system elapsed 
     0.04 0.03 29.94 

     ## WITHOUT CLUSTER 
     user system elapsed 
     73.96 0.00 74.46  
+0

Спасибо человек. Я определенно сделаю это. Я действительно ценю, что вы действительно предлагаете реальный ответ. Я все еще ищу способ использовать data.table тоже. Но в любом случае, я действительно ценю некоторые фактические советы. Я начинал думать, что причина для того, чтобы не предлагать советы (в отличие от фактического предложения некоторых), была стандартной практикой для этого форума. Спасибо, что вы доказали обратное. –

+0

@TomA - думая об этом, я думаю, что много времени находится в фактических 1M корреляционных вычислениях. Я отредактировал этот пример, чтобы показать, как вы можете обрабатывать параллельно, используя parApply(). На моем ноутбуке я смог добиться улучшения на 60% по сравнению с apply() – Troy

+0

Я просматриваю ваш код прямо сейчас. У меня возникли проблемы с пониманием того, в какой момент вы создаете кадр выходных данных, который содержит оценки отдельных показателей корреляции? Еще раз спасибо! –

Смежные вопросы