通过一次追加一行来创建 Pandas DataFrame

Create a Pandas Dataframe by appending one row at a time

提问人:PhE 提问时间:5/23/2012 最后编辑:Mateen UlhaqPhE 更新时间:7/29/2023 访问量:2202208

问:

如何创建一个空的,然后逐个添加行?DataFrame

我创建了一个空的:DataFrame

df = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))

然后,我可以在末尾添加一个新行,并用以下命令填充单个字段:

df = df._set_value(index=len(df), col='qty1', value=10.0)

它一次只适用于一个字段。添加新行的更好方法是什么?df

Python Pandas 数据帧 追加

评论

97赞 Wes McKinney 5/23/2012
请注意,这是构建大型 DataFrame 的一种非常低效的方法;追加行时,必须创建新数组(复制现有数据)。
8赞 max 8/28/2012
@WesMcKinney:谢谢,知道这一点真是太好了。将添加到大表中是否非常快?
7赞 user1154664 4/20/2013
如果它对您来说效率太低,您可以预先分配一个额外的行,然后更新它。
41赞 cs95 7/13/2020
嘿 你。。。是的,......我明白你在做什么......你想在一个循环中运行它,并以迭代方式将行添加到一个空的 DataFrame,不是吗?好吧,不要!
4赞 Giuseppe Salvatore 11/21/2020
我可能理解这通常是错误的,但是,实时处理呢?所以说我有一些数据每秒进来,我有一个线程只想填充一个数据帧,并且有另一个基于偶数的线程去查看数据帧?我发现这个用例是有效的,并且该解决方案适用于

答:

353赞 NPE 5/23/2012 #1

您可以使用 .有关详细信息和示例,请参阅合并、联接和连接pandas.concat()

例如:

def append_row(df, row):
    return pd.concat([
                df, 
                pd.DataFrame([row], columns=row.index)]
           ).reset_index(drop=True)

df = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))
new_row = pd.Series({'lib':'A', 'qty1':1, 'qty2': 2})

df = append_row(df, new_row)

评论

7赞 notilas 8/21/2014
嗨,那么使用 append() 或 concat() 的方法的答案是什么?我有同样的问题,但仍在努力弄清楚。
152赞 jwg 5/18/2016
这是正确的答案,但这不是一个很好的答案(几乎只有链接)。
5赞 Ken Williams 3/17/2017
我认为@fred的答案更正确。IIUC 这个答案的问题在于,每次追加一行时,它都会不必要地复制整个 DataFrame。使用可以避免的机制,尤其是在您小心的情况下。.loc
7赞 StayFoolish 9/8/2017
但是如果你想使用 ,你必须确保你的行数据首先也是一个 DataFrame,而不是一个列表。DataFrame.append()
3赞 3r1c 5/16/2022
DataFrame.append() 从 1.4.0 版本开始被弃用,以后只使用 pandas.concat(),比如 pandas.concat([DF1, DF2])
780赞 ShikharDua 7/6/2013 #2

如果可以预先获取数据框的所有数据,则有一种比追加到数据帧更快的方法:

  1. 创建一个词典列表,其中每个词典对应于一个输入数据行。
  2. 从此列表创建数据框。

我有一个类似的任务,逐行附加到数据框需要 30 分钟,并在几秒钟内从字典列表中创建一个数据框。

rows_list = []
for row in input_rows:
    dict1 = {}
    # get input row in dictionary format
    # key = col_name
    dict1.update(blah..) 

    rows_list.append(dict1)

df = pd.DataFrame(rows_list)               

评论

74赞 fantabolous 8/13/2014
对于我无法预先获取所有数据的任何情况,我也开始这样做。速度差异是惊人的。
79赞 thikonom 12/26/2015
从 pandas 文档复制:(pandas.pydata.org/pandas-docs/stable/...It is worth noting however, that concat (and therefore append) makes a full copy of the data, and that constantly reusing this function can create a significant performance hit. If you need to use the operation over several datasets, use a list comprehension.)
9赞 user5359531 8/10/2016
这很好用!除了我创建数据框时,列名的顺序都错了......
7赞 ShikharDua 8/11/2016
@user5359531 在这种情况下,您可以使用有序字典
34赞 Marcello Grechi Lins 1/28/2017
@user5359531 您可以手动指定列,顺序将被保留。PD的。DataFrame(rows_list, columns=['C1', 'C2','C3']) 就可以了
79赞 Nasser Al-Wohaibi 5/1/2014 #3

