绝对不要逐行增加DataFrame!
简而言之;(只读粗体文字)
这里的大多数答案都会告诉你如何创建一个空的DataFrame并填充它,但没有人会告诉你这样做是不好的。
这是我的建议:使用列表来累积数据,而不是DataFrame。
使用列表来收集数据,然后在准备好时初始化一个DataFrame。无论是列表的列表还是列表的字典格式,pd.DataFrame
都可以接受。
data = []
for row in some_function_that_yields_data():
data.append(row)
df = pd.DataFrame(data)
pd.DataFrame
将行的列表(其中每行是一个标量值)转换为DataFrame。如果您的函数返回的是DataFrame
,请调用{{link1:pd.concat
}}。
这种方法的优点:
将数据附加到列表并一次性创建DataFrame比创建一个空的DataFrame(或NaN的DataFrame)并反复附加要便宜得多。
列表占用的内存也较少,是一种更轻量级的数据结构,可以更容易地进行附加和删除(如果需要)。
自动推断dtypes
(而不是将object
分配给所有dtypes
)。
为您的数据自动创建RangeIndex
,而不必在每次迭代时手动分配正确的索引给附加的行。
如果你还不相信的话,这也在
文档中提到了:
逐行追加到DataFrame中的操作比单次连接更消耗计算资源。更好的解决方案是将这些行追加到一个列表中,然后一次性将列表与原始DataFrame连接起来。
pandas >= 2.0 更新:`append`已被移除!
`DataFrame.append`在1.4版本中被弃用,并在2.0版本中完全从pandas API中移除。
请参阅
弃用文档以及最初提出其弃用的
github问题。
这些选项太糟糕了。
在循环中使用
append
或
concat
是一个很大的错误。
以下是我从初学者那里看到的最大的错误之一:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True)
每次进行
append
或
concat
操作时,都会重新分配内存。再加上循环,就会产生
二次复杂度操作。
与
df.append
相关的另一个错误是用户往往忘记
append不是一个原地函数,所以结果必须重新赋值。您还需要关注数据类型:
df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)
df.dtypes
A object
B float64
C object
dtype: object
处理对象列从来都不是一件好事,因为pandas无法对这些列进行向量化操作。你需要调用
infer_objects()
方法来修复它:
df.infer_objects().dtypes
A int64
B float64
C object
dtype: object
在循环中使用的
loc
我也见过
loc
被用来追加到一个空的DataFrame中:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df.loc[len(df)] = [a, b, c]
和以前一样,每次创建新行时,你没有预先分配所需的内存量,所以内存会每次重新增长。这和`append`一样糟糕,甚至更丑陋。
NaN的空DataFrame
然后,还有创建一个由NaN组成的DataFrame,以及与之相关的所有注意事项。
df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
A B C
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
它创建了一个包含
object
列的DataFrame,就像其他的一样。
df.dtypes
A object
B object
C object
dtype: object
添加仍然存在与上述方法相同的问题。
for i, (a, b, c) in enumerate(some_function_that_yields_data()):
df.iloc[i] = [a, b, c]
实践出真知
通过计时这些方法,可以最快地看出它们在内存和实用性方面的差异有多大。
![enter image description here](https://istack.dev59.com/sGIV6.webp)
参考用的基准代码。
.append
和在 Python 中使用列表添加之间的功能区别是什么?我知道 pandas 中的.append
会将整个数据集复制到一个新对象中,那么 Python 的append
是否有不同的工作方式呢? - Lamma