2
votes

Comment renvoyer les éléments uniques entre les vecteurs tout en conservant le vecteur source de ces éléments uniques?

Par exemple, j'ai 5 vecteurs dans une liste:

Reduce(setdiff, list("my_vectors"))

En réalité, j'ai des centaines de ces vecteurs mais je n'ai donné que 5 vecteurs pour la reproductibilité. Mon objectif est de:

  1. Identifiez les éléments uniques provenant des vecteurs. Par exemple, le vector A ne doit rien renvoyer car tous ses éléments font partie du vector B , mais le vector B contribue avec un élément unique supplémentaire et c'est 6 . Vector C devrait me donner 7,8,9 puisque c(5,6) était déjà inclus dans le vector B Vector D ne doit rien renvoyer car tous ses éléments font partie de C
  2. reconnaître quel élément est unique à partir de quel vecteur
  3. Trouvez quels vecteurs sont des sous-ensembles d'autres vecteurs plus grands. Par exemple, le vector D est un sous-ensemble de C et le vector A est un sous-ensemble du vector B

Jusqu'à présent, la seule solution que j'ai trouvée était:

A <- c(1,2,3,4,5)

B <- c(1,2,3,4,5,6)

C <- c(5,6,7,8,9)

D <- c(8,9)

Mais cela ne me permet pas de reconnaître quel élément est unique à partir de quel vecteur. Par exemple, Reduce(setdiff, list(A,B)) renverrait 6 , mais je n'aurais aucune idée d'où vient le 6 ( A ou B )?

Ma difficulté est qu'il s'agit d'un problème à grande échelle, je n'ai pas seulement 5 vecteurs, j'en ai des centaines, donc je ne peux pas trouver de solution durable. Tous les conseils sont appréciés.

Edit: mes vecteurs sont dans une liste


5 commentaires

Les vecteurs sont-ils dans le .GlobalEnv ou dans une liste?


Ils sont dans une liste. J'ai donc une liste de vecteurs.


Dans votre exemple, il n'y a pas de chiffrements exclusifs.


Ceci n'est pas bien défini: par exemple, A ne doit rien renvoyer car B contient tous les éléments de A, mais B doit renvoyer 6. Cependant, 6 est également contenu dans C. Donc, ici, le seul élément vraiment unique que vous avez est 7 dans C am Je corrige?


Exactement. C'est plutôt ambigu.


4 Réponses :


1
votes

Une première approche naïve serait une boucle for, juste pour avoir une solution de travail. La fonction renvoie une liste avec les éléments unqiue et un dataframe, décrivant de quel vecteur dans la vectorList proviennent les éléments uniques (première apparition).

bigVectorList <- lapply(1:200, function(k) {
  sample(1:1e6,1000)
})

microbenchmark::microbenchmark(ff(bigVectorList),times=10)
#Unit: milliseconds
#              expr      min       lq     mean   median      uq      max neval
#ff(bigVectorList) 619.5148 624.8351 639.7535 633.2326 647.118 685.0387    10

Je ne sais pas à quel point vous avez besoin de la fonction, mais même avec 200 vecteurs de longueur 1000, elle semble être arrêtée rapidement (je ne connais pas vos dimensions):

A <- c(1,2,3,4,5)
B <- c(1,2,3,4,5,6)
C <- c(5,6,7,8,9)
D <- c(8,9)

vectorList <- list(A,B,C,D)

ff <- function(vectorList) {
  uniques <- unique(vectorList[[1]])
  comingFromDf <- data.frame(values=uniques)
  comingFromDf$source <- 1
  
  for(k in 2:length(vectorList)) {
    vec <- vectorList[[k]]
    newUniques <- vec[!(vec %in% uniques)]
    if(length(newUniques)) {
      newUniques <- unique(newUniques)
      toAdd <- data.frame(values=newUniques)
      toAdd$source <- k
      comingFromDf <- rbind(comingFromDf,toAdd)
      uniques <- c(uniques,newUniques)
    }
  }
  
  list(uniqueElements = uniques,
       comingFromInfo = comingFromDf)
}

ff(vectorList)

Sur ma machine, cela a pris un peu plus d'une demi-seconde, peut-être que cela vous suffit. Étant donné que la fonction n'inclut que des vecteurs et une trame de données, il serait facile de la réimplémenter en C ++ et en utilisant Rcpp. Cela devrait être beaucoup plus rapide que l'implémentation de la boucle for dans R. De plus, vous pouvez envisager d'utiliser l'argument d' accumulate dans la fonction Reduce pour enregistrer les résultats de calcul intermédiaires.


0 commentaires

1
votes

Supposons que vos données soient stockées comme ceci:

[[1]]
[1] 1 2 3 4 5

[[2]]
[1] 6

[[3]]
[1] 7 8 9

[[4]]
numeric(0)

Si vous utilisez accumulate = TRUE à l'appel de Reduce , vous obtenez également tous les résultats intermédiaires. Nous pouvons l'utiliser avec union pour construire le jeu total étape par étape (notez que j'ai mis init = c() pour nous assurer que nous commençons à vide):

lapply(1:length(my_vectors), function(i) setdiff(my_vectors[[i]], acc[[i]]))

Ensuite, nous pouvons prendre le setdiff de chaque élément avec cette liste construite.

acc <- Reduce(union, my_vectors, init = c(), accumulate = T)

Cela donne

my_vectors <- list(
  A = c(1,2,3,4,5),
  B = c(1,2,3,4,5,6),
  C = c(5,6,7,8,9),
  D = c(8,9)
)

Vous pouvez appliquer les noms de my_vectors plus tard si vous le souhaitez.


0 commentaires

1
votes

Voici une solution tidyverse .

lag(accumulate(l, union)) garde une trace de tous les éléments vus jusqu'à présent. La différence entre celle-ci et la liste d'origine donne les éléments nouvellement vus.

l %>%
  enframe() %>%
  expand_grid(a = ., b = .) %>%
  filter(
    a$name != b$name,
    map2_lgl(a$value, b$value, ~all(.x %in% .y))
  ) %>%
  transmute(this_vector = a$name, is_a_subset_of_this_vector = b$name)
#> # A tibble: 2 x 2
#>   this_vector is_a_subset_of_this_vector
#>   <chr>       <chr>                     
#> 1 A           B                         
#> 2 D           C 

Voici une réponse à votre autre question sur la recherche des vecteurs qui sont des sous-ensembles d'autres vecteurs plus grands.

expand_grid obtiendra toutes les combinaisons des vecteurs. Filtrez-le pour trouver quel vecteur est un sous-ensemble de tout autre vecteur.

library(tidyverse)

l <- lst(A, B, C, D)

map2(l, lag(accumulate(l, union)), setdiff)
#> $A
#> [1] 1 2 3 4 5
#> 
#> $B
#> [1] 6
#> 
#> $C
#> [1] 7 8 9
#> 
#> $D
#> numeric(0)


0 commentaires

0
votes

Ici, vous n'avez qu'un seul élément vraiment unique qui est 7 en C Le ci-dessous renverra les éléments uniques ainsi que leurs adhésions

mylist <- list("A"=A,"B"=B,"C"=C,"D"=D) #better for 100's of vectors
myres <- !unlist(lapply(1:length(mylist), function(x) unlist(mylist[x]) %in% unlist(mylist[-x])))
result <- as.numeric(unlist(mylist)[myres])
member <- sapply(mylist, function(x) result %in% x)
membername <- names(mylist[member])
result
membername
> result
 7 
> membername
[1] "C"


0 commentaires