要实现高效追加,请参阅如何向 pandas 数据帧添加额外行放大设置

不存在的键索引数据上添加行。例如:loc/ix

In [1]: se = pd.Series([1,2,3])

In [2]: se
Out[2]:
0    1
1    2
2    3
dtype: int64

In [3]: se[5] = 5.

In [4]: se
Out[4]:
0    1.0
1    2.0
2    3.0
5    5.0
dtype: float64

艺术

In [1]: dfi = pd.DataFrame(np.arange(6).reshape(3,2),
   .....:                 columns=['A','B'])
   .....:

In [2]: dfi
Out[2]:
   A  B
0  0  1
1  2  3
2  4  5

In [3]: dfi.loc[:,'C'] = dfi.loc[:,'A']

In [4]: dfi
Out[4]:
   A  B  C
0  0  1  0
1  2  3  2
2  4  5  4
In [5]: dfi.loc[3] = 5

In [6]: dfi
Out[6]:
   A  B  C
0  0  1  0
1  2  3  2
2  4  5  4
3  5  5  5

评论

1赞 Guilherme Felipe Reis 2/21/2019
用户要求实现(添加新行)。在这里,我们看看如何在定义的索引中添加一行或添加一列。
1赞 PirateApp 3/7/2019
与 dict 方法相比,关于如何工作的任何基准
0赞 waterproof 7/26/2019
这效率不高,因为它实际上复制了整个 DataFrame。
897赞 fred 7/22/2014 #4

您可以使用 ,其中带有索引的行将是您在 DataFrame 中指定的位置。df.loc[i]i

>>> import pandas as pd
>>> from numpy.random import randint

>>> df = pd.DataFrame(columns=['lib', 'qty1', 'qty2'])
>>> for i in range(5):
>>>     df.loc[i] = ['name' + str(i)] + list(randint(10, size=2))

>>> df
     lib qty1 qty2
0  name0    3    3
1  name1    2    4
2  name2    2    8
3  name3    2    1
4  name4    9    6

评论

