2016-10-06 4 views
8

データベースからデータをロードするデータフレームdfがあります。ほとんどの列はjson文字列であり、いくつかはjsonsのリストでもあります。例:あなたが見ることができるようにいくつかの列を持つpandasデータフレームをjsonとしてフラット化する方法はありますか?

id  name  columnA        columnB 
1  John  {"dist": "600", "time": "0:12.10"} [{"pos": "1st", "value": "500"},{"pos": "2nd", "value": "300"},{"pos": "3rd", "value": "200"}, {"pos": "total", "value": "1000"}] 
2  Mike  {"dist": "600"}      [{"pos": "1st", "value": "500"},{"pos": "2nd", "value": "300"},{"pos": "total", "value": "800"}] 
... 

、すべての行が列のJSON文字列の要素の数が同じではありません。私はそう

from pandas.io.json import json_normalize 
json_normalize(df) 

ようjson_normalizeを使用してみましたが、それがあるとして、idnameのような通常の列を維持されませんので、

id name columnA.dist columnA.time columnB.pos.1st columnB.pos.2nd columnB.pos.3rd  columnB.pos.total 
1  John 600   0:12.10  500    300    200     1000 
2  Mark 600   NaN   500    300    Nan     800 

のようなJSON列を平らにするために必要なもの

しかし、keyerrorにいくつかの問題があるようです。これを行う正しい方法は何ですか?

+0

列Bの値はどうなりますか?あなたも辞書を平らにしたいですか? – MMF

+0

はい。彼らは同様に平らにする必要があります。元の質問にタイプミスがあり、ここではすべてのフラット化された列に対してcolumnAを配置しましたが、今すぐ修正しました。 – sfactor

答えて

10

を使用平らにするカスタム関数を作成します。ここjson_normalize機能によって理解正しい形式でデータを取得するために、カスタム関数を使用して再びjson_normalize()を使用したソリューションです。

import ast 
from pandas.io.json import json_normalize 

def only_dict(d): 
    ''' 
    Convert json string representation of dictionary to a python dict 
    ''' 
    return ast.literal_eval(d) 

def list_of_dicts(ld): 
    ''' 
    Create a mapping of the tuples formed after 
    converting json strings of list to a python list 
    ''' 
    return dict([(list(d.values())[1], list(d.values())[0]) for d in ast.literal_eval(ld)]) 

A = json_normalize(df['columnA'].apply(only_dict).tolist()).add_prefix('columnA.') 
B = json_normalize(df['columnB'].apply(list_of_dicts).tolist()).add_prefix('columnB.pos.') 

最後に、取得するために、共通の指標にDFsに参加:

df[['id', 'name']].join([A, B]) 

Image


EDIT: -をコメントを1として@MartijnPietersにより、 json文字列をデコードする推奨方法は、を使用することですデータソースがJSONであることがわかっている場合は、ast.literal_eval()を使用する場合と比べてはるかに高速です。

+1

答えに感謝します! list_of_dicts(list(d.values())[0]、list(d.values())[1])の返されたリストです。さもなければ、これは私にとって完璧に働いた – sfactor

+1

'dictionaries'は繰り返し実行中に順序を保持しないことを知っているので、' dict'にある値はあなたのものとは逆の順序で表示されていましたので、スライス表記法をあなたとは違って使う必要がありました。あなたが言及したのと同じ順序で表示されている場合は、先に進むか、[Ordered Dict]を使用することもできます(https://docs.python.org/3/library/collections.html# collections.OrderedDict)を使用して注文を保存します。 –

+0

'json.loads()'を使用する必要があるときに(slow!) 'ast.literal_eval()'を呼び出すのはなぜですか?後者は正しいJSONデータを処理します。以前の* Python *構文はBMP以外のブール値、ヌル、ユニコードデータとは大きく異なります。 –

4

columnBが、その後pd.concat

def flatten(js): 
    return pd.DataFrame(js).set_index('pos').squeeze() 

pd.concat([df.drop(['columnA', 'columnB'], axis=1), 
      df.columnA.apply(pd.Series), 
      df.columnB.apply(flatten)], axis=1) 

enter image description here

関連する問題