如何 json_normalize 包含 NaN 的列
How to json_normalize a column with NaNs
- 此问题特定于
pandas.DataFrame
中的数据列
- 这个问题取决于列中的值是
str
、dict
还是 list
类型。
- 此问题解决了在
df.dropna().reset_index(drop=True)
不是有效选项时处理 NaN
值的问题。
案例一
- 对于
str
类型的列,在使用.json_normalize
.[=62之前,必须将列中的值转换为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
案例二
- 对于
dict
类型的列,使用 pandas.json_normalize
将键转换为列 headers,将值转换为行
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'
案例三
- 在
str
类型的列中,dict
在list
内。
- 对列进行归一化
- 应用
literal_eval
,因为爆炸不适用于 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
- 始终可以选择:
df = df.dropna().reset_index(drop=True)
- 这对于这里的虚拟数据来说很好,或者在处理其他列无关紧要的数据帧时。
- 对于需要额外列的数据框来说不是一个很好的选择。
案例一
- 由于该列包含
str
类型,因此填充 '{}'
(a 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
案例二
至少从 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
案例三
- 用
'[]'
填充NaNs
(一个str
)
- 现在
literal_eval
可以工作了
.explode
可用于列以将 dict
值分隔到行
- 现在
NaNs
需要填充 {}
(不是 str
)
- 然后列可以归一化
- 如果列是
dicts
的 lists
,不是 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
- 此问题特定于
pandas.DataFrame
中的数据列
- 这个问题取决于列中的值是
str
、dict
还是list
类型。 - 此问题解决了在
df.dropna().reset_index(drop=True)
不是有效选项时处理NaN
值的问题。
案例一
- 对于
str
类型的列,在使用.json_normalize
.[=62之前,必须将列中的值转换为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
案例二
- 对于
dict
类型的列,使用pandas.json_normalize
将键转换为列 headers,将值转换为行
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'
案例三
- 在
str
类型的列中,dict
在list
内。 - 对列进行归一化
- 应用
literal_eval
,因为爆炸不适用于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
- 始终可以选择:
df = df.dropna().reset_index(drop=True)
- 这对于这里的虚拟数据来说很好,或者在处理其他列无关紧要的数据帧时。
- 对于需要额外列的数据框来说不是一个很好的选择。
案例一
- 由于该列包含
str
类型,因此填充'{}'
(astr
)
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
案例二
至少从 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
案例三
- 用
'[]'
填充NaNs
(一个str
) - 现在
literal_eval
可以工作了 .explode
可用于列以将dict
值分隔到行- 现在
NaNs
需要填充{}
(不是str
) - 然后列可以归一化
- 如果列是
dicts
的lists
,不是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