41赞 FooBar 7/23/2014
考虑添加索引以预分配内存(请参阅我的答案)
70赞 hobs 9/26/2015
.loc引用索引列,因此,如果您使用的是预先存在的 DataFrame,其索引不是以 0 开头的连续整数序列(如示例中所示),则将覆盖现有行、插入行或在索引中创建间隙。用于附加现有非零长度数据帧的更可靠(但不是万无一失)的方法是:或按照@FooBar建议预填充索引。.locdf.loc[df.index.max() + 1] = [randint(...
8赞 flow2k 4/24/2019
@hobs 是 DataFrame 为空时。df.index.max()nan
3赞 hobs 4/25/2019
@flow2k好渔获!我能想到的唯一解决方案是尝试接受(仅在第一行插入时)与 pd。DataFrame() 构造函数调用。你知道更好的方法吗?
17赞 flow2k 4/26/2019
@hobs 我想到的一个解决方案是使用三元运算符:df.loc[0 if pd.isnull(df.index.max()) else df.index.max() + 1]
133赞 FooBar 7/23/2014 #5

如果您事先知道条目的数量,则应通过提供索引来预先分配空间(以不同答案中的数据为例):

import pandas as pd
import numpy as np
# we know we're gonna have 5 rows of data
numberOfRows = 5
# create dataframe
df = pd.DataFrame(index=np.arange(0, numberOfRows), columns=('lib', 'qty1', 'qty2') )

# now fill it up row by row
for x in np.arange(0, numberOfRows):
    #loc or iloc both work here since the index is natural numbers
    df.loc[x] = [np.random.randint(-1,1) for n in range(3)]
In[23]: df
Out[23]: 
   lib  qty1  qty2
0   -1    -1    -1
1    0     0     0
2   -1     0    -1
3    0    -1     0
4   -1     0     0

速度比较

In[30]: %timeit tryThis() # function wrapper for this answer
In[31]: %timeit tryOther() # function wrapper without index (see, for example, @fred)
1000 loops, best of 3: 1.23 ms per loop
100 loops, best of 3: 2.31 ms per loop

而且 - 从评论中可以看出 - 大小为 6000,速度差异变得更大:

增加数组的大小 (12) 和行数 (500) 使 速度差异更惊人:313ms对2.29s

评论

6赞 ely 10/10/2014
很好的答案。这应该是常态,这样行空间就不必以增量方式分配。
9赞 Tickon 4/2/2015
增加数组的大小(12)和行数(500)使速度差异更加明显:313ms与2.29s
94赞 Lydia 6/25/2015 #6
mycolumns = ['A', 'B']
df = pd.DataFrame(columns=mycolumns)
rows = [[1,2],[3,4],[5,6]]
for row in rows:
    df.loc[len(df)] = row

评论

3赞 Eike P. 3/9/2016
这!我已经搜索了很长一段时间,这是第一篇真正展示如何为行分配特定值的帖子!奖励问题:列名/值对的语法是什么?我想这一定是使用字典的东西,但我似乎做对了。
9赞 waterproof 7/26/2019
这并不高效,因为它在扩展时实际上会复制整个 DataFrame。
0赞 PatrickT 11/4/2021
考虑改为这样做。len(df.index)
81赞 W.P. McNeill 2/24/2016 #7

您可以使用该选项将单行追加为字典。ignore_index

>>> f = pandas.DataFrame(data = {'Animal':['cow','horse'], 'Color':['blue', 'red']})
>>> f
  Animal Color
0    cow  blue
1  horse   red
>>> f.append({'Animal':'mouse', 'Color':'black'}, ignore_index=True)
  Animal  Color
0    cow   blue
1  horse    red
2  mouse  black

评论

47赞 Blairg23 5/28/2016
您可能还会提到创建一个新对象,而不是简单地追加到当前对象,因此,如果您尝试追加到脚本中的数据帧,则需要说f.append(<stuff>)f = f.append(<stuff>)
2赞 lol 11/8/2016
有没有办法做到这一点?
1赞 waterproof 7/26/2019
@lol没有。请参阅 github.com/pandas-dev/pandas/issues/2801 - 无法扩展基础数组,因此必须复制它们。
1赞 Gene M 8/1/2020
我更喜欢这种方法,因为它非常像 SQL(在语义上不依赖于索引),并且我尽可能使用它。
14赞 user3250815 7/13/2016 #8

这不是对 OP 问题的回答,而是一个玩具示例来说明 ShikharDua 的答案,我发现这非常有用。

虽然这个片段是微不足道的,但在实际数据中,我有 1,000 行和许多列,我希望能够按不同的列分组,然后对多个目标列执行下面的统计信息。因此,拥有一种可靠的方法来一次构建一行数据框非常方便。谢谢ShikharDua!

import pandas as pd

BaseData = pd.DataFrame({ 'Customer' : ['Acme','Mega','Acme','Acme','Mega','Acme'],
                          'Territory'  : ['West','East','South','West','East','South'],
                          'Product'  : ['Econ','Luxe','Econ','Std','Std','Econ']})
BaseData

columns = ['Customer','Num Unique Products', 'List Unique Products']

rows_list=[]
for name, group in BaseData.groupby('Customer'):
    RecordtoAdd={} #initialise an empty dict
    RecordtoAdd.update({'Customer' : name}) #
    RecordtoAdd.update({'Num Unique Products' : len(pd.unique(group['Product']))})
    RecordtoAdd.update({'List Unique Products' : pd.unique(group['Product'])})

    rows_list.append(RecordtoAdd)

AnalysedData = pd.DataFrame(rows_list)

print('Base Data : \n',BaseData,'\n\n Analysed Data : \n',AnalysedData)
9赞 Jack Daniel 7/18/2016 #9

创建新记录(数据框)并添加到old_data_frame

传递列表和相应的名以创建new_record (data_frame):

new_record = pd.DataFrame([[0, 'abcd', 0, 1, 123]], columns=['a', 'b', 'c', 'd', 'e'])

old_data_frame = pd.concat([old_data_frame, new_record])
3赞 qed 11/12/2016 #10

另一种方法(可能不是很高性能):

# add a row
def add_row(df, row):
    colnames = list(df.columns)
    ncol = len(colnames)
    assert ncol == len(row), "Length of row must be the same as width of DataFrame: %s" % row
    return df.append(pd.DataFrame([row], columns=colnames))

您还可以像这样增强 DataFrame 类:

import pandas as pd
def add_row(self, row):
    self.loc[len(self.index)] = row
pd.DataFrame.add_row = add_row
48赞 hkyi 8/6/2017 #11

为了 Python 的方式:

res = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))
res = res.append([{'qty1':10.0}], ignore_index=True)
print(res.head())

   lib  qty1  qty2
