【问题标题】:constructing pandas dataframe from csv that has columns of dictionaries从具有字典列的csv构造pandas数据框
【发布时间】: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”)填充了我想将其分解为列的字典。为了说明,我将它们截断为上面的示例。

【问题讨论】:

    标签: python csv pandas dictionary


    【解决方案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.loadsast.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。我将使用上面导入为dmergecytoolz.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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-02
      • 1970-01-01
      • 1970-01-01
      • 2019-03-30
      • 2023-01-21
      • 1970-01-01
      • 1970-01-01
      • 2023-02-05
      相关资源
      最近更新 更多