从具有字典列的csv构造pandas数据框
Posted
技术标签:
【中文标题】从具有字典列的csv构造pandas数据框【英文标题】:constructing pandas dataframe from csv that has columns of dictionaries 【发布时间】:2017-10-01 20:34:06 【问题描述】:我有一个 csv,其中包含用单个 dict 填充的多列。有数千行。我想把这些字典拉出来,用它们的键制作列,并用它们的值填充单元格,在缺少值的地方填充 NaN。所以:
id attributes
0 255RSSSTCHL-QLTDGLZD-BLK "color": "Black", "hardware": "Goldtone"
1 C3ACCRDNFLP-QLTDS-S-BLK "size": "Small", "color": "Black"
变成:
id size color hardware
0 255RSSSTCHL-QLTDGLZD-BLK NaN Black Goldtone
1 C3ACCRDNFLP-QLTDS-S-BLK Small Black NaN
我希望在生成的 DataFrame 中保持几列(如“id”)不变,并且有几列(如“attributes”)填充了我想将其分解为列的字典。为了说明,我将它们截断为上面的示例。
【问题讨论】:
【参考方案1】:来源 DF:
In [172]: df
Out[172]:
id attributes attr2
0 255RSSSTCHL-QLTDGLZD-BLK "color":"Black","hardware":"Goldtone" "aaa":"aaa", "bbb":"bbb"
1 C3ACCRDNFLP-QLTDS-S-BLK "size":"Small","color":"Black" "ccc":"ccc"
解决方案 1:
import ast
attr_cols = ['attributes','attr2']
def f(df, attr_col):
return df.join(df.pop(attr_col) \
.apply(lambda x: pd.Series(ast.literal_eval(x))))
for col in attr_cols:
df = f(df, col)
解决方案 2: 感谢@DYZ for the hint:
import json
attr_cols = ['attributes','attr2']
def f(df, attr_col):
return df.join(df.pop(attr_col) \
.apply(lambda x: pd.Series(json.loads(x))))
for col in attr_cols:
df = f(df, col)
结果:
In [175]: df
Out[175]:
id color hardware size aaa bbb ccc
0 255RSSSTCHL-QLTDGLZD-BLK Black Goldtone NaN aaa bbb NaN
1 C3ACCRDNFLP-QLTDS-S-BLK Black NaN Small NaN NaN ccc
时间: 20.000 行 DF:
In [198]: df = pd.concat([df] * 10**4, ignore_index=True)
In [199]: df.shape
Out[199]: (20000, 3)
In [201]: %paste
def f_ast(df, attr_col):
return df.join(df.pop(attr_col) \
.apply(lambda x: pd.Series(ast.literal_eval(x))))
def f_json(df, attr_col):
return df.join(df.pop(attr_col) \
.apply(lambda x: pd.Series(json.loads(x))))
## -- End pasted text --
In [202]: %%timeit
...: for col in attr_cols:
...: f_ast(df.copy(), col)
...:
1 loop, best of 3: 33.1 s per loop
In [203]:
In [203]: %%timeit
...: for col in attr_cols:
...: f_json(df.copy(), col)
...:
1 loop, best of 3: 30 s per loop
In [204]: df.shape
Out[204]: (20000, 3)
【讨论】:
如果字典也是有效的 JSON 对象,那么json.loads
比 ast.literal_eval
快大约 5%。
@DYZ,我添加了一个计时 - 对于那个 DF,它快了 10% ;)【参考方案2】:
您可以使用 converters
选项将字符串解析嵌入到 pd.read_csv
调用中
import pandas as pd
from io import StringIO
from cytoolz.dicttoolz import merge as dmerge
from json import loads
txt = """id|attributes|attr2
255RSSSTCHL-QLTDGLZD-BLK|"color":"Black","hardware":"Goldtone"|"aaa":"aaa", "bbb":"bbb"
C3ACCRDNFLP-QLTDS-S-BLK|"size":"Small","color":"Black"|"ccc":"ccc""""
converters = dict(attributes=loads, attr2=loads)
df = pd.read_csv(StringIO(txt), sep='|', index_col='id', converters=converters)
df
然后我们可以merge
将每一行的字典转换为pd.DataFrame
。我将使用上面导入为dmerge
的cytoolz.dicttoolz.merge
。
pd.DataFrame(df.apply(dmerge, 1).values.tolist(), df.index).reset_index()
id aaa bbb ccc color hardware size
0 255RSSSTCHL-QLTDGLZD-BLK aaa bbb NaN Black Goldtone NaN
1 C3ACCRDNFLP-QLTDS-S-BLK NaN NaN ccc Black NaN Small
【讨论】:
以上是关于从具有字典列的csv构造pandas数据框的主要内容,如果未能解决你的问题,请参考以下文章