0  NaN  10.0   NaN
1赞 Vineet Jain 8/25/2017 #12

让一切变得简单。通过将列表作为输入,该列表将作为行附加到数据框中:

import pandas as pd
res = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))
for i in range(5):
    res_list = list(map(int, input().split()))
    res = res.append(pd.Series(res_list, index=['lib', 'qty1', 'qty2']), ignore_index=True)
37赞 Brian Burns 10/13/2017 #13

您还可以构建列表列表并将其转换为数据帧 -

import pandas as pd

columns = ['i','double','square']
rows = []

for i in range(6):
    row = [i, i*2, i*i]
    rows.append(row)

df = pd.DataFrame(rows, columns=columns)

    i   double  square
0   0   0   0
1   1   2   1
2   2   4   4
3   3   6   9
4   4   8   16
5   5   10  25
438赞 Mikhail_Sam 12/26/2017 #14

在向 DataFrame 添加大量行的情况下,我对性能感兴趣。因此,我尝试了四种最流行的方法并检查了它们的速度。

性能

  1. 使用 .append(NPE 的答案)
  2. 使用 .loc (fred 的答案)
  3. 将 .loc 与预分配一起使用(FooBar 的答案)
  4. 最后使用 dict 并创建 DataFrame(ShikharDua 的答案)

运行时结果(以秒为单位):

方法 1000 行 5000 行 10 000 行
。附加 0.69 3.39 6.78
不带 prealloc 的 .loc 0.74 3.90 8.35
带有 prealloc 的 .loc 0.24 2.58 8.70
字典 0.012 0.046 0.084

所以我通过字典为自己使用加法。


法典:

import pandas as pd
import numpy as np
import time

del df1, df2, df3, df4
numOfRows = 1000
# append
startTime = time.perf_counter()
df1 = pd.DataFrame(np.random.randint(100, size=(5,5)), columns=['A', 'B', 'C', 'D', 'E'])
for i in range( 1,numOfRows-4):
    df1 = df1.append( dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E']), ignore_index=True)
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df1.shape)

# .loc w/o prealloc
startTime = time.perf_counter()
df2 = pd.DataFrame(np.random.randint(100, size=(5,5)), columns=['A', 'B', 'C', 'D', 'E'])
for i in range( 1,numOfRows):
    df2.loc[i]  = np.random.randint(100, size=(1,5))[0]
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df2.shape)

# .loc with prealloc
df3 = pd.DataFrame(index=np.arange(0, numOfRows), columns=['A', 'B', 'C', 'D', 'E'] )
startTime = time.perf_counter()
for i in range( 1,numOfRows):
    df3.loc[i]  = np.random.randint(100, size=(1,5))[0]
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df3.shape)

# dict
startTime = time.perf_counter()
row_list = []
for i in range (0,5):
    row_list.append(dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E']))
for i in range( 1,numOfRows-4):
    dict1 = dict( (a,np.random.randint(100)) for a in ['A','B','C','D','E'])
    row_list.append(dict1)

df4 = pd.DataFrame(row_list, columns=['A','B','C','D','E'])
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df4.shape)

P.S.:我相信我的实现并不完美,也许可以做一些优化。

评论

