Cách json_normalize một cột bằng NaNs
Sep 13 2020
- Câu hỏi này dành riêng cho các cột dữ liệu trong
pandas.DataFrame - Câu hỏi này phụ thuộc vào nếu các giá trị trong cột
str,dicthoặclistloại. - Câu hỏi này đề cập đến việc xử lý các
NaNgiá trị, khi nàodf.dropna().reset_index(drop=True)không phải là một tùy chọn hợp lệ.
Trường hợp 1
- Với một cột
strkiểu, các giá trị trong cột phải được chuyển đổi thànhdictkiểu, vớiast.literal_eval, trước khi sử dụng.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)
Lỗi:
df.col_str.apply(literal_eval) results in ValueError: malformed node or string: nan
Trường hợp 2
- Với loại cột
dict, hãy sử dụngpandas.json_normalizeđể chuyển đổi khóa thành tiêu đề cột và giá trị thành hàng
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)
Lỗi:
pd.json_normalize(df.col_dict) results in AttributeError: 'float' object has no attribute 'items'
Trường hợp 3
- Trong một cột
strloại, vớidictbên trong alist. - Để chuẩn hóa cột
- áp dụng
literal_eval, vì phát nổ không hoạt động trênstrloại - nổ cột để tách các
dictshàng riêng biệt - bình thường hóa cột
- áp dụng
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)
Lỗi:
df.col_str.apply(literal_eval) results in ValueError: malformed node or string: nan
Trả lời
2 TrentonMcKinney Sep 13 2020 at 23:59
- Như đã chỉ ra trong một nhận xét, luôn có tùy chọn để:
df = df.dropna().reset_index(drop=True)- Điều đó tốt cho dữ liệu giả ở đây hoặc khi xử lý khung dữ liệu trong đó các cột khác không quan trọng.
- Không phải là một lựa chọn tuyệt vời cho khung dữ liệu với các cột bổ sung được yêu cầu.
Trường hợp 1
- Vì cột chứa
strcác loại, điền vào bằng'{}'(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
Trường hợp 2
- Vì cột chứa
dictcác loại, nên điền vào{}(không phải astr) - Điều này cần được điền bằng cách sử dụng đọc hiểu chính tả, vì
fillna({})nó không hoạt động
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
Trường hợp 3
- Điền vào
NaNsvới'[]'(astr) - Bây giờ
literal_evalsẽ hoạt động .explodecó thể được sử dụng trên cột để tách cácdictgiá trị thành các hàng- Bây giờ
NaNsnhu cầu được lấp đầy bằng{}(không phải astr) - Sau đó, cột có thể được chuẩn hóa
- Đối với trường hợp cột là
listscủadicts, khôngstrthuộc loại, hãy bỏ qua.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