如何高效迭代向空Pandas DataFrame添加行?(日增10万行场景)
嘿,你提的这个问题非常典型——很多人刚开始用Pandas的时候都会踩df.append()的性能坑,尤其是要处理十万级别的数据时,你的担心完全没错!
先给你明确结论:
df.append()绝对不适合你的场景——Pandas的append方法每次调用都会创建一个全新的DataFrame对象,把原有的所有数据和新行一起复制一遍。当你要添加10万行时,这种反复复制的开销会大到难以忍受,完全不是高效的做法。
下面给你几个针对你场景的最优方案,按优先级排序:
1. 先把数据存到列表,一次性生成DataFrame(首推)
既然你内存充足,这是性能最高的方案。Python列表的append操作开销极低,我们可以先把所有新获取的数据行存在列表里,等数据收集完成(或者到一天结束时),再一次性转换成DataFrame。
示例代码:
import pandas as pd import datetime # 初始化空列表存数据行 data_rows = [] # 如果初始df有数据,可以保留,最后合并即可 df = pd.DataFrame([], columns=['Timestamp', 'Value']) # 模拟不定期获取数据的过程(10万次) for _ in range(100000): # 每次拿到的数据存成字典(或者元组,更省内存) new_data = { 'Timestamp': datetime.datetime.now(), 'Value': 456 # 替换成你的实际数据值 } data_rows.append(new_data) # 一次性把列表转成DataFrame,替换或合并原df # 如果原df一开始是空的,直接生成就行 df = pd.DataFrame(data_rows, columns=['Timestamp', 'Value'])
这种方式的性能比逐行append高几个数量级——列表的append是均摊O(1)的操作,最后一次性生成DataFrame只需要一次内存分配和数据复制,完全避免了反复复制的开销。
2. 批量拼接(适合无法一次性收集所有数据的场景)
如果你的数据是持续不定期获取,没法等到最后一次性处理,可以每积累一定数量的行(比如1000行)就用pd.concat合并一次,大幅减少拼接的次数:
import pandas as pd import datetime batch_size = 1000 # 每攒1000行合并一次 current_batch = [] df = pd.DataFrame([], columns=['Timestamp', 'Value']) for _ in range(100000): new_data = { 'Timestamp': datetime.datetime.now(), 'Value': 456 } current_batch.append(new_data) # 达到批量大小就合并到主df if len(current_batch) >= batch_size: batch_df = pd.DataFrame(current_batch, columns=['Timestamp', 'Value']) df = pd.concat([df, batch_df], ignore_index=True) current_batch = [] # 清空当前批次,准备攒下一批 # 处理最后剩余的不足一批的数据 if current_batch: batch_df = pd.DataFrame(current_batch, columns=['Timestamp', 'Value']) df = pd.concat([df, batch_df], ignore_index=True)
这种方式把原本10万次的拼接操作减少到100次,性能提升非常明显,同时也能满足你不定期获取数据的需求。
额外补充:关于Pandas的官方建议
Pandas从1.4.0版本开始就已经把append方法标记为**过时(deprecated)**了,官方推荐用pd.concat来替代,但哪怕是pd.concat,频繁调用依然会有复制开销,所以还是批量处理或者先存列表的方案最靠谱。
另外,如果你中途需要偶尔查询数据,也可以用列表存储的同时,定期更新一个临时的小DataFrame,这样既能保证性能,又能满足实时查看的需求。
为什么这些方案更高效?
本质原因是Pandas的DataFrame基于NumPy数组,而数组的大小是固定的——每次添加行都需要重新分配更大的内存空间,然后把原数据全部复制过去。而Python列表是动态扩容的数组,扩容的开销要小得多,最后一次性转换只需要一次内存分配和复制,效率自然高很多。
内容的提问来源于stack exchange,提问作者William Anderson

