วิธี json_normalize คอลัมน์ด้วย NaNs
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อยู่ภายใน alist. - เพื่อทำให้คอลัมน์เป็นปกติ
- นำไปใช้
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ประเภทจึงเติมด้วย{}(ไม่ใช่ astr) - สิ่งนี้จำเป็นต้องกรอกโดยใช้การเข้าใจตามคำบอกเนื่องจาก
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ด้วย'[]'(astr) - ตอนนี้
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