2010-11-23 10 views
0

Supposons que j'ai deux vecteurs b et a. Les composants de ce dernier (a) sont presque toujours à zéro sauf quelques uns.produit par composant d'un vecteur clairsemé avec une fonction de composant d'un autre vecteur dans R

Si je veux calculer le produit par composante d'une et une fonction composante par composante (comme exp) de b, je peux faire

a*exp(b) 

Toutefois, pour ces majorité zéro composantes d'un, l'évaluation d'exp sur les composants correspondants de b sera un gaspillage.

Je me demandais dans des cas comme celui-ci, est-il possible de programmer plus efficacement dans R? Ou il n'y a pas besoin de changer. Merci!

Répondre

2

Pour développer la réponse de dwin, et votre commentaire, juste garder une trace du 0 et rajoutez dans les réponses triviales:

## 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]) 

Ce qui donne les bons résultats:

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

Si vous le souhaitez, vous pouvez envelopper dans une fonction:

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

T poule utilisent

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

Mais rien de tout cela est plus efficace que d'utiliser a * exp(b) directement. Les deux * et exp() sont vectorisés, donc fonctionnera très rapidement, beaucoup plus rapidement que l'une des mesures de tenue de réservation utilisées dans les diverses réponses jusqu'à présent. Si vous avez besoin de solutions de comptabilité, cela dépendra du coût de votre fonction (exp() dans l'exemple de votre Q) en termes de calcul. Essayez les deux approches sur un petit échantillon et évaluez les temps (en utilisant system.time()) pour voir si cela vaut la peine de faire l'effort supplémentaire de faire le sous-ensemble pour suivre le 0.

+0

-1 pour traiter b comme zéro. +1 pour note sur l'efficacité d'exécution. sum = 0. –

+0

Je ne peux pas vous mettre en colère maintenant, après avoir joué avec les boutons de vote avant. Faites un petit montage et puis je peux. –

0

Vous pourriez accomplir cela en indexant les deux vecteurs avec un test pour n'importe quelle situation que vous estimez être un gaspillage. Si la fonction est plus coûteux que le temps exp, il pourrait faire une différence:

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

reconnaissent également qu'il ya des pièges à tester l'égalité avec le mode numérique. Vous pouvez regarder zapsmall et all.equal comme alternatives en fonction de ce que le vrai problème est.

> 3/10 == 0.1*3 
[1] FALSE 
+2

Merci DWin! Mais un [! B == 0] * exp (b [!b == 0]) donnera un résultat différent d'un * exp (b). – Tim

+0

-1 c'est 'a' qui est principalement 0. –

+0

Yep. Diaphonie neuronale. Cela aurait dû être un [! A == 0] * exp (b [! A == 0]) mais souffre quand même de ne pas fournir le vecteur complet. –

1

similaires à la suggestion de 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 
2

Il suffit de remplacer votre expression avec:

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

Je serais surpris si cela fait une amélioration de la performance, cependant, puisque R est interprété , l'overhead de courir le ifelse est probablement pire que gaspiller l'invocation exp.

+0

Cela doit être 'ifelse (b == 0, a, a * exp (b))' --- notant que c'est 'b' qui contient les 0 et que si' b' * est * zéro, alors nous a 'a * 1' donc nous devons retourner' a' pas '0' pour ces cas. –

+0

Cochez la question - "Cependant, pour les composantes majoritaires de zéro, l'évaluation de exp sur les composantes correspondantes de b sera un gaspillage." –

+1

Désolé, vous avez totalement raison Plusieurs d'entre nous semblent avoir mal lu ça! –