【问题标题】:How to json_normalize a column with NaNs如何使用 NaN 对列进行 json_normalize
【发布时间】:2020-12-31 17:20:57
【问题描述】:
  • 此问题特定于pandas.DataFrame 中的数据列
  • 这个问题取决于列中的值是strdict 还是list 类型。
  • df.dropna().reset_index(drop=True) 不是有效选项时,此问题涉及处理NaN 值。

案例一

  • 对于str类型的列,在使用.json_normalize之前,必须将该列中的值转换为dict类型,使用ast.literal_eval
import numpy as np
import pandas as pd
from ast import literal_eval

df = pd.DataFrame({'col_str': ['{"a": "46", "b": "3", "c": "12"}', '{"b": "2", "c": "7"}', '{"c": "11"}', np.NaN]})

                            col_str
0  {"a": "46", "b": "3", "c": "12"}
1              {"b": "2", "c": "7"}
2                       {"c": "11"}
3                               NaN

type(df.iloc[0, 0])
[out]: str

df.col_str.apply(literal_eval)

错误:

df.col_str.apply(literal_eval) results in ValueError: malformed node or string: nan

案例 2

  • 对于dict 类型的列,使用pandas.json_normalize 将键转换为列标题,将值转换为行
df = pd.DataFrame({'col_dict': [{"a": "46", "b": "3", "c": "12"}, {"b": "2", "c": "7"}, {"c": "11"}, np.NaN]})

                           col_dict
0  {'a': '46', 'b': '3', 'c': '12'}
1              {'b': '2', 'c': '7'}
2                       {'c': '11'}
3                               NaN

type(df.iloc[0, 0])
[out]: dict

pd.json_normalize(df.col_dict)

错误:

pd.json_normalize(df.col_dict) results in AttributeError: 'float' object has no attribute 'items'

案例 3

  • str 类型的列中,dictlist 内。
  • 标准化列
    • 应用literal_eval,因为explode 不适用于str 类型
    • 分解列以分隔dicts 以分隔行
    • 规范化列
df = pd.DataFrame({'col_str': ['[{"a": "46", "b": "3", "c": "12"}, {"b": "2", "c": "7"}]', '[{"b": "2", "c": "7"}, {"c": "11"}]', np.nan]})

                                                    col_str
0  [{"a": "46", "b": "3", "c": "12"}, {"b": "2", "c": "7"}]
1                       [{"b": "2", "c": "7"}, {"c": "11"}]
2                                                       NaN

type(df.iloc[0, 0])
[out]: str
    
df.col_str.apply(literal_eval)

错误:

df.col_str.apply(literal_eval) results in ValueError: malformed node or string: nan

【问题讨论】:

    标签: python json pandas dictionary json-normalize


    【解决方案1】:
    • 始终可以选择:
      • df = df.dropna().reset_index(drop=True)
      • 这对于此处的虚拟数据或在处理其他列无关紧要的数据框时很好。
      • 对于需要额外列的数据框来说不是一个很好的选择。

    案例一

    • 由于该列包含str 类型,因此用'{}' 填充(一个str
    import numpy as np
    import pandas as pd
    from ast import literal_eval
    
    df = pd.DataFrame({'col_str': ['{"a": "46", "b": "3", "c": "12"}', '{"b": "2", "c": "7"}', '{"c": "11"}', np.NaN]})
    
                                col_str
    0  {"a": "46", "b": "3", "c": "12"}
    1              {"b": "2", "c": "7"}
    2                       {"c": "11"}
    3                               NaN
    
    type(df.iloc[0, 0])
    [out]: str
    
    # fillna
    df.col_str = df.col_str.fillna('{}')
    
    # convert the column to dicts
    df.col_str = df.col_str.apply(literal_eval)
    
    # use json_normalize
    df = df.join(pd.json_normalize(df.col_str)).drop(columns=['col_str'])
    
    # display(df)
         a    b    c
    0   46    3   12
    1  NaN    2    7
    2  NaN  NaN   11
    3  NaN  NaN  NaN
    

    案例 2

    至少从 pandas 1.3.4 开始,pd.json_normalize(df.col_dict) 可以正常工作,至少对于这个简单的示例而言。


    • 由于该列包含dict 类型,因此使用{} 填充(不是str
    • 这需要使用 dict-comprehension 来填充,因为 fillna({}) 不起作用
    df = pd.DataFrame({'col_dict': [{"a": "46", "b": "3", "c": "12"}, {"b": "2", "c": "7"}, {"c": "11"}, np.NaN]})
    
                               col_dict
    0  {'a': '46', 'b': '3', 'c': '12'}
    1              {'b': '2', 'c': '7'}
    2                       {'c': '11'}
    3                               NaN
    
    type(df.iloc[0, 0])
    [out]: dict
        
    # fillna
    df.col_dict = df.col_dict.fillna({i: {} for i in df.index})
    
    # use json_normalize
    df = df.join(pd.json_normalize(df.col_dict)).drop(columns=['col_dict'])
    
    # display(df)
         a    b    c
    0   46    3   12
    1  NaN    2    7
    2  NaN  NaN   11
    3  NaN  NaN  NaN
    

    案例 3

    1. '[]'str)填充NaNs
    2. 现在literal_eval 可以工作了
    3. 可以在列上使用.explodedict 值分隔为行
    4. 现在NaNs 需要填写{}(不是str
    5. 然后可以对列进行归一化
    • 对于列为listsdicts 且不是str 类型的情况,请跳至.explode
    df = pd.DataFrame({'col_str': ['[{"a": "46", "b": "3", "c": "12"}, {"b": "2", "c": "7"}]', '[{"b": "2", "c": "7"}, {"c": "11"}]', np.nan]})
    
                                                        col_str
    0  [{"a": "46", "b": "3", "c": "12"}, {"b": "2", "c": "7"}]
    1                       [{"b": "2", "c": "7"}, {"c": "11"}]
    2                                                       NaN
    
    type(df.iloc[0, 0])
    [out]: str
        
    # fillna
    df.col_str = df.col_str.fillna('[]')
    
    # literal_eval
    df.col_str = df.col_str.apply(literal_eval)
    
    # explode
    df = df.explode('col_str').reset_index(drop=True)
    
    # fillna again
    df.col_str = df.col_str.fillna({i: {} for i in df.index})
    
    # use json_normalize
    df = df.join(pd.json_normalize(df.col_str)).drop(columns=['col_str'])
    
    # display(df)
         a    b    c
    0   46    3   12
    1  NaN    2    7
    2  NaN    2    7
    3  NaN  NaN   11
    4  NaN  NaN  NaN
    

    【讨论】:

      猜你喜欢
      • 2020-12-27
      • 2018-11-09
      • 2018-01-05
      • 2019-12-17
      • 2021-03-14
      • 2020-03-26
      • 2014-02-06
      • 2015-04-06
      相关资源
      最近更新 更多