2012-07-19 18 views
10

この質問は、非周期的な同種または異種のデータ構造のコレクションをデータフレームに変換する一般的なメカニズムに関するものです。これは、多くのJSON文書や辞書の配列である大きなJSON文書の取り込みを処理する場合に特に便利です。R:JSONからdata.frameへの一般的なフラット化

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

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

完全に均質でない可能性があるこれらのデータ構造の集合を有する場合、データフレームへの平坦化を成功させる鍵は、すべての可能なデータフレーム列の名前を発見することである/個別に平坦化されたデータ構造内の値の名前。

これは一般的なパターンのようで、誰かが既にRのためにこれを構築しているのかどうか疑問に思っています。私はそれを構築しますが、Rのユニークな約束事に基づくデータ構造を考えると、ヒープスラッシングを最小限に抑える実装アプローチ。

+0

Huh?私にとって英語が多すぎる(とにかく)理解する。いくつかの(恐らく)遅いコードをいくつか再現可能な入力に提供して、あなたが望む出力を生成し、そこから行くことを提案してください。おそらく、私はJSONを知らないだけかもしれません。新しいRセッションにペースト可能なものを提供して、どこかのJSONデータをダウンロードして質問を示すことができますか? [素晴らしい再現可能な例を作る方法](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) –

答えて

7

こんにちは@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) 
} 

getnamesがAnnotationDbiから構成されている::: make.name.tree)

flattenHow to flatten a list to a list without coercion?ここでの議論から構成されています)簡単な例として

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) 

UPDATE jsonliteパッケージは、具体的にはJSONとの間の変換をするように設計RJSONIOのフォークである.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" 
+0

有望そうです。あなたは後ろにある '.1'sを取り除くことをどのように提案しますか? – Sim

+0

'names(flattened_structure)'を再割り当てできるはずですか? – Sim

+0

私は同意します。今すぐクリーナー。私の質問は、特に、辞書/ハッシュの配列である大きなJSON文書をdata.frameに変換することでした。そのためには、すべてのフラット・リスト名の和集合として列セットを構築する必要があります。 – Sim

4

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

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

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

例:

(my_data <- list(x = list('1' = 1, '2' = list(y = 2)))) 
unlist(my_data) 
+0

downvoteとは何ですか? 'unlist'は@Simが望む"汎用データ構造の平坦化ユーティリティ "と全く同じように見えます。実際、@ttmaccerにリンクされている同様の質問には、 'unlist'を広範に利用した回答が含まれています。 –

+0

@ttmaccer:うん、あなたはRで両方の方法を取ることはできません。単一のデータ型を持つフラット(ベクトル)データ構造または混合型を持つネスト(リスト)構造のいずれかです。 RにはJSONが必要なものに変換可能なツールが十分にあると思います。 –

+0

@RichieCotton @ttmaccer私は、 'unlist'は一般的な方法では動作しないことに同意します。これが最高のRであれば、私は先に進んで、私が他の言語で使用した再帰的な降下フラットナーを書くでしょう。 – Sim

1

末尾除去する

素朴な方法とデータフレームが簡単になります。あなたは例のjsonのデータを提供していませんが、これはあなたが探しているかもしれないと思います。このblog postまたはthe vignetteをご覧ください。

0

flattenとgetnames関数の優れた答えです。 JSON文字列のベクトルからdata.frameに移動するのに必要なすべてのオプションを調べるのに数分かかったので、ここでそれを記録すると思いました。 jsonvecがJSON文字列のベクトルであるとします。以下は、stringごとに1つの行が存在するdata.frame(data.table)を構築し、各列はJSONツリーの異なる葉ノードに対応しています。特定のリーフノードを欠いている文字列はすべて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) 
関連する問題