7
votes

R: moyen le plus rapide de vérifier la présence de chaque élément d'un vecteur dans chacune des colonnes d'une matrice

J'ai un vecteur entier A code> xxx pré>

et une matrice entier b code> p> xxx pré >

Et j'aimerais créer un nouveau booléen lxc code> matrice indiquant si chaque élément de vecteur dans A code> est présent dans chaque colonne spécifique de matrice B code>. P>

J'ai essayé ceci avec p> xxx pré>

ou avec p>

a1=a(1000)
B1=B(20000)
system.time(ispresent1(a1,B1))
   user  system elapsed 
  76.63    1.08   77.84 

system.time(ispresent2(a1,B1))
   user  system elapsed 
  218.10    0.00   230.00 


8 commentaires

Vous voulez dire présent dans n'importe quel de la colonne de B matrice? Votre libellé me ​​déroule tout en regardant votre code


Non, je veux dire la présence de chaque élément vectoriel dans chacune des colonnes - le "Tout" dans le code est utilisé pour fonctionner sur le tableau 3 dimensionnel OUT produit par externe.


Pour reformuler l'exigence: Pour chaque élément de chaque colonne de B2, définissez VRAI est la valeur est dans A1, FAUX sinon? (Ai-je raison ou ai-je totalement manqué le point?)


Non, c'est l'inverse - pour chaque élément de vecteur A1, je veux savoir s'il se produit parmi les éléments de chacune des colonnes de B1 - Je pense que votre demande fonctionne dans l'inverse ...


Le résultat devrait donc être un l x c (ici 1000 x 20000) matrice booléenne - votre Apply retournerait une matrice de 5 x 20 000, ce qui n'est pas ce que je suis après ... désolé si je n'étais pas clair quelque part ...


@Tomwenseleers donc dans ce cas: Appliquer (B1,2, fonction (x) {A1% en% x}) devrait faire. (près de 40 fois plus vite que ispresent1 sur ma machine) (et résultats vérifiés avec identique )


@TENSIBAI C'est soigné, vous devriez poster cela.


Ha oui bien sûr - merci beaucoup pour cela - je savais qu'il devait y avoir une solution simple - faisait clairement des choses un peu surcpliquées! Cela vous dérangerait-il de l'afficher comme une réponse?


3 Réponses :


-1
votes
a=function(l) as.integer(runif(l,1,600))
B=function(c) matrix(as.integer(runif(5*c,1,600)),nrow=5)

ispresent1 = function (a,B) { 
  out = outer(a, B, FUN = "==" )
  apply(out,c(1,3),FUN="any") }

ispresent2 = function (a,B) t(sapply(1:length(a), function(i) apply(B,2,function(x) a[[i]] %in% x)))

ispresent3<-function(a,B){
  tf<-matrix((B %in% a),nrow=5)
  sapply(1:ncol(tf),function(x) a %in% B[,x][tf[,x]])
}

a1=a(1000)
B1=B(20000)

> system.time(ispresent1(a1,B1))
   user  system elapsed 
  29.91    0.48   30.44 

> system.time(ispresent2(a1,B1))
   user  system elapsed 
  89.65    0.15   89.83 

> system.time(ispresent3(a1,B1))
   user  system elapsed 
   0.83    0.00    0.86 

res1<-ispresent1(a1,B1)
res3<-ispresent3(a1,B1)

> identical(res1,res3)
[1] TRUE

3 commentaires

Thx pour cela - ne pensez pas que cela soit correct cependant, car ma matrice de sortie est constituée comme une matrice L x C (ici 1000 x 20000) ...


b <-unique (b) ceci était inutile. Mais ok je te comprends. Toutes les valeurs A1 doivent être uniques dans votre étude, je suppose.


Oui c'est correct - dans mes données réelles, il n'y aurait pas de nombreux éléments en double (presque non) ... suppose que j'aurais dû dire que ...



8
votes

RCPP code> est génial pour des problèmes tels que celui-ci. Il est tout à fait possible qu'il y ait un moyen de le faire avec data.table code> ou avec une fonction existante, mais avec le paquet inline code>, il faut presque moins de temps pour l'écrire vous-même que de savoir.

[1] TRUE


1 commentaires

Merci beaucoup pour cela! Près de deux fois plus vite que la solution mentionnée ci-dessus Ispresent = fonction (A, B) Appliquer (B, 2, fonction (x) {a% en% x})! Super! Thx millions! Sera ma chance de finalement entrer dans la RCPP!



10
votes

Après avoir creusé un peu et par curiosité à propos de la réponse de la RCPP de @backlin, j'ai écrit une référence de solution Orignale et nos deux solutions:

Je devais changer la fonction de Backlin comme inline ne fonctionnait pas sur mon Boîte à Windows (désolé si j'ai raté quelque chose avec elle, laissez-moi savoir s'il y a quelque chose à adapter) p>

code utilisé: p> xxx pré>

validation: P> > XXX PRE>

Benchmark: P>

> library(microbenchmark)
> microbenchmark(ispresent1(a1,B1),tensibai(a1,B1),backlin(a1,B1),times=3)

Unit: milliseconds
               expr        min         lq       mean     median         uq        max neval
 ispresent1(a1, B1) 36358.4633 36683.0932 37312.0568 37007.7231 37788.8536 38569.9840     3
   tensibai(a1, B1)   603.6323   645.7884   802.0970   687.9445   901.3294  1114.7144     3
    backlin(a1, B1)   471.5052   506.2873   528.3476   541.0694   556.7689   572.4684     3


5 commentaires

Je t'en prie. @Backlin pourrait vérifier que je n'ai pas pénalisé votre fonction pendant la migration vers CPPFunction ?


Nice @tensaibai! Je suis donc dans RCPP pour le moment que j'oublie parfois à quel point la base est bonne base. À moins que l'ensemble de données ne soit énorme ou que vous devez exécuter la fonction un million de fois, votre solution serait le choix sensible car cela vous permet d'économiser du temps de développement précieux et est plus facile à lire également.


Il n'y a aucune différence de temps entre votre code C ++ et le mien (le vôtre était en fait de 10 millisecondes plus rapidement dans mon analyse comparative).


@Backlin je ne comprends pas pourquoi, je n'ai changé que la déclaration en fait. Je suppose que 10 ms différence est davantage en raison de facteurs externes sur la machine de référence (autres processus utilisant la CPU avec une priorité plus élevée par exemple)


Un doute ne serait-il pas possible dans externe en utilisant vectorisation (non testé)