Extraire les noms de colonnes d'une liste imbriquée de data.frames


10

J'ai une liste imbriquée de data.frames, quelle est la façon la plus simple d'obtenir les noms de colonne de tous les data.frames?

Exemple:

d = data.frame(a = 1:3, b = 1:3, c = 1:3)

l = list(a = d, list(b = d, c = d))

Résultat:

$a
[1] "a" "b" "c"

$b
[1] "a" "b" "c"

$c
[1] "a" "b" "c"

Réponses:


7

Il y a déjà quelques réponses. Mais permettez-moi de laisser une autre approche. J'ai utilisé rapply2()dans le package rawr.

devtools::install_github('raredd/rawr')
library(rawr)
library(purrr)

rapply2(l = l, FUN = colnames) %>% 
flatten

$a
[1] "a" "b" "c"

$b
[1] "a" "b" "c"

$c
[1] "a" "b" "c"

5

Voici une solution de base R.

Vous pouvez définir une fonction personnalisée pour aplatir votre liste imbriquée (qui peut traiter une liste imbriquée de n'importe quelle profondeur , par exemple, plus de 2 niveaux), c'est-à-dire,

flatten <- function(x){  
  islist <- sapply(x, class) %in% "list"
  r <- c(x[!islist], unlist(x[islist],recursive = F))
  if(!sum(islist))return(r)
  flatten(r)
}

puis utilisez le code suivant pour obtenir les noms de colonnes

out <- Map(colnames,flatten(l))

tel que

> out
$a
[1] "a" "b" "c"

$b
[1] "a" "b" "c"

$c
[1] "a" "b" "c"

Exemple avec une liste imbriquée plus profonde

l <- list(a = d, list(b = d, list(c = list(e = list(f= list(g = d))))))
> l
$a
  a b c
1 1 1 1
2 2 2 2
3 3 3 3

[[2]]
[[2]]$b
  a b c
1 1 1 1
2 2 2 2
3 3 3 3

[[2]][[2]]
[[2]][[2]]$c
[[2]][[2]]$c$e
[[2]][[2]]$c$e$f
[[2]][[2]]$c$e$f$g
  a b c
1 1 1 1
2 2 2 2
3 3 3 3

et vous obtiendrez

> out
$a
[1] "a" "b" "c"

$b
[1] "a" "b" "c"

$c.e.f.g
[1] "a" "b" "c"

4

Voici une tentative de le faire aussi vectorisé que possible,

i1 <- names(unlist(l, TRUE, TRUE))
#[1] "a.a1" "a.a2" "a.a3" "a.b1" "a.b2" "a.b3" "a.c1" "a.c2" "a.c3" "b.a1" "b.a2" "b.a3" "b.b1" "b.b2" "b.b3" "b.c1" "b.c2" "b.c3" "c.a1" "c.a2" "c.a3" "c.b1" "c.b2" "c.b3" "c.c1" "c.c2" "c.c3"
i2 <- names(split(i1, gsub('\\d+', '', i1)))
#[1] "a.a" "a.b" "a.c" "b.a" "b.b" "b.c" "c.a" "c.b" "c.c"

Nous pouvons maintenant nous séparer i2de tout avant le point, ce qui donnera,

split(i2, sub('\\..*', '', i2))

#    $a
#    [1] "a.a" "a.b" "a.c"

#    $b
#    [1] "b.a" "b.b" "b.c"

#    $c
#    [1] "c.a" "c.b" "c.c"

Pour les nettoyer complètement, nous devons boucler et appliquer une simple expression régulière,

 lapply(split(i2, sub('\\..*', '', i2)), function(i)sub('.*\\.', '', i))

qui donne,

$a
[1] "a" "b" "c"

$b
[1] "a" "b" "c"

$c
[1] "a" "b" "c"

Le Code compacté

i1 <- names(unlist(l, TRUE, TRUE))
i2 <- names(split(i1, gsub('\\d+', '', i1)))
final_res <- lapply(split(i2, sub('\\..*', '', i2)), function(i)sub('.*\\.', '', i))

3

Essaye ça

d = data.frame(a = 1:3, b = 1:3, c = 1:3)

l = list(a = d, list(b = d, c = d))

foo <- function(x, f){
    if (is.data.frame(x)) return(f(x))
    lapply(x, foo, f = f)
}

foo(l, names)

Le point crucial ici est qu'il s'agit en data.framesfait d'une liste spéciale, il est donc important de savoir quoi tester.

Petite explication: ce qui doit être fait ici est une récursivité, car avec chaque élément, vous pouvez regarder soit une trame de données, donc vous voulez décider si vous appliquez le namesou approfondissez la récursivité et appelez à foonouveau.


Le problème est que foo (l, names) renvoie également une liste imbriquée
user680111

Je ne. Je ne sais pas, ce que vous avez fait différemment.
Georgery

Vous pouvez ajouter unlist()à la fin, mais je ne sais pas si c'est ce que vous voulez.
Georgery

2

Créez d'abord l1, une liste imbriquée avec uniquement les noms de colonnes

l1 <- lapply(l, function(x) if(is.data.frame(x)){
  list(colnames(x)) #necessary to list it for the unlist() step afterwards
}else{
  lapply(x, colnames)
})

Puis annulez l1

unlist(l1, recursive=F)

2

Voici une façon d'utiliser les purrrfonctions map_depthetvec_depth

library(purrr)

return_names <- function(x) {
   if(inherits(x, "list"))
     return(map_depth(x, vec_depth(x) - 2, names))
    else return(names(x))
}

map(l, return_names)

#$a
#[1] "a" "b" "c"

#[[2]]
#[[2]]$b
#[1] "a" "b" "c"

#[[2]]$c
#[1] "a" "b" "c"
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.