компонентное произведение разреженного вектора с компонентной функцией другого вектора в R - PullRequest
0 голосов
/ 23 ноября 2010

Предположим, у меня есть два вектора b и a. Компоненты последнего (a) почти всегда равны нулю, за исключением нескольких.

Если я хочу вычислить компонентное произведение a и компонентную функцию (например, exp) для b, я могу сделать

a*exp(b)

Однако для тех компонентов с нулевым большинством, оценка exp для соответствующих компонентов b будет пустой тратой.

Мне было интересно в таких случаях, как этот, возможно ли более эффективное программирование на R? Или нет необходимости менять. Спасибо!

Ответы [ 4 ]

2 голосов
/ 23 ноября 2010

Чтобы развернуть ответ DWin и свой комментарий к нему, просто следите за 0 и добавьте обратно в тривиальные ответы:

## Dummy data
set.seed(1)
a <- sample(0:10, 100, replace = TRUE)
b <- runif(100)

## something to hold results
out <- numeric(length(a))
## the computations you *want* to do
want <- !a==0
## fill in the wanted answers
out[want] <- a[want] * exp(b[want])

, что дает правильные результаты:

> all.equal(out, a * exp(b))
[1] TRUE

Если вы хотите, вы можете обернуть это в функцию:

myFun <- function(a, b) {
    out <- numeric(length(a))
    want <- !a==0
    out[want] <- a[want] * exp(b[want])
    return(out)
}

Затем используйте ее

> all.equal(out, myFun(a, b))
[1] TRUE

Но нет ничего болееэффективнее, чем использование a * exp(b) напрямую.И *, и exp() векторизованы, поэтому они будут выполняться очень быстро, намного быстрее, чем любая из мер по сохранению резервирования, использованных в различных ответах.

Потребности в решениях для учета будут зависетьо том, насколько дорогая ваша функция (exp() в примере в вашем Q) в вычислительном выражении.Попробуйте оба подхода на небольшой выборке и оцените время (используя system.time()), чтобы увидеть, стоит ли дополнительных усилий выполнять поднабор для отслеживания 0.

2 голосов
/ 23 ноября 2010

Просто замените выражение на:

ifelse(a==0,0,a*exp(b))

Я был бы удивлен, если бы это улучшило производительность, хотя, поскольку интерпретируется R, затраты на выполнение ifelse, вероятно, хуже, чем потеря вызова exp.

1 голос
/ 23 ноября 2010

Аналогично предложению DWin:

> n <- 1e5
> nonzero <- .01
> b <- rnorm(n)
> a <- rep(0, n)
> a[1:(n*nonzero)] <- rnorm(n*nonzero)
> 
> system.time(replicate(100, {
+                   c <- a*exp(b)
+               }))
   user      system     elapsed 
   1.19        0.05        1.23 
> system.time(replicate(100, {
+                   zero <- a < .Machine$double.eps
+                   c <- a
+                   c[!zero] <- a[!zero]*exp(b[!zero])
+               }))
   user      system     elapsed 
   0.42        0.08        0.50 
0 голосов
/ 23 ноября 2010

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

a[ !b==0 ]*exp( b[!b==0] )

Также следует признать, что существуют ловушки для проверки на равенство в числовом режиме. Возможно, вы захотите взглянуть на zapsmall и all.equal как на альтернативные варианты в зависимости от реальной проблемы.

> 3/10 == 0.1*3
[1] FALSE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...