11

この質問は、非周期的な同種または異種のデータ構造のコレクションをデータフレームに変換するための一般的なメカニズムに関するものです。これは、多くのJSONドキュメントの取り込みや、辞書の配列である大きなJSONドキュメントを処理する場合に特に役立ちます。

深くネストされたJSON構造を操作し、、などの機能を使用してデータフレームに変換することを扱うSOの質問がいくつかありますplyrlapply私が見つけたすべての質問と回答は、のコレクションを処理するための一般的なアプローチを提供するのではなく、特定のケースに関するものです。複雑なJSONデータ構造。

PythonとRubyでは、データ構造内のリーフノードへのパスを、フラット化されたデータ構造内のそのノードの値の名前として使用する汎用データ構造フラット化ユーティリティを実装することで、十分なサービスを受けています。たとえば、値my_data[['x']][[2]][['y']]はとして表示されresult[['x.2.y']]ます。

完全に均質ではない可能性のあるこれらのデータ構造のコレクションがある場合、データフレームのフラット化を成功させるための鍵は、たとえば、すべてのキー/名前の和集合を取ることによって、すべての可能なデータフレーム列の名前を見つけることです。個別にフラット化されたデータ構造の値。

これは一般的なパターンのように思われるので、誰かがすでにR用にこれを構築したかどうか疑問に思います。そうでない場合は構築しますが、Rの独自のpromiseベースのデータ構造を考えると、実装アプローチに関するアドバイスをいただければ幸いです。ヒープのスラッシングを最小限に抑えます。

4

4 に答える 4

9

こんにちは@Sim私は昨日あなたの問題を反省する原因がありました定義:

flatten<-function(x) {
    dumnames<-unlist(getnames(x,T))
    dumnames<-gsub("(*.)\\.1","\\1",dumnames)
    repeat {
        x <- do.call(.Primitive("c"), x)
        if(!any(vapply(x, is.list, logical(1)))){
           names(x)<-dumnames
           return(x)
        }
    }
}
getnames<-function(x,recursive){

    nametree <- function(x, parent_name, depth) {
        if (length(x) == 0) 
            return(character(0))
        x_names <- names(x)
        if (is.null(x_names)){ 
            x_names <- seq_along(x)
            x_names <- paste(parent_name, x_names, sep = "")
        }else{ 
            x_names[x_names==""] <- seq_along(x)[x_names==""]
            x_names <- paste(parent_name, x_names, sep = "")
        }
        if (!is.list(x) || (!recursive && depth >= 1L)) 
            return(x_names)
        x_names <- paste(x_names, ".", sep = "")
        lapply(seq_len(length(x)), function(i) nametree(x[[i]], 
            x_names[i], depth + 1L))
    }
    nametree(x, "", 0L)
}

getnamesAnnotationDbi ::: make.name.treeから採用)

flattenここでの議論から適応されます強制なしでリストをリストにフラット化する方法は?

簡単な例として

my_data<-list(x=list(1,list(1,2,y='e'),3))

> my_data[['x']][[2]][['y']]
[1] "e"

> out<-flatten(my_data)
> out
$x.1
[1] 1

$x.2.1
[1] 1

$x.2.2
[1] 2

$x.2.y
[1] "e"

$x.3
[1] 3

> out[['x.2.y']]
[1] "e"

したがって、結果は、おおよそあなたが提案する命名構造を持つフラット化されたリストになります。強制も回避されます。これはプラスです。

より複雑な例

library(RJSONIO)
library(RCurl)
json.data<-getURL("http://www.reddit.com/r/leagueoflegends/.json")
dumdata<-fromJSON(json.data)
out<-flatten(dumdata)

アップデート

末尾の.1を削除する素朴な方法

my_data<-list(x=list(1,list(1,2,y='e'),3))
gsub("(*.)\\.1","\\1",unlist(getnames(my_data,T)))

> gsub("(*.)\\.1","\\1",unlist(getnames(my_data,T)))
[1] "x.1"   "x.2.1" "x.2.2" "x.2.y" "x.3"  
于 2012-08-12T01:29:07.613 に答える
4

Rには、JSON入力を処理するためのrjsonRJSONIOの2つのパッケージがあります。「非周期的な同種または異種のデータ構造のコレクション」の意味を正しく理解していれば、これらのパッケージのいずれかがその種の構造をとしてインポートすると思いますlist

次に、関数を使用してそのリストを(ベクトルに)フラット化できunlistます。

リストが適切に構造化されている場合(各要素が同じ長さのネストされていないリスト)as.data.frame、リストをデータフレームに変換する代替手段がありません。

例:

(my_data <- list(x = list('1' = 1, '2' = list(y = 2))))
unlist(my_data)
于 2012-07-19T09:53:24.663 に答える
3

このパッケージは、 JSONとデータフレーム間の変換を容易にするために特別に設計されjsonliteたフォークです。RJSONIOサンプルデータは提供していませんjsonが、これがあなたが探しているものかもしれないと思います。このブログ投稿またはビネットをご覧ください。

于 2014-02-22T08:42:57.987 に答える
1

flatten関数とgetnames関数で素晴らしい答えが得られます。JSON文字列のベクトルからdata.frameに到達するために必要なすべてのオプションを理解するのに数分かかったので、ここにそれを記録すると思いました。jsonvecがJSON文字列のベクトルであるとします。以下は、文字列ごとに1つの行があり、各列がJSONツリーの異なる可能なリーフノードに対応するdata.frame(data.table)を構築します。特定のリーフノードが欠落している文字列は、NAで埋められます。

library(data.table)
library(jsonlite)
parsed = lapply(jsonvec, fromJSON, simplifyVector=FALSE)
flattened = lapply(parsed, flatten) #using flatten from accepted answer
d = rbindlist(flattened, fill=TRUE)
于 2017-05-22T16:16:32.373 に答える