Pandas处理DataFrame:赋值后无法移除指定行的技术问题
问题描述
需要对一组包含测量数据的DataFrame执行以下预处理步骤:
- 删除不需要的列;
- 为每行逐步赋值,遇到值
11111111时,切换为samples列表中的下一个值; - 删除NaN列和包含
11111111的行。
现有代码中前两步正常执行,但最后无法移除包含11111111的行,最终结果仍保留了这些行。
原实现代码:
frames = [df_JSON, df_CBOR, df_mSEED, df_bSEED] samples=[250, 500, 1000, 2000, 4000, 8000, 16000, 32000, 64000] for df in frames: df.drop(df.columns[5:], axis=1, inplace=True) # 删除不需要的列 df['samples']='' # 创建新列用于存放赋值结果 counter=0 for index, row in df.iterrows(): if row['tg']!=11111111: # 未遇到11111111时,使用当前sample值 row['samples']=samples[counter] df.iloc[index]=row else: counter+=1 # 遇到11111111时,切换到下一个sample值 df.dropna(axis=1, inplace=True) # 删除NaN列 rslt_df=df.loc[df['tg']!=11111111] # 筛选不含11111111的行 df=rslt_df # 尝试覆盖原DataFrame
补充测试代码:
xls = pd.ExcelFile('testdata.xlsx') df_JSON = pd.read_excel(xls, 1) df_CBOR = pd.read_excel(xls, 2) df_mSEED = pd.read_excel(xls, 3) df_bSEED = pd.read_excel(xls, 4) frames = [df_JSON, df_CBOR, df_mSEED, df_bSEED] samples=[250, 500, 1000, 2000, 4000, 8000, 16000, 32000, 64000] for df in frames: df.drop(df.columns[5:], axis=1, inplace=True) # 删除不需要的列 df['samples']='' # 创建新列用于存放赋值结果 counter=0 for index, row in df.iterrows(): if row['tg']!=11111111: # 未遇到11111111时,使用当前sample值 row['samples']=samples[counter] df.iloc[index]=row else: counter+=1 # 遇到11111111时,切换到下一个sample值 df.dropna(axis=1, inplace=True) # 删除NaN列 rslt_df=df.loc[df['tg']!=11111111] # 筛选不含11111111的行 df=rslt_df # 尝试覆盖原DataFrame
问题原因与解决方案
核心问题
循环中df = rslt_df仅修改了循环变量的临时引用,并未更新frames列表中原有的DataFrame对象。Python列表迭代时,循环变量是原对象的副本,重新赋值不会改变列表内的元素。此外,iterrows()遍历赋值效率较低,适合改用向量化操作优化。
优化后的代码
import pandas as pd xls = pd.ExcelFile('testdata.xlsx') df_JSON = pd.read_excel(xls, 1) df_CBOR = pd.read_excel(xls, 2) df_mSEED = pd.read_excel(xls, 3) df_bSEED = pd.read_excel(xls, 4) frames = [df_JSON, df_CBOR, df_mSEED, df_bSEED] samples = [250, 500, 1000, 2000, 4000, 8000, 16000, 32000, 64000] # 通过索引遍历列表,直接修改原列表中的DataFrame for i in range(len(frames)): df = frames[i] # 1. 保留前5列,删除其余列 df = df.iloc[:, :5] # 2. 生成samples列:遇到11111111切换到下一个sample值 split_points = df['tg'] == 11111111 # 计算每个行对应的sample索引(累计分隔点数量) sample_indices = split_points.cumsum() # 避免索引超出samples列表长度 sample_indices = sample_indices.clip(upper=len(samples)-1) # 为非分隔行赋值对应的sample值 df['samples'] = sample_indices.map(lambda x: samples[x]) # 3. 删除NaN列和含11111111的行 df = df.dropna(axis=1) df = df[df['tg'] != 11111111] # 更新frames列表中的原DataFrame对象 frames[i] = df # 处理后的DataFrame可从frames列表中取出使用 df_JSON_processed = frames[0] df_CBOR_processed = frames[1]
关键改动说明
- 索引遍历更新列表:通过
range(len(frames))遍历,直接修改frames[i],确保原列表中的DataFrame对象被更新。 - 向量化替代循环赋值:用
cumsum()计算分隔点累计次数,映射到samples列表,比iterrows()效率提升显著。 - 简化列操作:用
iloc[:, :5]直接选取前5列,逻辑更直观。 - 显式更新列表元素:处理完成后将新DataFrame赋值回
frames[i],彻底解决引用失效问题。
内容的提问来源于stack exchange,提问作者marco890
相关产品推荐
相关产品推荐

