[r] 중첩 된 데이터 목록에서 Colname을 추출합니다.

data.frames의 중첩 목록이 있는데 모든 data.frames의 열 이름을 얻는 가장 쉬운 방법은 무엇입니까?

예:

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

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

결과:

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

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

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



답변

이미 몇 가지 답변이 있습니다. 그러나 다른 접근 방식을 남겨 두겠습니다. rapply2()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"


답변

기본 R 솔루션은 다음과 같습니다.

중첩 된 목록을 평평하게하는 사용자 정의 함수를 정의 할 수 있습니다 ( 예 : 2 단계 이상의 깊이를 갖는 중첩 된 목록을 처리 할 수 있음).

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

다음 코드를 사용하여 colname을 달성하십시오.

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

그런

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

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

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

더 깊은 중첩 목록이있는 예

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

그리고 당신은 얻을 것이다

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

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

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


답변

다음은 가능한 한 Vectorized로 시도하는 것입니다.

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"

이제 i2점 앞에있는 모든 것을 분할 할 수 있습니다 .

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"

그것들을 완전히 청소하려면 간단한 정규 표현식을 반복해서 적용해야합니다.

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

그것은,

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

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

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

압축 된 코드

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


답변

이 시도

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)

여기서 중요한 점은 data.frames실제로는 특별한 목록이므로 테스트 할 대상이 중요하다는 것입니다.

작은 설명 : 여기에서 수행해야 할 것은 재귀입니다. 모든 요소마다 데이터 프레임을 볼 수 있으므로 names재귀에 적용 하거나 더 깊이 들어가고 foo다시 호출 할지 여부를 결정하려고 합니다.


답변

먼저 Colname 만 포함 된 중첩 된 목록 인 l1을 작성하십시오.

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

그런 다음 l1을 나열 해제하십시오.

unlist(l1, recursive=F)


답변

여기에 사용하는 방법 중 하나입니다 purrr기능 map_depthvec_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"


답변