如何使用 NaN 对列进行 json_normalize

Posted

技术标签:

【中文标题】如何使用 NaN 对列进行 json_normalize【英文标题】:How to json_normalize a column with NaNs 【发布时间】: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

【问题讨论】:

【参考方案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

    '[]'str)填充NaNs 现在literal_eval 可以工作了 可以在列上使用.explodedict 值分隔为行 现在NaNs 需要填写(不是str) 然后可以对列进行归一化
对于列为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

【讨论】:

以上是关于如何使用 NaN 对列进行 json_normalize的主要内容,如果未能解决你的问题,请参考以下文章

如何在熊猫中为每个组做前向填充

如何使用 json_normalize 规范化嵌套的 json

sql - 如何使用单独的逗号对列进行分组

pandas 如何使用 groupby 在标签中按日期对列进行分组?

如何在 Handsontable 中使用自定义渲染器对列进行排序?

当我从 ajax 发送数据时,如何在 jQuery 中使用 DataTables 对列进行排序?