Pandas遍历行计算赋值失效问题及修复求助
问题描述
- 需求:遍历DataFrame的每一行,当
source字段值为HR(对应类别“HR contacts”)时,若total number≤500则保留全部数值,否则保留500并计算剩余数值。 - 问题:使用
iterrows()循环赋值后,新增的keep #和rest #列仍全部为NaN;改用iloc循环的方式也未解决。
用户提供的代码片段:
第一段代码:
cntByUserNm['keep #'] = np.nan cntByUserNm['rest #'] = np.nan for index, row in cntByUserNm.iterrows(): print(row['Owner Name'], row['source']) if row['source'] == 'HR': if row['total number'] <= 500: row['keep #'] = row['total number'] row['rest #'] = 0 else: row['keep #'] = 500 row['rest #'] = row['total number'] - 500
第二段尝试代码:
for i in range(0, len(cntByUserNm)): print(cntByUserNm.iloc[i]['Owner Name'], cntByUserNm.iloc[i]['blizday source']) if cntByUserNm.iloc[i]['blizday source'] == mainCat: if cntByUserNm.iloc[i][befCnt] <= destiNum: cntByUserNm.iloc[i]['keep #'] = cntByUserNm.iloc[i][befCnt] cntByUserNm.iloc[i]['rest #'] = 0 else: cntByUserNm.iloc[i]['keep #'] = destiNum cntByUserNm.iloc[i]['rest #'] = cntByUserNm.iloc[i][befCnt] - destiNum
修复方法
问题根源
iterrows()返回的row是原DataFrame的副本,修改副本不会同步到原DataFrame,因此赋值无效。iloc[i]['列名']属于链式索引,可能返回原数据的视图或副本,直接赋值可能无法修改原DataFrame,还会触发SettingWithCopyWarning。
方法1:修正iterrows()循环赋值
通过loc[index, 列名]直接修改原DataFrame,避免操作副本:
import numpy as np cntByUserNm['keep #'] = np.nan cntByUserNm['rest #'] = np.nan for index, row in cntByUserNm.iterrows(): print(row['Owner Name'], row['source']) if row['source'] == 'HR': if row['total number'] <= 500: cntByUserNm.loc[index, 'keep #'] = row['total number'] cntByUserNm.loc[index, 'rest #'] = 0 else: cntByUserNm.loc[index, 'keep #'] = 500 cntByUserNm.loc[index, 'rest #'] = row['total number'] - 500
方法2:修正iloc循环赋值
使用iloc[i, 列索引]的方式直接定位修改,避免链式索引问题:
for i in range(len(cntByUserNm)): print(cntByUserNm.iloc[i]['Owner Name'], cntByUserNm.iloc[i]['blizday source']) if cntByUserNm.iloc[i]['blizday source'] == mainCat: # 获取列的索引位置 keep_col_idx = cntByUserNm.columns.get_loc('keep #') rest_col_idx = cntByUserNm.columns.get_loc('rest #') current_val = cntByUserNm.iloc[i][befCnt] if current_val <= destiNum: cntByUserNm.iloc[i, keep_col_idx] = current_val cntByUserNm.iloc[i, rest_col_idx] = 0 else: cntByUserNm.iloc[i, keep_col_idx] = destiNum cntByUserNm.iloc[i, rest_col_idx] = current_val - destiNum
方法3:推荐使用向量化操作(高效无循环)
Pandas的向量化操作比循环效率高得多,尤其适合大数据量场景,同时避免副本/视图问题:
import numpy as np # 初始化列 cntByUserNm['keep #'] = np.nan cntByUserNm['rest #'] = np.nan # 筛选source为HR的行 hr_mask = cntByUserNm['source'] == 'HR' # 处理total number ≤500的情况 low_val_mask = hr_mask & (cntByUserNm['total number'] <= 500) cntByUserNm.loc[low_val_mask, 'keep #'] = cntByUserNm.loc[low_val_mask, 'total number'] cntByUserNm.loc[low_val_mask, 'rest #'] = 0 # 处理total number >500的情况 high_val_mask = hr_mask & (cntByUserNm['total number'] > 500) cntByUserNm.loc[high_val_mask, 'keep #'] = 500 cntByUserNm.loc[high_val_mask, 'rest #'] = cntByUserNm.loc[high_val_mask, 'total number'] - 500
内容的提问来源于stack exchange,提问作者Binnnnn5
相关产品推荐
相关产品推荐

