Должен ускорить рядовые операции - PullRequest
3 голосов
/ 23 февраля 2012

Мне нужно выполнять строковые операции более 15 миллионов раз, но у меня слишком медленный код.Вот небольшой воспроизводимый пример:

costMatrix1 <- rbind(c(4.2,3.6,2.1,2.3),c(9.6,5.5,7.2,4.9),c(2.6,8.2,6.4,8.3),c(4.8,3.3,6.8,5.7))
costMatrix2 <- costMatrix1 #Example, the costMatrix2 is actually different from costMatrix1

tbl_Filter <- rbind(c(0,0,0,4),c(1,2,3,4),c(1,0,3,0),c(1,2,0,0),c(1,2,0,4))

tbl_Sums <- data.frame(matrix(0, nrow=10, ncol=2))
colnames(tbl_Sums) <- c("Sum1","Sum2")

for (i in 1:nrow(tbl_Filter))
{
  tbl_Sums[i,1] <- sum(costMatrix1[tbl_Filter[i,],tbl_Filter[i,]])
  tbl_Sums[i,2] <- sum(costMatrix2[tbl_Filter[i,],tbl_Filter[i,]])
}

Я думаю, что замена цикла for на ddply - это решение, но я не могу заставить его работать.

Ответы [ 4 ]

5 голосов
/ 23 февраля 2012

Если у вас есть очень большие массивы для работы, вам, вероятно, лучше придерживаться базы R.

Вот как вы можете использовать sapply для решения задачи суммирования для одной матрицы. Затем используйте его повторно для каждой входной матрицы:

sumOne <- function(cost, filter){
  sapply(1:nrow(filter), function(i)sum(cost[filter[i,], filter[i,]]))
}


cbind(
    sumOne(costMatrix1, tbl_Filter),
    sumOne(costMatrix2, tbl_Filter)
)

Результаты:

     [,1]  [,2]
[1,]  5.7  11.4
[2,] 85.5 171.0
[3,] 15.3  30.6
[4,] 22.9  45.8
[5,] 43.9  87.8

Это должно быть намного, намного быстрее, чем ваш цикл. Не потому, что цикл for по сути медленнее, чем sapply (это не так), а потому, что sapply автоматически резервирует память для результата в сочетании с тем, что [<- медленен.

4 голосов
/ 23 февраля 2012

Если у вас более одного ядра процессора, использование snowfall может помочь вам ускорить это. Настройка (предварительное распараллеливание):

newfun = function(n) {
  a <- sum(costMatrix1[tbl_Filter[n,],tbl_Filter[n,]])
  b <- sum(costMatrix2[tbl_Filter[n,],tbl_Filter[n,]])
  c(a,b)
  }

nvec = matrix(data = 1:nrow(tbl_Filter), ncol = 1)

t = proc.time()
out = t(apply(nvec,1,function(x) newfun(x)))
proc.time() - t

Теперь распараллелено:

## load 'snowfall' package
require(snowfall)

## Initialize parallel operation --> choose number of CPUs here!
sfInit( parallel=TRUE, cpus=2 )

##################################################################
## 'Export' functions and variables to all "slaves" so that parallel calculations
## can occur

sfExport(list=list('newfun'))

sfExport('costMatrix1')
sfExport('costMatrix2')
sfExport('tbl_Filter')
sfExport('nvec')

## call function using sfApply; will return values as a list object
 out = sfApply(nvec, 1, function(x) newfun(x))

## stop parallel computing job
sfStop()

tbl_Sums = as.data.frame(t(out))
colnames(tbl_Sums) <- c("Sum1","Sum2")
2 голосов
/ 23 февраля 2012

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

> ttt <- apply((tbl_Filter>0)*1,1,function(x) x %*% t(x))
> t(rbind(as.numeric(costMatrix1), as.numeric(costMatrix2)) %*% ttt)
     [,1]  [,2]
[1,]  5.7  11.4
[2,] 85.5 171.0
[3,] 15.3  30.6
[4,] 22.9  45.8
[5,] 43.9  87.8
0 голосов
/ 24 мая 2013

В дополнение к упомянутой выше библиотеке snowfall есть также multicore, которая реализует только параллельную версию lapply (называемую mclapply), а не apply, но код легко переписать в учесть это:

newfun = function(n) {
  a <- sum(costMatrix1[tbl_Filter[n,],tbl_Filter[n,]])
  b <- sum(costMatrix2[tbl_Filter[n,],tbl_Filter[n,]])
  c(a,b)
}

nvec = matrix(data = 1:nrow(tbl_Filter), ncol = 1)

# single-core version using apply
out = t(apply(nvec,1,newfun))

# multicore version using mclapply
library(multicore)
out.list = mclapply(1:nrow(nvec),function(i)newfun(nvec[i,]))) 
out = do.call("rbind", out.list) 

# if the number of rows is huge, this will be much faster than do.call:
library(data.table)
out = rbindlist(out.list)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...