Como json_normalizar uma coluna com NaNs
Sep 13 2020
- Esta questão é específica para colunas de dados em um
pandas.DataFrame - Esta questão depende de se os valores nas colunas são
str,dictoulisttipo. - Esta questão trata de lidar com os
NaNvalores, quandodf.dropna().reset_index(drop=True)não é uma opção válida.
Caso 1
- Com uma coluna do
strtipo, os valores na coluna devem ser convertidos emdicttipo, comast.literal_eval, antes de usar.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)
Erro:
df.col_str.apply(literal_eval) results in ValueError: malformed node or string: nan
Caso 2
- Com uma coluna do
dicttipo, usepandas.json_normalizepara converter chaves em cabeçalhos de coluna e valores em linhas
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)
Erro:
pd.json_normalize(df.col_dict) results in AttributeError: 'float' object has no attribute 'items'
Caso 3
- Em uma coluna do
strtipo, com odictinterior alist. - Para normalizar a coluna
- aplicar
literal_eval, porque explodir não funciona nostrtipo - explodir a coluna para separar o
dictspara separar linhas - normalizar a coluna
- aplicar
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)
Erro:
df.col_str.apply(literal_eval) results in ValueError: malformed node or string: nan
Respostas
2 TrentonMcKinney Sep 13 2020 at 23:59
- Conforme apontado em um comentário, sempre há a opção de:
df = df.dropna().reset_index(drop=True)- Isso é bom para os dados fictícios aqui, ou ao lidar com um dataframe onde as outras colunas não importam.
- Não é uma ótima opção para dataframes com colunas adicionais necessárias.
Caso 1
- Como a coluna contém
strtipos, preencha com'{}'(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
Caso 2
- Uma vez que a coluna contém
dicttipos, preencha com{}(não umstr) - Isso precisa ser preenchido usando uma compreensão de dicionário, uma vez
fillna({})que não funciona
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
Caso 3
- Preencha o
NaNscom'[]'(astr) - Agora
literal_evalvai funcionar .explodepode ser usado na coluna para separar osdictvalores em linhas- Agora, a
NaNsnecessidade de ser preenchido com{}(não umstr) - Então a coluna pode ser normalizada
- Para o caso em que a coluna é
listsdedicts, que não são dostrtipo, pule para.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
O que significa um erro “Não é possível encontrar o símbolo” ou “Não é possível resolver o símbolo”?
George Harrison ficou chateado por suas letras de 'Hurdy Gurdy Man' de Donovan não terem sido usadas