2012-02-16 1 views
5

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

M <- c_alignment 
c_check <- function(x){ 
    if (x == c_1) { 
     1 
    }else{ 
     0 
    } 
} 
both_c_check <- function(x){ 
    if (x[res_1] == c_1 && x[res_2] == c_1) { 
     1 
    }else{ 
     0 
    } 
} 
variance_function <- function(x,y){ 
    sqrt(x*(1-x))*sqrt(y*(1-y)) 
} 
frames_total <- nrow(M) 
cols <- ncol(M) 
c_vector <- apply(M, 2, max) 
freq_vector <- matrix(nrow = sum(c_vector)) 
co_freq_matrix <- matrix(nrow = sum(c_vector), ncol = sum(c_vector)) 
insertion <- 0 
res_1_insertion <- 0 
for (res_1 in 1:cols){ 
    for (c_1 in 1:conf_vector[res_1]){ 
     res_1_insertion <- res_1_insertion + 1 
     insertion <- insertion + 1 
     res_1_subset <- sapply(M[,res_1], c_check) 
     freq_vector[insertion] <- sum(res_1_subset)/frames_total 
     res_2_insertion <- 0 
     for (res_2 in 1:cols){ 
      if (is.na(co_freq_matrix[res_1_insertion, res_2_insertion + 1])){ 
       for (c_2 in 1:max(c_vector[res_2])){ 
        res_2_insertion <- res_2_insertion + 1 
        both_res_subset <- apply(M, 1, both_c_check) 
        co_freq_matrix[res_1_insertion, res_2_insertion] <- sum(both_res_subset)/frames_total 
        co_freq_matrix[res_2_insertion, res_1_insertion] <- sum(both_res_subset)/frames_total 
       } 
      } 
     } 
    } 
} 
covariance_matrix <- (co_freq_matrix - crossprod(t(freq_vector))) 
variance_matrix <- matrix(outer(freq_vector, freq_vector, variance_function), ncol = length(freq_vector)) 
correlation_coefficient_matrix <- covariance_matrix/variance_matrix 

Входная модели будет что-то вроде этого:

1 2 1 4 3 
1 3 4 2 1 
2 3 3 3 1 
1 1 2 1 2 
2 3 4 4 2 

Что я вычисление биномиальной ковариации для каждого состояния найдено в M[,i] с каждым штатом, найденным в M[,j]. Каждая строка - это состояние, найденное для этого процесса, и я хочу посмотреть, как состояние столбцов изменяется.

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

Вход представляет собой матрицу 4200 x 510, а значение c для каждого столбца в среднем составляет около 15. Я знаю, что циклы for ужасно медленны в R, но я не уверен, как я могу использовать функцию apply здесь. Если у кого-то есть предложение по правильному использованию здесь apply, я бы очень признателен. Сейчас скрипт занимает несколько часов. Благодаря!

+0

Не могли бы вы добавить небольшой набор данных и то, что вы пытаетесь получить? – aatrujillob

+0

@AndresT Добавлена ​​дополнительная информация. –

+0

Вы пытались включить оптимизатор цикла для разворачивания в компиляторе? –

ответ

3

На самом деле это не 4-х вложенные петли, а то, как ваш код увеличивает память на каждой итерации. Это происходит 4 раза, когда я разместил # ** на линиях cbind и rbind. Стандартные рекомендации в R (и Matlab и Python) в таких ситуациях - это заранее распределить и затем заполнить его. Вот что делают функции apply. Они выделяют list до тех пор, пока известное количество результатов, присваивает каждому результату каждому слоту и затем объединяет все результаты вместе в конце. В вашем случае вы можете просто выделить правильную размерную матрицу заранее и назначить ей в этих 4 точках (грубо говоря). Это должно быть так же быстро, как и семейство apply, и вам может быть проще его закодировать.

15

Я думал написать комментарий, но у меня есть слишком много, чтобы сказать.

Прежде всего, если вы считаете, что применение идет быстрее, посмотрите на Is R's apply family more than syntactic sugar?. Это может быть, но это далеко не гарантировано.

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

Затем, смотрите на странице справки о ?subset и предупреждение дано там:

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

Всегда. Используйте. Индексы.

Далее Вы повторяете одни и те же значения снова и снова. fre_res_2, например, рассчитывается для каждого res_2 и state_2 столько раз, сколько у вас есть комбинации res_1 и state_1. Это просто пустая трата ресурсов. Выйдите из своих циклов, что вам не нужно пересчитывать, и сохраните их в матрицах, к которым вы можете просто получить доступ снова.

Heck, теперь я нахожусь: используйте векторизованные функции. Подумайте еще раз и посмотреть, что вы можете вытащить из петли: Это то, что я вижу, как ядро ​​вашего расчета:

cov <- (freq_both - (freq_res_1)*(freq_res_2))/
(sqrt(freq_res_1*(1-freq_res_1))*sqrt(freq_res_2*(1-freq_res_2))) 

Как я вижу, вы можете построить матрицу freq_both, freq_res_1 и freq_res_2 и использовать их как вход для этой одной строки. И это будет вся ковариационная матрица (не называйте ее cov, cov - функция). Выйти из цикла. Введите быстрый код.

Учитывая тот факт, я не имею понятия, что в c_alignment, я не собираюсь переписывать код для вас, но вы обязательно должны избавиться от пути C мышления и начать думать Р.

Пусть это Старт: The R Inferno

+1

Хотел бы я дать вам +2! отличный ответ и ссылки! – Justin

+0

В частности, обратите внимание на круг 2 «The R Inferno». –

+0

I second the +2 –