2017-09-27 2 views
1

I ont une liste:Comment puis-je supprimer les valeurs partagées à partir d'une liste des vecteurs

x <- list("a" = c(1:6,32,24) , "b" = c(1:4,8,10,12,13,17,24), 
      "F" = c(1:5,9:15,17,18,19,20,32)) 
x 

$a 
[1] 1 2 3 4 5 6 32 24 

$b 
[1] 1 2 3 4 8 10 12 13 17,24 

$F 
[1] 1 2 3 4 5 9 10 11 12 13 14 15 17 18 19 20 32 

Chaque vecteur dans la liste partage un certain nombre d'éléments avec les autres. Comment puis-je supprimer des valeurs partagées pour obtenir le résultat suivant?

$a 
    [1] 1 2 3 4 5 6 32 24 

    $b 
    [1] 8 10 12 13 17 

    $F 
    [1] 9 11 14 15 18 19 20 

Comme vous pouvez le voir: le premier vecteur ne change pas. Les éléments partagés entre les premier et second vecteurs seront supprimés du deuxième vecteur, puis nous supprimerons les éléments partagés des troisièmes vecteurs après les avoir comparés avec les premier et second vecteurs. La cible de cette tâche est le groupe de données en cluster (l'ensemble de données d'origine contient 590 objets).

Répondre

1
x <- list("a" = c(1:6,32,24) , 
      "b" = c(1:4,8,10,12,13,17,24), 
      "F" = c(1:5,9:15,17,18,19,20,32)) 

Ceci est inefficace car elle re-fait l'union de l'ensemble des listes précédentes à chaque étape (plutôt que garder un total en cours d'exécution), mais il était le je pensais que la première façon .

for (i in 2:length(x)) { 
    ## construct union of all previous lists 
    prev <- Reduce(union,x[1:(i-1)]) 
    ## remove shared elements from the current list 
    x[[i]] <- setdiff(x[[i]],prev) 
} 

Vous pouvez probablement améliorer ce en initialisant prev comme numeric(0) et faisant prev dans c(prev,x[i-1]) à chaque étape (bien que celle-ci devienne un vecteur à chaque étape, ce qui est une opération lente). Si vous n'avez pas un ensemble de données gigantesque/n'avez pas à faire cette opération des millions de fois c'est probablement assez bon.

5

Vous pouvez utiliser Reduce et setdiff dans la liste dans l'ordre inverse pour trouver tous les éléments du dernier vecteur qui n'apparaissent pas dans les autres. Bung cela en un lapply pour exécuter sur des sous-listes partielles pour obtenir votre sortie désirée:

lapply(seq_along(x), function(y) Reduce(setdiff,rev(x[seq(y)]))) 
[[1]] 
[1] 1 2 3 4 5 6 32 24 

[[2]] 
[1] 8 10 12 13 17 

[[3]] 
[1] 9 11 14 15 18 19 20 

Lorsque plus grande échelle, le nombre de rev appels peut devenir un problème, vous voudrez peut-être inverser la liste une fois, à l'extérieur le lapply en tant que nouvelle variable, et sous-ensemble en son sein.

+0

x_rev <- rev (x); lapply (seq_along (x), fonction (y) Reduce (setdiff, x_rev [seq (y)])) ... donnera un résultat différent, en ce qui concerne votre commentaire. +1 de toute façon. Votre solution est une vraie beauté. –

+0

Merci, James pour votre réponse, cela fonctionne parfaitement. – Noor

+0

@AndreElrico Bon point, il faut faire attention à l'indexation. Je pense que 'tail (x_rev, y)' fonctionnerait mieux. – James