5赞 krassowski 1/24/2019
使用 for 会不必要地增加计算复杂性。简单就可以了。对我来说,它将时间从 10 秒减少到 8.64 秒df2.index.max().locdf2.loc[i] = ...
0赞 FooBar 7/30/2019
请从列表中删除我的名字,因为您在测试中没有遵循我的方法:您没有通过提供合适大小的索引来预分配内存。
1赞 flow2k 9/29/2019
@Mikhail_Sam 对于最后一个 dict 方法,使用两个循环和 ?for i in range (0,5):for i in range( 1,numOfRows-4):
2赞 trumpetlicks 12/4/2019
只是想抛出另一个评论,说明为什么 Dict to Pandas DataFrame 是一种更好的方法。在我对表中具有多种不同数据类型的数据集的实验中,使用 Pandas 追加方法会破坏类型,而使用 Dict 并且仅从中创建一次 DataFrame,似乎可以保持原始数据类型完好无损。
1赞 qwr 7/29/2023
您还应该使用微基准测试来避免一些常见的基准测试问题。timeit.timeit
17赞 Qinsi 8/30/2018 #15

我想出了一个简单而不错的方法:

>>> df
     A  B  C
one  1  2  3
>>> df.loc["two"] = [4,5,6]
>>> df
     A  B  C
one  1  2  3
two  4  5  6

请注意注释中提到的性能警告。

评论

3赞 waterproof 7/26/2019
请注意,这将在后台复制整个 DataFrame。基础数组无法扩展,因此必须复制它们。
7赞 shivampip 9/6/2018 #16

以下是在 Pandas 中添加/附加行的方法:DataFrame

def add_row(df, row):
    df.loc[-1] = row
    df.index = df.index + 1
    return df.sort_index()

add_row(df, [1,2,3])

它可用于在空的或填充的 Pandas DataFrame 中插入/追加一行。

评论

1赞 Parthiban Rajendran 10/14/2018
这是按降序添加索引
0赞 Armali 8/22/2019 #17

我们经常看到要分配给一个 DataFrame 行的构造。Mikhail_Sam发布了包含此构造以及最终使用 dict 和 create DataFrame 的方法等基准测试。他发现后者是迄今为止最快的。df.loc[subscript] = …

但是,如果我们用 替换他代码中的 (使用预分配的 DataFrame) ,结果就会发生重大变化,因为该方法的执行方式与使用 dict 的方法类似。因此,我们应该更经常地考虑使用。但是请注意,它采用从零开始的下标,该下标可能与 DataFrame.index 不同。df3.loc[i] = …df3.values[i] = …df.values[subscript] = ….values

评论

1赞 Armali 2/7/2020
@baxx - 一个代码示例在基准链接 (),另一个示例是我必须将 Pandas DataFrame 的每一行的数据与其余行的数据进行比较的问题,有没有办法加快计算速度? 及其公认的答案。# .loc with prealloc
13赞 RockStar 10/21/2019 #18

您可以使用生成器对象来创建 DataFrame,这将比列表更节省内存。

num = 10

# Generator function to generate generator object
def numgen_func(num):
    for i in range(num):
        yield ('name_{}'.format(i), (i*i), (i*i*i))

# Generator expression to generate generator object (Only once data get populated, can not be re used)
numgen_expression = (('name_{}'.format(i), (i*i), (i*i*i)) for i in range(num) )

df = pd.DataFrame(data=numgen_func(num), columns=('lib', 'qty1', 'qty2'))

若要将原始数据添加到现有 DataFrame,可以使用 append 方法。

df = df.append([{ 'lib': "name_20", 'qty1': 20, 'qty2': 400  }])
17赞 qwr 12/30/2019 #19

ShikharDua的回答(基于行)中的字典列表不同,我们还可以将表表示为列表字典(基于列),其中每个列表存储一列(按行顺序),前提是我们事先知道我们的列。最后,我们构造一次 DataFrame。

在这两种情况下,字典键始终是列名。行顺序隐式存储为列表中的顺序。对于 c 列和 n 行,这将使用一个包含 c 列表(长度为 n)的字典,而不是一个包含 n 个字典(包含 c 条目)的字典。字典列表方法使每个字典冗余地存储所有键,并且需要为每一行创建一个新字典。在这里,我们只附加到列表,这总体上是相同的时间复杂度(向列表和字典添加条目都是摊销的恒定时间),但由于列表比字典更简单,因此时间和空间开销可能更少。

# Current data
data = {"Animal":["cow", "horse"], "Color":["blue", "red"]}

# Adding a new row (be careful to ensure every column gets another value)
data["Animal"].append("mouse")
data["Color"].append("black")

