为何Pandas中df.at迭代赋值后所有行均显示最后生成的列表?
问题:Pandas迭代赋值后
test列所有行显示相同列表的原因及解决办法 问题场景
运行以下代码后,DataFrame的test列所有行最终都显示最后一次迭代生成的完整累积列表,而非预期的逐行递增的累积列表:
import pandas as pd import random data = {'col1': [random.randint(0, 100) for _ in range(5)], 'col2': [random.randint(0, 100) for _ in range(5)]} df = pd.DataFrame(data) lista = [] df['test'] = None for index, row in df.iterrows(): lista.append([random.randint(0, 100) for _ in range(5)]) df.at[index, 'test'] = lista print(index,lista) display(df)
预期输出的test列应该是逐行累积的列表:
test [[first list]] [[first list], [second list]] [[first list], [second list], [third list]] [[first list], [second list], [third list], [fourth list]] [[first list], [second list], [third list], [fourth list], [fifth list]]
原因分析
核心问题是列表的引用传递:
lista是一个可变列表对象,每次lista.append()都是在修改同一个对象的内容。df.at[index, 'test'] = lista赋值的是这个列表对象的引用,而非列表的副本。- 所有行的
test列都指向同一个lista对象,当循环结束时lista已经是完整的5个元素的列表,所以所有行都会显示这个最终状态的列表。
解决办法
方法1:赋值时传入列表的副本
每次赋值时,使用lista.copy()(或list(lista)、lista[:])创建当前lista的副本,这样每行的test列会指向不同的列表对象,保存当前累积的状态:
import pandas as pd import random data = {'col1': [random.randint(0, 100) for _ in range(5)], 'col2': [random.randint(0, 100) for _ in range(5)]} df = pd.DataFrame(data) lista = [] df['test'] = None for index, row in df.iterrows(): lista.append([random.randint(0, 100) for _ in range(5)]) # 赋值列表的副本而非原对象引用 df.at[index, 'test'] = lista.copy() print(index,lista) display(df)
方法2:避免循环,用Pandas向量化方式生成(更高效)
对于Pandas来说,iterrows()效率较低,推荐用列表推导式先生成所有累积列表,再直接赋值给test列:
import pandas as pd import random data = {'col1': [random.randint(0, 100) for _ in range(5)], 'col2': [random.randint(0, 100) for _ in range(5)]} df = pd.DataFrame(data) # 先生成所有随机子列表 all_lists = [[random.randint(0, 100) for _ in range(5)] for _ in range(5)] # 生成累积列表 cumulative_lists = [all_lists[:i+1] for i in range(len(all_lists))] # 直接赋值给test列 df['test'] = cumulative_lists display(df)
内容的提问来源于stack exchange,提问作者OdiumPura
相关产品推荐
相关产品推荐

