ネストされたリスト構造をデータフレームに変換しようとしています。リストは次のようになります(httrパッケージを使用して読み込まれた解析済みJSONからのシリアル化されたデータです)。
_ myList <- list(object1 = list(w=1, x=list(y=0.1, z="cat")), object2 = list(w=NULL, x=list(z="dog")))
_
編集:元のサンプルデータは単純すぎました。実際のデータは不揃いです。つまり、すべてのオブジェクトにすべての変数が存在するわけではなく、リスト要素の一部がNULLです。これを反映するようにデータを編集しました。
unlist(myList)
は、リストを再帰的にフラット化する優れた機能を果たします。その後、lapply
を使用して、すべてのオブジェクトを適切にフラット化できます。
_ flatList <- lapply(myList, FUN= function(object) {return(as.data.frame(rbind(unlist(object))))})
_
最後に、_plyr::rbind.fill
_を使用してボタンを押します。
_ myDF <- do.call(plyr::rbind.fill, flatList)
str(myDF)
#'data.frame': 2 obs. of 3 variables:
#$ w : Factor w/ 2 levels "1","2": 1 2
#$ x.y: Factor w/ 2 levels "0.1","0.2": 1 2
#$ x.z: Factor w/ 2 levels "cat","dog": 1 2
_
問題は、wとx.yが文字ベクトルとして解釈され、デフォルトでデータフレーム内の要素として解析されることです。 unlist()
が原因だと思いますが、リスト構造を再帰的にフラット化する別の方法を見つけることはできません。回避策は、データフレームを後処理し、データ型を割り当てることです。ベクトルが有効な数値または整数のベクトルであるかどうかを判断するための最良の方法は何ですか?
説明したように ここ 、as.numeric
はNA
値を返します。これは、文字列に数値データが含まれているかどうかを確認するための簡単な方法です。今、あなたは次のようなことをすることができます:
myDF2 <- lapply(myDF, function(col) {
if (suppressWarnings(all(!is.na(as.numeric(as.character(col)))))) {
as.numeric(as.character(col))
} else {
col
}
})
str(myDF2)
# List of 3
# $ w : num [1:2] 1 2
# $ x.y: num [1:2] 0.1 0.2
# $ x.z: Factor w/ 2 levels "cat","dog": 1 2
NAが含まれている場合、@ josliberの関数は機能しません(サンプルデータの質問にはうまく答えますが)。 @Amy Mの関数は機能するはずですが、Hmisc
パッケージをロードする必要があります。
このようなものはどうですか?
_can.be.numeric <- function(x) {
stopifnot(is.atomic(x) || is.list(x)) # check if x is a vector
numNAs <- sum(is.na(x))
numNAs_new <- suppressWarnings(sum(is.na(as.numeric(x))))
return(numNAs_new == numNAs)
}
_
入力ベクトルのNA
sとas.numeric()
の出力のNA
sをカウントし、ベクトルをTRUE
に「安全に」変換できる場合(つまり、numeric
値を追加せずに)、NA
を返します。
plyr::ldply
を使用できます:
ldply(myList,.fun=function(x)data.frame(x))
.id w x.y x.z
1 object1 1 0.1 cat
2 object2 2 0.2 dog
通常のベースRメソッドに対するplyr :: ldplyの利点はわかりません。
do.call(rbind, lapply(myList, data.frame) )
#-------------
w x.y x.z
object1 1 0.1 cat
object2 2 0.2 dog
この問題は、データの固有の構造を考慮せずにデータを「フラット化」しようとする誤った試みが原因で発生していました。
文字列を含むリストまたはベクトルがあり、数値のみを数値に変換する場合、考えられる解決策は次のとおりです。
catchNumeric <- function(mylist) {
newlist <- suppressWarnings(as.numeric(mylist))
mylist <- as.list(mylist)
mylist[!is.na(newlist)] <- newlist[!is.na(newlist)]
mylist
}
> catchNumeric(c("123", "c12", "abc", "123.12"))
[[1]]
[1] 123
[[2]]
[1] "c12"
[[3]]
[1] "abc"
[[4]]
[1] 123.12
> catchNumeric(list("123", "c12", "abc", "123.12"))
[[1]]
[1] 123
[[2]]
[1] "c12"
[[3]]
[1] "abc"
[[4]]
[1] 123.12
読み込まれたときに誤って文字として分類されたすべての数値ベクトルを変換するだけの場合は、Hmisc
パッケージの関数all.is.numeric
を使用することもできます。
myDF2 <- lapply(myDF, Hmisc::all.is.numeric, what = "vector", extras = NA)
what = "vector"
を選択すると、ベクターに数値のみが含まれている場合は、ベクターが数値に変換されます。 NAまたはその他のタイプの欠落値は、上記のextras
引数で指定されていない限り、変換を妨げます。
ただし、DateまたはPOSIXctベクトルを含むdata.frame全体に適用した場合、これらも数値に変換されることに注意してください。これを防ぐには、次のような関数でラップします。
catchNumeric <- function(dtcol) {
require(Hmisc)
if (is.character(dtcol)) {
dtcol1 = all.is.numeric(dtcol, what = "vector", extras = NA)
} else {
dtcol1 = dtcol
}
return(dtcol1)
}
次に、data.frameに適用します。
myDF2 <- lapply(myDF, catchNumeric)