# At the end, construct our DataFrame
df = pd.DataFrame(data)
#   Animal  Color
# 0    cow   blue
# 1  horse    red
# 2  mouse  black

评论

0赞 Shajirr 7/16/2023
我发现这种方法使用起来最方便,因为在附加新值时,您永远不必担心列顺序。
0赞 kamran kausar 2/19/2020 #20

熊猫。DataFrame.append

DataFrame.append(self, other, ignore_index=False, verify_integrity=False, sort=False) → 'DataFrame'

法典

df = pd.DataFrame([[1, 2], [3, 4]], columns=list('AB'))
df2 = pd.DataFrame([[5, 6], [7, 8]], columns=list('AB'))
df.append(df2)

ignore_index设置为 True 时:

df.append(df2, ignore_index=True)

评论

1赞 Peter Mortensen 7/14/2021
目前尚不清楚为什么前两行不是文字代码。简洁是好的,但你能详细说明你的答案,例如通过添加一些支持性文本吗?但是如果没有“编辑:”,“更新:”或类似的东西 - 答案应该看起来就像今天写的一样。
4赞 Shahir Ansari 3/26/2020 #21

如果要在末尾添加一行,请将其附加为列表:

valuestoappend = [va1, val2, val3]
res = res.append(pd.Series(valuestoappend, index = ['lib', 'qty1', 'qty2']), ignore_index = True)
0赞 srikanth Gattu 4/18/2020 #22

在添加一行之前,我们必须将 DataFrame 转换为字典。在那里,您可以看到键作为 DataFrame 中的列,并且列的值再次存储在字典中,但每列的键都是 DataFrame 中的索引号。

这个想法促使我编写下面的代码。

df2 = df.to_dict()
values = ["s_101", "hyderabad", 10, 20, 16, 13, 15, 12, 12, 13, 25, 26, 25, 27, "good", "bad"] # This is the total row that we are going to add
i = 0
for x in df.columns:   # Here df.columns gives us the main dictionary key
    df2[x][101] = values[i]   # Here the 101 is our index number. It is also the key of the sub dictionary
    i += 1
3赞 hansrajswapnil 4/30/2020 #23

为此,您可以连接两个 DataFrame。我基本上遇到了这个问题,以使用字符索引(而不是数字)向现有 DataFrame 添加新行。

因此,我在 duct() 中输入新行的数据,并在列表中输入索引。

new_dict = {put input for new row here}
new_list = [put your index here]

new_df = pd.DataFrame(data=new_dict, index=new_list)

df = pd.concat([existing_df, new_df])

评论

0赞 Igor Ostaptchenko 4/29/2022
这确实是我所需要的
3赞 Giorgos Myrianthous 5/1/2020 #24

您所需要的只是或loc[df.shape[0]]loc[len(df)]


# Assuming your df has 4 columns (str, int, str, bool)
df.loc[df.shape[0]] = ['col1Value', 100, 'col3Value', False] 

df.loc[len(df)] = ['col1Value', 100, 'col3Value', False] 
3赞 Harshal Deore 6/13/2020 #25
initial_data = {'lib': np.array([1,2,3,4]), 'qty1': [1,2,3,4], 'qty2': [1,2,3,4]}

df = pd.DataFrame(initial_data)

df

lib    qty1    qty2
0    1    1    1
1    2    2    2
2    3    3    3
3    4    4    4

val_1 = [10]
val_2 = [14]
val_3 = [20]

df.append(pd.DataFrame({'lib': val_1, 'qty1': val_2, 'qty2': val_3}))

lib    qty1    qty2
0    1    1    1
1    2    2    2
2    3    3    3
3    4    4    4
0    10    14    20

您可以使用 for 循环来循环访问值,也可以添加值数组。

val_1 = [10, 11, 12, 13]
val_2 = [14, 15, 16, 17]
val_3 = [20, 21, 22, 43]

df.append(pd.DataFrame({'lib': val_1, 'qty1': val_2, 'qty2': val_3}))

lib    qty1    qty2
0    1    1    1
1    2    2    2
2    3    3    3
3    4    4    4
0    10    14    20
1    11    15    21
2    12    16    22
3    13    17    43

评论

