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"
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"
回答:
これがベース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)
}
そして、次のコードを使用してcolnamesを取得します
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"
これを可能な限りベクトル化するための試みを以下に示します。
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
再度呼び出すかを決定する必要があります。
unlist()
最後に追加することもできますが、これでよいかどうかはわかりません。