[英]Convert pandas column of json-like strings to DataFrame
我有以下 DataFrame,我從 API 中“按原樣”獲得:
df = pd.DataFrame({'keys': {0: "[{'contract': 'G'}, {'contract_type': 'C'}, {'strike': '560'}, {'strip': '10/1/2022'}]",
1: "[{'contract': 'G'}, {'contract_type': 'P'}, {'strike': '585'}, {'strip': '10/1/2022'}]",
2: "[{'contract': 'G'}, {'contract_type': 'C'}, {'strike': '580'}, {'strip': '10/1/2022'}]",
3: "[{'contract': 'G'}, {'contract_type': 'C'}, {'strike': '545'}, {'strip': '10/1/2022'}]",
4: "[{'contract': 'G'}, {'contract_type': 'P'}, {'strike': '555'}, {'strip': '10/1/2022'}]"},
'value': {0: 353.3, 1: 25.8, 2: 336.65, 3: 366.05, 4: 20.8}})
>>> df
keys value
0 [{'contract': 'G'}, {'contract_type': 'C'}, {'... 353.30
1 [{'contract': 'G'}, {'contract_type': 'P'}, {'... 25.80
2 [{'contract': 'G'}, {'contract_type': 'C'}, {'... 336.65
3 [{'contract': 'G'}, {'contract_type': 'C'}, {'... 366.05
4 [{'contract': 'G'}, {'contract_type': 'P'}, {'... 20.80
“鍵”列的每一行都是一個字符串(不是 JSON,因為值用單引號而不是雙引號括起來)。 例如:
>>> df.at[0, keys]
"[{'contract': 'G'}, {'contract_type': 'C'}, {'strike': '560'}, {'strip': '10/1/2022'}]"
我想將“鍵”列轉換為 DataFrame 和 append 作為新列轉換為df
。
我目前正在做:
json.loads
以讀入具有以下結構的字典列表:[{'contract': 'G'}, {'contract_type': 'C'}, {'strike': '560'}, {'strip': '10/1/2022'}]
{'contract': 'G', 'contract_type': 'C', 'strike': '560', 'strip': '10/1/2022'}
apply
到每一行並在結果上調用pd.DataFrame
構造函數。join
原來的df
在一行中,我的代碼是:
>>> df.drop("keys", axis=1).join(pd.DataFrame(df["keys"].apply(lambda x: {k: v for d in json.loads(x.replace("'","\"")) for k, v in d.items()}).tolist()))
value contract contract_type strike strip
0 353.30 G C 560 10/1/2022
1 25.80 G P 585 10/1/2022
2 336.65 G C 580 10/1/2022
3 366.05 G C 545 10/1/2022
4 20.80 G P 555 10/1/2022
我想知道是否有更好的方法來做到這一點。
您可以使用ast.literal_eval
(內置)將字典字符串轉換為實際字典,然后使用pd.json_normalize
和record_path=[[]]
將對象轉換為表格格式:
import ast
new_df = pd.json_normalize(df['keys'].apply(ast.literal_eval), record_path=[[]]).apply(lambda col: col.dropna().tolist())
Output:
>>> new_df
contract contract_type strike strip
0 G C 560 10/1/2022
1 G P 585 10/1/2022
2 G C 580 10/1/2022
3 G C 545 10/1/2022
4 G P 555 10/1/2022
另一種解決方案是使用字符串替換將單獨的字典合並為一個:
import ast
new_df = pd.DataFrame(df['keys'].str.replace("'}, {'", "', '", regex=True).apply(ast.literal_eval).str[0].tolist())
Output:
還有另一種選擇,這個使用functools.reduce
(內置):
import ast
new_df = pd.DataFrame(df['keys'].apply(ast.literal_eval).apply(lambda row: functools.reduce(lambda x, y: x | y, row)).tolist())
您可以使用ast.literal_eval
和ChainMap
集合將字典列表合並為單個字典。
from collections import ChainMap
df['keys'] = df['keys'].apply(ast.literal_eval).apply(lambda x: dict(ChainMap(*x)))
print(df)
keys value
0 {'strip': '10/1/2022', 'strike': '560', 'contr... 353.30
1 {'strip': '10/1/2022', 'strike': '585', 'contr... 25.80
2 {'strip': '10/1/2022', 'strike': '580', 'contr... 336.65
3 {'strip': '10/1/2022', 'strike': '545', 'contr... 366.05
4 {'strip': '10/1/2022', 'strike': '555', 'contr... 20.80
然后使用.apply(pd.Series)
將一列字典分解為單獨的列,並使用concat
將其與 dataframe 的 rest 合並
df_ = pd.concat([df['keys'].apply(pd.Series), df['value']], axis=1)
print(df_)
strip strike contract_type contract value
0 10/1/2022 560 C G 353.30
1 10/1/2022 585 P G 25.80
2 10/1/2022 580 C G 336.65
3 10/1/2022 545 C G 366.05
4 10/1/2022 555 P G 20.80
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.