如何正确从Pandas字典列表列提取指定数据并避免链式赋值警告?
原始数据
我们有如下Pandas DataFrame:
import pandas as pd df = pd.DataFrame({"item_id": [1, 2, 3], "item_properties":[ [{"property_id" : 1, "property_name": "name_1", "property_value": ['property_value_1']}, {"property_id" : 2, "property_name": "name_2", "property_value": ['property_value_1']}, ], [{"property_id" : 1, "property_name": "name_1", "property_value": ['property_value_1']}, {"property_id" : 2, "property_name": "name_2", "property_value": ['property_value_1', 'property_value_2']}, ], [{"property_id" : 1, "property_name": "name_1", "property_value": ['property_value_1', 'property_value_2']}, {"property_id" : 2, "property_name": "name_2", "property_value": ['property_value_1', 'property_value_2']}, ], ] })
需求
从item_properties列的每个字典列表中,提取property_id等于2的property_value值,多个值用分号分隔,最终得到如下结构的DataFrame:
| item_id | desired_column |
|---|---|
| 1 | property_value_1 |
| 2 | property_value_1;property_value_2 |
| 3 | property_value_1;property_value_2 |
问题重现
原代码使用循环链式赋值,触发FutureWarning:
df['desired_value'] = '' for i in range(len(df)): [df['desired_value'][i]] = [d.get("property_value") for d in df['item_properties'][i] if d['property_id'] == 2] df['desired_value'] = [';'.join(map(str, l)) for l in df['desired_value']]
警告内容:
FutureWarning: ChainedAssignmentError: behaviour will change in pandas 3.0!
You are setting values through chained assignment. Currently this works in certain cases, but when using Copy-on-Write (which will become the default behaviour in pandas 3.0) this will never work to update the original DataFrame or Series, because the intermediate object on which we are setting values will behave as a copy.
A typical example is when you are setting values in a column of a DataFrame, like:df["col"][row_indexer] = value
Use df.loc[row_indexer, "col"] = values instead, to perform the assignment in a single step and ensure this keeps updating the original df.
正确实现方式
方法1:使用apply(推荐,符合Pandas风格)
通过自定义函数结合apply向量化处理,避免循环和链式赋值问题:
def get_target_value(properties_list): # 遍历字典列表,找到property_id=2的项 target_prop = next((prop for prop in properties_list if prop['property_id'] == 2), None) if target_prop: # 用分号拼接多值 return ';'.join(target_prop['property_value']) # 没有找到时返回空字符串 return '' # 生成目标列 df['desired_column'] = df['item_properties'].apply(get_target_value)
方法2:修复循环中的赋值方式
如果坚持使用循环,需改用df.loc直接赋值,避免链式索引:
df['desired_column'] = '' for idx in df.index: # 提取property_id=2的property_value value_list = next((p['property_value'] for p in df.loc[idx, 'item_properties'] if p['property_id'] == 2), []) # 用loc直接赋值 df.loc[idx, 'desired_column'] = ';'.join(value_list)
两种方法最终都能得到目标DataFrame,且不会触发链式赋值警告。
内容的提问来源于stack exchange,提问作者Artem

