2017-05-03 57 views
3

我有一个csv,其中包含填充了单个字典的多个列。有成千上万的行。我想把这些命令拉出来,并将列从列表中移出,然后用它们的值填充单元格,填入缺少值的NaN。所以说:从csv构建熊猫数据框,它包含多个字典列

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 

有几列像“身份证”,我想在生成的数据帧,以保持原封不动,有几列像“属性”那充满有我想吹入列的字典。为了说明,我将它们截断为上面的例子。

回答

2

来源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) 
+3

如果字典也是有效的JSON对象,那么'json.loads'大约比'ast.literal_eval'快5%。 – DyZ

+1

@DYZ,我增加了一个时间 - 对于那个DF它快了10%;) – MaxU

0

您可以嵌入使用converters选项

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 

enter image description herepd.read_csv调用字符串解析

然后我们可以merge横跨每一行的字典并转换为pd.DataFrame。我将使用上面导入的cytoolz.dicttoolz.merge作为dmerge

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 
相关问题