我试图将字典附加到 DataFrame 对象,但出现以下错误:
AttributeError:“DataFrame”对象没有属性“append”
据我所知 DataFrame 确实有“append”方法。
代码片段:
df = pd.DataFrame(df).append(new_row, ignore_index=True)
我期待字典
new_row
被添加为新行。
从 pandas 2.0 开始,
append
(之前已弃用)已删除。
concat
(对于大多数应用程序):
df = pd.concat([df, pd.DataFrame([new_row])], ignore_index=True)
正如@cottontail所指出的,也可以使用
loc
,尽管这仅在新索引尚未存在于DataFrame中时才有效(通常,如果索引是RangeIndex
,则会出现这种情况)
:
df.loc[len(df)] = new_row # only use with a RangeIndex!
我们经常看到 pandas 的新用户尝试像使用纯 Python 一样进行编码。他们使用
iterrows
来访问循环中的项目(请参阅 here 为什么不应该),或者以类似于 python append
的方式使用
list.append
。
然而,正如pandas问题#35407中所述,pandas的
append
和list.append
实际上不是同一件事。 list.append
已就位,而 pandas 的 append
创建了一个新的 DataFrame:
我认为我们应该弃用 Series.append 和 DataFrame.append。 他们正在与 list.append 进行类比,但这是一个糟糕的类比 因为行为尚未(也不可能)到位。数据为 需要复制索引和值才能创建结果。
这些显然也是流行的方法。 DataFrame.append 就在附近 我们的 API 文档中访问量排名第十的页面。
除非我弄错了,否则用户最好建立一个列表 值并将它们传递给构造函数,或者构建一个列表 NDFrames 后跟一个 concat。
因此,虽然
list.append
在循环的每一步都是 摊销 O(1),但 pandas' append
是 O(n)
,使得重复插入时效率低下。
重复使用
append
或 concat
不是一个好主意(这具有 二次行为,因为它为每个步骤创建一个新的 DataFrame)。
在这种情况下,新项目应收集在列表中,并在循环结束时转换为
DataFrame
并最终连接到原始 DataFrame
。
lst = []
for new_row in items_generation_logic:
lst.append(new_row)
# create extension
df_extended = pd.DataFrame(lst, columns=['A', 'B', 'C'])
# or columns=df.columns if identical columns
# concatenate to original
out = pd.concat([df, df_extended])
如果是单行,
loc
也可以完成这项工作。
df.loc[len(df)] = new_row
通过
loc
调用,数据帧会使用索引标签 len(df)
进行放大,仅当索引为 RangeIndex
时才有意义;如果未将显式索引传递给数据帧构造函数,则默认创建 RangeIndex
。
一个工作示例:
df = pd.DataFrame({'A': range(3), 'B': list('abc')})
df.loc[len(df)] = [4, 'd']
df.loc[len(df)] = {'A': 5, 'B': 'e'}
df.loc[len(df)] = pd.Series({'A': 6, 'B': 'f'})
也就是说,如果您要使用
DataFrame.append
或 concat
或 loc
在循环中放大数据框,请考虑重写代码以放大 Python 列表并构造一次数据框。
正如 @mozway 所指出的,放大 pandas 数据帧具有 O(n^2) 复杂度,因为在每次迭代中,必须读取和复制整个数据帧。下面的 perfplot 显示了相对于一次串联的运行时差异。1 正如您所看到的,两种扩大数据帧的方法都比扩大列表和构建一次数据帧要慢得多(例如,对于具有 10k 行的数据帧,循环中的
concat
大约慢 800 倍,循环中的 loc
大约慢 1600 倍)。
1 用于生成性能图的代码:
import pandas as pd
import perfplot
def concat_loop(lst):
df = pd.DataFrame(columns=['A', 'B'])
for dic in lst:
df = pd.concat([df, pd.DataFrame([dic])], ignore_index=True)
return df.infer_objects()
def concat_once(lst):
df = pd.DataFrame(columns=['A', 'B'])
df = pd.concat([df, pd.DataFrame(lst)], ignore_index=True)
return df.infer_objects()
def loc_loop(lst):
df = pd.DataFrame(columns=['A', 'B'])
for dic in lst:
df.loc[len(df)] = dic
return df
perfplot.plot(
setup=lambda n: [{'A': i, 'B': 'a'*(i%5+1)} for i in range(n)],
kernels=[concat_loop, concat_once, loc_loop],
labels= ['concat in a loop', 'concat once', 'loc in a loop'],
n_range=[2**k for k in range(16)],
xlabel='Length of dataframe',
title='Enlarging a dataframe in a loop',
relative_to=1,
equality_check=pd.DataFrame.equals);
免责声明:这个答案似乎很受欢迎,但建议的方法不应该使用。
append
未 更改 为 _append
,_append
是私有 内部 方法,append
已从 pandas API 删除。声明“pandas 中的 append
方法看起来类似于 python 中的 list.append。这就是为什么 pandas 中的append 方法现在修改为
_append
。”是完全不正确的,前导
_
只意味着一件事,该方法是private 并且不打算在 pandas 的内部代码之外使用。
Pandas中,append
方法更改为
_append
,您可以简单地使用
_append
代替
append
,即
df._append(df2)
df = df1._append(df2,ignore_index=True)
为什么变了?
pandas 中的append
方法看起来与 python 中的 list.append 类似。这就是为什么 pandas 中的append 方法现在修改为
_append