如何将 Pandas DataFrame 中的字典列表展平为几列?
Posted
技术标签:
【中文标题】如何将 Pandas DataFrame 中的字典列表展平为几列?【英文标题】:How to flatten a list of dicts from a Pandas DataFrame into several columns? 【发布时间】:2018-04-30 01:44:26 【问题描述】:我有一个看起来像这样的 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 |
我将 pandas 0.21.0 与 python 2.7 一起使用。
示例数据:
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'],
])
我尝试了很多解决方案:
Handling of nested JSON records Pandas read nested json任何建议将不胜感激!
【问题讨论】:
【参考方案1】:假设您已经按照 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
现在,您将 pivot 您的 DataFrame 将类型模式转换为列:
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
中使用的列),因为它不存在。
如果你想删除这个假列,你需要为行创建一个新的索引:
df.set_index(['user', 'query'], inplace=True)
如果 Column index Name 困扰你,你可以重置它:
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)
这可以解决问题,然后回到我的答案的开头。
【讨论】:
@landercy 认为 DataFrame 是读取 json 文件的结果:df = pd.read_json(path,lines='True') 我收到此错误:TypeError: string indices must be integers @Omar14,我已经用你的 MCWE 数据建立了我的答案,如果有问题,应该在导入阶段发生。您可以使用 PSLjson.loads
来馈送 json_normalize
。
@Omar14 添加了代码来完成您的请求。如果适合您,请标记为答案。
@jlandercy 你知道如何删除类型列吗?我试过 df.drop(columns=['Type'])【参考方案2】:
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
【讨论】:
以上是关于如何将 Pandas DataFrame 中的字典列表展平为几列?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Pandas 系列中的多个字典键转换为 DataFrame 中的列?
将字典嵌套在另一个字典中,按 Pandas Dataframe 中的值分组
将 pandas.DataFrame 转换为 Python 中的字典列表