Wyodrębnij nazwy z zagnieżdżonej listy data.frames

10

Mam zagnieżdżoną listę data.frames, jaki jest najłatwiejszy sposób na uzyskanie nazw kolumn wszystkich data.frames?

Przykład:

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

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

Wynik:

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

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

$c
[1] "a" "b" "c"
użytkownik680111
źródło

Odpowiedzi:

7

Jest już kilka odpowiedzi. Ale zostawmy inne podejście. Użyłem rapply2()w pakiecie 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"
jazzurro
źródło
5

Oto podstawowe rozwiązanie R.

Możesz zdefiniować niestandardową funkcję spłaszczania listy zagnieżdżonej (która może obsługiwać zagnieżdżoną listę dowolnych głębokości , np. Więcej niż 2 poziomy), tj.

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

a następnie użyj następującego kodu, aby uzyskać nazwy coln

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

takie, że

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

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

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

Przykład z głębiej zagnieżdżoną listą

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

i dostaniesz

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

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

$c.e.f.g
[1] "a" "b" "c"
ThomasIsCoding
źródło
4

Oto próba zrobienia tego w jak największym stopniu wektoryzowanym,

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"

Możemy teraz podzielić się i2na wszystko przed kropką, co da,

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"

Aby je w pełni wyczyścić, musimy zapętlić i zastosować prosty regex,

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

co daje,

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

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

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

Kod zagęszczony

i1 <- names(unlist(l, TRUE, TRUE))
i2 <- names(split(i1, gsub('\\d+', '', i1)))
final_res <- lapply(split(i2, sub('\\..*', '', i2)), function(i)sub('.*\\.', '', i))
Sotos
źródło
3

Spróbuj tego

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)

Najważniejsze jest to, że w data.framesrzeczywistości są to specjalne listy, więc ważne jest, na co należy testować.

Małe wyjaśnienie: tutaj należy wykonać rekurencję, ponieważ przy każdym elemencie możesz spojrzeć na ramkę danych, więc chcesz zdecydować, czy zastosować nameslub przejść głębiej do rekurencji i fooponownie zadzwonić .

Gruzja
źródło
Problem polega na tym, że foo (l, nazwy) zwraca również zagnieżdżoną listę
user680111,
Ja nie. Nie jestem pewien, co zrobiłeś inaczej.
Georgery,
Możesz dodać unlist()na końcu, ale nie jestem pewien, czy tego właśnie chcesz.
Georgery,
2

Najpierw utwórz l1, zagnieżdżoną listę zawierającą tylko nazwy coln

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

Następnie unlist l1

unlist(l1, recursive=F)
Solarion
źródło
2

Oto jeden ze sposobów korzystania z purrrfunkcji map_depthivec_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"
Ronak Shah
źródło