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"

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"

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"

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

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ć .


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)

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"
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.