1赞 Peter Mortensen 7/14/2021
对第一部分的解释是有序的。为什么在谈论示例代码时没有“for”循环?你能说得更清楚吗?请通过编辑您的答案来回复,而不是在评论中(没有“编辑:”,“更新:”或类似内容 - 答案应该看起来好像是今天写的)。
301赞 cs95 7/5/2020 #26

从 pandas >= 2.0,已被删除!append

DataFrame.append在版本 1.4 中已弃用,并在版本 2.0 中完全从 pandas API 中删除。

请参阅有关弃用的文档以及最初建议弃它的 github 问题

如果您运行的是 pandas 版本 2.0 或更高版本,则可能会遇到以下错误:

AttributeError: 'DataFrame' object has no attribute 'append' for DataFrame

如果您想了解更多惯用的替代方法,请继续阅读。append


永远不要增长 DataFrame!

是的,人们已经解释过,你永远不应该增长 DataFrame,你应该将你的数据附加到一个列表中,并在最后将其转换为一个 DataFrame。但是你明白为什么吗?

以下是最重要的原因,摘自我在这里的帖子。

  1. 一次性追加到列表并创建 DataFrame 总是更便宜/更快。
  2. 列表占用的内存更少,并且是一种更轻量级的数据结构,可用于处理、追加和删除。
  3. dtypes自动推断您的数据。另一方面,创建一个 NaN 的空帧会自动使它们成为 ,这很糟糕。object
  4. 系统会自动为您创建一个索引,而您不必注意将正确的索引分配给要追加的行。

这是积累数据的正确方法™

data = []
for a, b, c in some_function_that_yields_data():
    data.append([a, b, c])

df = pd.DataFrame(data, columns=['A', 'B', 'C'])

请注意,如果返回较小的 DataFrame,则可以在列表中累积单个 DataFrame,然后在最后对 pd.concat 进行一次调用。some_function_that_yields_data()

这些选项太可怕了

  1. 在循环中追加连接

    append并且本身并不是孤立的坏。这 当您在循环中迭代调用它们时,问题就开始了 - 这个 导致二次内存使用。concat

    # Creates empty DataFrame and appends
    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)  
        # This is equally bad:
        # df = pd.concat(
        #       [df, pd.Series({'A': i, 'B': b, 'C': c})], 
        #       ignore_index=True)
    
  2. NaN 的空 DataFrame

    切勿创建 NaN 的 DataFrame,因为列是用 (缓慢的、不可矢量化的 dtype) 初始化的。object

    # Creates DataFrame of NaNs and overwrites values.
    df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
    for a, b, c in some_function_that_yields_data():
        df.loc[len(df)] = [a, b, c]
    

证据在布丁中

对这些方法进行计时是了解它们在内存和实用性方面有多大差异的最快方法。

enter image description here

基准测试代码供参考。


正是这样的帖子提醒了我为什么我是这个社区的一员。人们明白教人们用正确的代码获得正确答案的重要性,而不是用错误的代码获得正确的答案。现在,您可能会争辩说,使用它不是问题,或者如果您只向 DataFrame 添加一行。然而,人们经常在这个问题上添加不止 - 通常要求是使用来自函数的数据在循环中迭代添加一行(参见相关问题)。在这种情况下,重要的是要了解迭代增长 DataFrame 不是一个好主意。locappend

评论

9赞 user1657853 9/8/2020
很公平。如果您需要(或想要)一个数据帧,但您的所有样本确实一个接一个地出现,是否有任何解决方案?(通常是在线学习或主动学习)
0赞 Dev Aggarwal 9/17/2020
这不包括在每次 append() 之后需要 dataframe 的情况。在这种情况下,数据帧无论如何都会被复制,因此 df.loc 方法更快
1赞 cs95 9/18/2020
@DevAggarwal不正确,loc 每次也会创建一个副本。请看我回答中的图表时间。Append 和 loc_append 同样糟糕。我还分享了我的代码和流程,所以你可以自由地说服自己。
0赞 Dev Aggarwal 9/18/2020
道歉应该更清楚。请从 for 循环中的中间列表创建数据帧,这里 -- gist.github.com/Coldsp33d/...
0赞 Kuzeko 1/20/2021
有没有人对@DevAggarwal的建议进行基准测试?我经常遇到这种情况
1赞 Muhammad Yasirroni 11/16/2022
如果数据来自另一个 DataFrame,该怎么办?
0赞 Gerard 10/12/2020 #27

