Как json_normalize столбец с NaN
Sep 13 2020
- Этот вопрос относится к столбцам данных в
pandas.DataFrame - Этот вопрос зависит от того, если значения в столбцах
str,dictилиlistтип. - Этот вопрос касается работы со
NaNзначениями, когдаdf.dropna().reset_index(drop=True)это недопустимый вариант.
Случай 1
- Для столбца
strтипа значения в столбце должны быть преобразованы вdictтип, сast.literal_eval, перед использованием.json_normalize.
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типа с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
Ответы
2 TrentonMcKinney Sep 13 2020 at 23:59
- Как указано в комментарии, всегда есть возможность:
df = df.dropna().reset_index(drop=True)- Это нормально для фиктивных данных здесь или при работе с фреймом данных, где другие столбцы не имеют значения.
- Не лучший вариант для фреймов данных с дополнительными столбцами, которые необходимы.
Случай 1
- Поскольку столбец содержит
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
Случай 2
- Поскольку столбец содержит
dictтипы, заполните его{}(неstr) - Это необходимо заполнить с помощью dict-computing, поскольку
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
- Наполните
NaNsс'[]'(аstr) - Сейчас
literal_evalбудет работать .explodeможет использоваться в столбце для разделенияdictзначений на строки- Теперь
NaNsнужно заполнить{}(а неstr) - Тогда столбец можно нормализовать
- Для случая , когда колонна
listsизdicts, которые не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