Extrahieren Sie Spaltennamen aus einer verschachtelten Liste von data.frames


10

Ich habe eine verschachtelte Liste von data.frames. Was ist der einfachste Weg, um die Spaltennamen aller data.frames abzurufen?

Beispiel:

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

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

Ergebnis:

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

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

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

Antworten:


7

Es gibt bereits einige Antworten. Aber lassen Sie mich einen anderen Ansatz verlassen. Ich habe rapply2()im rawr-Paket verwendet.

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

Hier ist eine Basis-R-Lösung.

Sie können eine benutzerdefinierte Funktion definieren, um Ihre verschachtelte Liste zu reduzieren (die verschachtelte Listen beliebiger Tiefen , z. B. mehr als 2 Ebenen, verarbeiten kann), d. H.

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)
}

Verwenden Sie dann den folgenden Code, um die Spaltennamen zu erhalten

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

so dass

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

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

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

Beispiel mit einer tieferen verschachtelten Liste

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

und du wirst bekommen

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

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

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

4

Hier ist ein Versuch, dies so vektorisiert wie möglich zu tun.

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"

Wir können jetzt i2alles vor dem Punkt aufteilen , der geben wird,

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"

Um sie vollständig zu reinigen, müssen wir eine Schleife ausführen und einen einfachen regulären Ausdruck anwenden.

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

was gibt,

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

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

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

Der Code wurde komprimiert

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

Versuche dies

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)

Der springende Punkt hier ist, dass es sich data.framestatsächlich um eine spezielle Liste handelt. Daher ist es wichtig, worauf zu testen ist.

Kleine Erklärung: Was hier getan werden muss, ist eine Rekursion, da Sie bei jedem Element entweder einen Datenrahmen betrachten können. Sie möchten also entscheiden, ob Sie namesdie Rekursion anwenden oder tiefer in die Rekursion einsteigen und fooerneut aufrufen .


Das Problem ist, dass foo (l, names) auch eine verschachtelte Liste
zurückgibt

Ich nicht. Ich bin mir nicht sicher, was du anders gemacht hast.
Georgery

Sie können unlist()am Ende hinzufügen , aber ich bin nicht sicher, ob dies das ist, was Sie wollen.
Georgery

2

Erstellen Sie zuerst l1, eine verschachtelte Liste mit nur den Spaltennamen

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)
})

Dann liste l1 auf

unlist(l1, recursive=F)

2

Hier ist eine Möglichkeit, purrrFunktionen map_depthund zu verwendenvec_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"
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.