如果 DataFrame 中的所有数据都具有相同的 dtype,则可以使用 NumPy 数组。您可以将行直接写入预定义的数组,并在末尾将其转换为数据帧。 它似乎比转换字典列表还要快。

import pandas as pd
import numpy as np
from string import ascii_uppercase

startTime = time.perf_counter()
numcols, numrows = 5, 10000
npdf = np.ones((numrows, numcols))
for row in range(numrows):
    npdf[row, 0:] = np.random.randint(0, 100, (1, numcols))
df5 = pd.DataFrame(npdf, columns=list(ascii_uppercase[:numcols]))
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df5.shape)

评论

0赞 Peter Mortensen 7/14/2021
回复“它似乎更快”:你能量化它(通过编辑(改变)你的答案)吗?我们在说什么顺序?快 10%?快 100%?快 10 倍?快 1,000,000 倍?在什么尺度上(它可以是二次/指数)?
0赞 Mahdi 12/21/2020 #28

如果您有一个数据框,并且想要将列表作为新行添加到 ,则只需执行以下操作即可:dfnew_listdf

df.loc[len(df)] = new_list

如果要在 Data Frame 下添加新的数据框,则可以使用:new_dfdf

df.append(new_df)
22赞 Prajot Kuvalekar 3/6/2021 #29

如果您总是想在末尾添加新行,请使用以下命令:

df.loc[len(df)] = ['name5', 9, 0]

评论

0赞 autonopy 7/21/2022
这假定数据帧的索引是有编号的,并且它是完全连续的。使用可以解决这个问题,但就目前而言,它实际上可能会覆盖现有行。df.reset_index()
0赞 mpa 3/24/2023 #30

以下是 3 个经常提到的选项及其添加的缺点

  • 单行(非多
  • 针对可读性进行了优化(不是为了运行时性能,例如,即使不是首选,也允许复制 DataFrame)
  • 列可以具有不同的 DTYPE
  • 保留所有列的 dtype
  • 索引可以是任何形式,例如整数序列中的“洞”
  • 保留df.index

代码设置:

df = pd.DataFrame({'carId': [1, 4, 7], 'maxSpeed': [1.1, 4.4, 7.7]})
df = df.astype({
    'carId': np.uint16,
    'maxSpeed': np.float32,
})
df.set_index('carId', drop=False, inplace=True)
assert df.index.dtype == np.uint64

# the row to add
additional_row = [9, 9.9]
assert len(df.columns) == len(additional_row)
original_dtypes = df.dtypes
original_index_dtype = df.index.dtype

1) pd.concat()

df_new_row = pd.DataFrame([additional_row], columns=df.columns)
newDf = pd.concat([df, df_new_row])
assert df.dtypes.equals(newDf.dtypes)  # fails: carId is np.int64 and maxSpeed is np.float64
assert newDf.dtypes.equals(original_dtypes)  # fails: newDf.index.dype is np.float64

2) df.loc[]

df.loc[additional_row[0], :] = additional_row
assert df.index.dtype == original_index_dtype
assert df.dtypes.equals(original_dtypes)  # fails: carId and maxSpeed are np.float64

3) df.append()

自 Pandas 1.4.0 起折旧

溶液

df.loc[] 保持 df.index 不变,因此我通常会转换列的类型:

df.loc[additional_row[0], :] = additional_row
df = df.astype(original_dtypes)
assert df.index.dtype == original_index_dtype
assert df.dtypes.equals(original_dtypes)

请注意,这将创建 . 如果可以接受 copy 参数的副作用,则可以避免这种情况。df.astype()dfdf.astype(copy=False)

如果您不想显式设置索引,请使用例如 .请注意,如果为空,则失败。df.loc[df.index.max() + 1, :] = additional_rowdf.index.max()df

不幸的是,如何向 pandas 数据帧添加额外的行已被标记为重复并指向此问题。这篇文章的标题“一次附加一行”意味着定期向 DataFrame 添加多行是一个好主意。我同意以前的许多评论,即这可能没有很多用例。但是,向 DataFrame 添加单行的频率更高,即使它仍然是边缘情况。