![](/img/trans.png)
[英]How to make a pandas dataframe with nested columns from a list of nested dicts
[英]How to flatten a list of dicts from a Pandas DataFrame into several columns?
我有一個如下所示的 Pandas 數據框:
User | Query| Filters
-----------------------------------------------------------------------------------------
1 | abc | [{u'Op': u'and', u'Type': u'date', u'Val': u'1992'},{u'Op': u'and', u'Type': u'sex', u'Val': u'F'}]
1 | efg | [{u'Op': u'and', u'Type': u'date', u'Val': u'2000'},{u'Op': u'and', u'Type': u'col', u'Val': u'Blue'}]
1 | fgs | [{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'col', u'Val': u'Red'}]
2 | hij | [{u'Op': u'and', u'Type': u'date', u'Val': u'2002'}]
2 | dcv | [{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'sex', u'Val': u'F'}]
2 | tyu | [{u'Op': u'and', u'Type': u'date', u'Val': u'1999'},{u'Op': u'and', u'Type': u'col', u'Val': u'Yellow'}]
3 | jhg | [{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'sex', u'Val': u'M'}]
4 | mlh | [{u'Op': u'and', u'Type': u'date', u'Val': u'2001'}]
我期望的結果:
User| Query | date | sex | col
--------------------------------
1 | abc | 1992 | F |
1 | efg | 2000 | | Blue
1 | fgs | 2001 | | Red
2 | hij | 2002 | |
2 | dcv | 2001 | F |
2 | tyu | 1999 | | Yellow
3 | jhg | 2001 | |
4 | mlh | 2001 | H |
我在 python 2.7 中使用 pandas 0.21.0。
示例數據:
df = pd.DataFrame([{'user': 1,'query': 'abc', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'1992'},{u'Op': u'and', u'Type': u'sex', u'Val': u'F'}]},
{'user': 1,'query': 'efg', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2000'},{u'Op': u'and', u'Type': u'col', u'Val': u'Blue'}]},
{'user': 1,'query': 'fgs', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'col', u'Val': u'Red'}]},
{'user': 2 ,'query': 'hij', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2002'}]},
{'user': 2 ,'query': 'dcv', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'sex', u'Val': u'F'}]},
{'user': 2 ,'query': 'tyu', 'Filters':[{u'Op': u'and', u'Type': u'date', u'Val': u'1999'},{u'Op': u'and', u'Type': u'col', u'Val': u'Yellow'}]},
{'user': 3 ,'query': 'jhg', 'Filters':[{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'sex', u'Val': u'M'}]},
{'user': 4 ,'query': 'mlh', 'Filters':[{u'Op': u'and', u'Type': u'date', u'Val': u'2001'}]},
])
我嘗試了很多解決方案:
任何建議將不勝感激!
假設您已經按照 MCWE 中的定義導入了數據:
data = [{'user': 1,'query': 'abc', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'1992'},{u'Op': u'and', u'Type': u'sex', u'Val': u'F'}]},
{'user': 1,'query': 'efg', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2000'},{u'Op': u'and', u'Type': u'col', u'Val': u'Blue'}]},
{'user': 1,'query': 'fgs', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'col', u'Val': u'Red'}]},
{'user': 2 ,'query': 'hij', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2002'}]},
{'user': 2 ,'query': 'dcv', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'sex', u'Val': u'F'}]},
{'user': 2 ,'query': 'tyu', 'Filters':[{u'Op': u'and', u'Type': u'date', u'Val': u'1999'},{u'Op': u'and', u'Type': u'col', u'Val': u'Yellow'}]},
{'user': 3 ,'query': 'jhg', 'Filters':[{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'sex', u'Val': u'M'}]},
{'user': 4 ,'query': 'mlh', 'Filters':[{u'Op': u'and', u'Type': u'date', u'Val': u'2001'}]},
]
然后,您正在尋找用於數據規范化的 Pandas json_normalize方法:
from pandas.io.json import json_normalize
df = json_normalize(data, 'Filters', ['query', 'user'])
它返回一個規范化的 DataFrame 版本,其中您的json
列擴展為同名類型的列:
Op Type Val user query
0 and date 1992 1 abc
1 and sex F 1 abc
2 and date 2000 1 efg
3 and col Blue 1 efg
4 and date 2001 1 fgs
5 and col Red 1 fgs
6 and date 2002 2 hij
7 and date 2001 2 dcv
8 and sex F 2 dcv
9 and date 1999 2 tyu
10 and col Yellow 2 tyu
11 and date 2001 3 jhg
12 and sex M 3 jhg
13 and date 2001 4 mlh
現在,您將旋轉DataFrame 以將 Type 模式轉換為列:
df = df.pivot_table(index=['user', 'query', 'Op'], columns='Type', aggfunc='first')
它導致:
Val
Type col date sex
user query Op
1 abc and None 1992 F
efg and Blue 2000 None
fgs and Red 2001 None
2 dcv and None 2001 F
hij and None 2002 None
tyu and Yellow 1999 None
3 jhg and None 2001 M
4 mlh and None 2001 None
最后,如果它們打擾您,您可以清理和重置索引:
df.columns = df.columns.droplevel(0)
df.reset_index(inplace=True)
它返回您請求的 MCVE 輸出:
Type user query Op col date sex
0 1 abc and None 1992 F
1 1 efg and Blue 2000 None
2 1 fgs and Red 2001 None
3 2 dcv and None 2001 F
4 2 hij and None 2002 None
5 2 tyu and Yellow 1999 None
6 3 jhg and None 2001 M
7 4 mlh and None 2001 None
不列
在這個最終的 DataFrame 中,第一列似乎被稱為Type
,但事實並非如此。 它是一個沒有名稱的整數索引:
df.index
RangeIndex(start=0, stop=8, step=1)
列索引稱為Type
,它不包含任何稱為Type
模態(因此沒有具有此名稱的列)。
df.columns
Index(['user', 'query', 'Op', 'col', 'date', 'sex'], dtype='object', name='Type')
這就是您不能刪除列Type
(在pivot_table
使用的pivot_table
)的原因,因為它不存在。
如果你想刪除這個假列,你需要為行創建一個新的索引:
df.set_index(['user', 'query'], inplace=True)
如果列索引名稱困擾您,您可以重置它:
df.columns.name = None
它導致:
Op col date sex
user query
1 abc and None 1992 F
efg and Blue 2000 None
fgs and Red 2001 None
2 dcv and None 2001 F
hij and None 2002 None
tyu and Yellow 1999 None
3 jhg and None 2001 M
4 mlh and None 2001 None
創建新索引時始終檢查它的唯一性是一種很好的做法:
df.index.is_unique
True
來自文件的數據
如果您的數據在文件中,您應該首先使用 PSL json
模塊將其導入到一個變量中:
import json
with open(path) as file:
data = json.load(file)
這將解決問題,然后回到我的答案的開頭。
import pandas as pd
df = pd.DataFrame([{'user': 1,'query': 'abc', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'1992'},{u'Op': u'and', u'Type': u'sex', u'Val': u'F'}]},
{'user': 1,'query': 'efg', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2000'},{u'Op': u'and', u'Type': u'col', u'Val': u'Blue'}]},
{'user': 1,'query': 'fgs', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'col', u'Val': u'Red'}]},
{'user': 2 ,'query': 'hij', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2002'}]},
{'user': 2 ,'query': 'dcv', 'Filters': [{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'sex', u'Val': u'F'}]},
{'user': 2 ,'query': 'tyu', 'Filters':[{u'Op': u'and', u'Type': u'date', u'Val': u'1999'},{u'Op': u'and', u'Type': u'col', u'Val': u'Yellow'}]},
{'user': 3 ,'query': 'jhg', 'Filters':[{u'Op': u'and', u'Type': u'date', u'Val': u'2001'},{u'Op': u'and', u'Type': u'sex', u'Val': u'M'}]},
{'user': 4 ,'query': 'mlh', 'Filters':[{u'Op': u'and', u'Type': u'date', u'Val': u'2001'}]},
])
def func(x):
date = x[0]['Val']
sex = ''
col = ''
if len(x) > 1:
if x[1]['Val'] in ['F','M']:
sex = x[1]['Val']
else:
col = x[1]['Val']
return pd.Series([date,sex,col])
df[['date','sex','color']] = df['Filters'].apply(func)
df
輸出(未顯示過濾器):
query user date sex color
0 abc 1 1992 F
1 efg 1 2000 Blue
2 fgs 1 2001 Red
3 hij 2 2002
4 dcv 2 2001 F
5 tyu 2 1999 Yellow
6 jhg 3 2001 M
7 mlh 4 2001
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.