在pandas DataFrame中添加一行

PhE*_*PhE 731 python append dataframe pandas

我知道pandas旨在加载完全填充DataFrame但我需要创建一个空的DataFrame,然后逐个添加行.做这个的最好方式是什么 ?

我成功创建了一个空的DataFrame:

res = DataFrame(columns=('lib', 'qty1', 'qty2'))
Run Code Online (Sandbox Code Playgroud)

然后我可以添加一个新行并填充一个字段:

res = res.set_value(len(res), 'qty1', 10.0)
Run Code Online (Sandbox Code Playgroud)

它工作但似乎很奇怪: - /(它添加字符串值失败)

如何向我的DataFrame添加新行(具有不同的列类型)?

fre*_*red 466

>>> 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
Run Code Online (Sandbox Code Playgroud)

  • @MaximG:我强烈建议升级.目前的熊猫版本是0.15.0. (34认同)
  • `.loc`正在引用索引列,所以如果你正在处理一个预先存在的DataFrame,其索引不是以0开头的连续整数序列(如你的例子),`.loc`将覆盖现有行或插入行,或在索引中创建间隙.用于附加现有非零长度数据帧的更强大(但不是万无一失的)方法是:`df.loc [df.index.max()+ 1] = [randint(...`或预填充索引为@FooBar建议. (33认同)
  • 考虑添加索引以预分配内存(请参阅我的回答) (21认同)
  • 当DataFrame为空时,@hobs`df.index.max()`是`nan`。 (3认同)
  • @hobs:我完全同意你的看法.感谢您的输入.但是,它与原始问题中提出的情况不同.如果您事先了解数据框的大小,那么分配内存肯定会更快. (2认同)
  • @ flow2k好抓!我能想到的唯一解决方案是尝试接受pd.DataFrame()构造函数调用(仅在第一行插入)。你知道更好的方法吗? (2认同)
  • @hobs我想到的一种解决方案是使用三元运算符:df.loc [0,如果pd.isnull(df.index.max())否则df.index.max()+ 1]` (2认同)
  • df.loc[len(df.index)] = 行 (2认同)

Shi*_*Dua 378

如果您可以预先获取数据帧的所有数据,则可以采用比附加到数据框更快的方法:

  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)               
Run Code Online (Sandbox Code Playgroud)

  • 对于我无法预先获得所有数据的任何情况,我已经开始这样做了.速度差异令人惊讶. (38认同)
  • 从pandas docs复制:"值得注意的是,concat(因此追加)会生成数据的完整副本,并且不断重用此函数会产生重大的性能损失.如果您需要对多个数据集使用该操作,请使用列表推导.(http://pandas.pydata.org/pandas-docs/stable/merging.html#concatenating-objects) (36认同)
  • @ user5359531您可以手动指定列,并保留订单.pd.DataFrame(rows_list,columns = ['C1','C2','C3'])会做的伎俩 (16认同)
  • 这很棒!除了我创建数据框外,列名都是错误的顺序...... (5认同)
  • @ user5359531在这种情况下你可以使用有序的dict (5认同)
  • @ShikharDua 你能解释一下如何构造数据,即当你说 # 以字典格式获取输入行 # key = col_name 你是什么意思?我的用例:我从 MySQL 表中获取行,每个 `row` 对象都是一个包含 10 个字符串的元组 (2认同)
  • 我在代码中使用 Tuple 尝试了这一点,它甚至比 Dict 还要快。在我的例子中,160 行和 4 列的速度提高了 3 倍。 (2认同)

NPE*_*NPE 265

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

  • 这是正确的答案,但它不是一个非常好的答案(几乎只是链接). (86认同)
  • 嗨,那么使用append()或concat()的方法的答案是什么.我有同样的问题,但仍然试图搞清楚. (6认同)
  • 但是如果你想使用`DataFrame.append()`,你必须首先确保你的行数据也是一个DataFrame,而不是列表. (5认同)
  • 我认为@fred的答案更为正确.IIUC这个答案的问题是每次附加一行时它会不必要地复制整个DataFrame.使用可以避免的`.loc`机制,特别是如果你小心的话. (4认同)
  • DataFrame.append() [自版本 1.4.0 起已弃用](https://pandas.pydata.org/docs/whatsnew/v1.4.0.html#whatsnew-140-deprecations-frame-series-append),仅使用pandas.concat() 将来就像 pandas.concat([DF1, DF2]) (3认同)

cs9*_*s95 174

永远不要增长数据帧!

是的,人们已经解释过你永远不应该增长一个 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'])
Run Code Online (Sandbox Code Playgroud)

这些选项太可怕了

  1. appendconcat在循环内

    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)
    
    Run Code Online (Sandbox Code Playgroud)
  2. NaN 的空数据帧

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

    # 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]
    
    Run Code Online (Sandbox Code Playgroud)

证据就在布丁里

对这些方法进行计时是查看它们在内存和效用方面有多大差异的最快方法。

在此处输入图片说明

基准代码供参考。


像这样的帖子提醒我为什么我是这个社区的一员。人们理解教人们用正确的代码得到正确答案的重要性,而不是用错误的代码得到正确的答案。现在您可能会争辩说这不是问题,loc或者append您是否只向 DataFrame 添加一行。然而,人们往往看这个问题补充不止一个-通常要求是反复添加使用来自一个函数的数据在一个循环内一排(见相关的问题)。在这种情况下,重要的是要了解迭代增长 DataFrame 不是一个好主意。

  • 很公平。如果您需要(或想要)一个数据框,但您的所有样本确实是一个接一个地出现,是否有任何解决方案?(通常是在线学习或主动学习) (5认同)

Mik*_*Sam 131

已经很久了,但我也遇到了同样的问题.并在这里找到了很多有趣的答案.所以我很困惑使用什么方法.

在向数据帧添加大量行的情况下,我对速度性能感兴趣.所以我尝试了3种最流行的方法并检查了它们的速度.

使用新版本的软件包在2019年更新

速度表现

  1. 使用.append(NPE的答案)
  2. 使用.loc(fred的答案FooBar的答案)
  3. 最后使用dict并创建DataFrame(ShikharDua的答案)

结果(以秒为单位):

|------------|-------------|-------------|-------------|
|  Approach  |  1000 rows  |  5000 rows  | 10 000 rows |
|------------|-------------|-------------|-------------|
| .append    |    0.69     |    3.39     |    6.78     |
|------------|-------------|-------------|-------------|
| .loc w/o   |    0.74     |    3.90     |    8.35     |
| prealloc   |             |             |             |
|------------|-------------|-------------|-------------|
| .loc with  |    0.24     |    2.58     |    8.70     |
| prealloc   |             |             |             |
|------------|-------------|-------------|-------------|
|  dict      |    0.012    |   0.046     |   0.084     |
|------------|-------------|-------------|-------------|
Run Code Online (Sandbox Code Playgroud)

还要感谢@krassowski的有用评论 - 我更新了代码.

所以我通过字典为自己添加了.


码:

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)
Run Code Online (Sandbox Code Playgroud)

PS我相信,我的认识并不完美,也许有一些优化.

  • 在.loc中使用df2.index.max()不必要地增加了计算复杂度。简单的`df2.loc [i] = ...`就可以了。对我来说,时间从10秒减少到8.64秒 (3认同)
  • 只是想提出另一条评论,解释为什么 Dict to Pandas DataFrame 是更好的方法。在我对表中具有多种不同数据类型的数据集进行的实验中,使用 Pandas 追加方法会破坏类型,而使用 Dict 并且仅从中创建 DataFrame 一次,似乎可以保持原始数据类型完整。 (2认同)

Foo*_*Bar 96

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

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
Run Code Online (Sandbox Code Playgroud)

速度比较

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
Run Code Online (Sandbox Code Playgroud)

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

增加阵列(12)的大小和行数(500)会使速度差异更加显着:313ms vs 2.29s

  • 增加阵列(12)的大小和行数(500)会使速度差异更加显着:313ms vs 2.29s (7认同)
  • 很好的答案.这应该是常态,因此行空间不必逐步分配. (3认同)

Lyd*_*dia 69

mycolumns = ['A', 'B']
df = pd.DataFrame(columns=mycolumns)
rows = [[1,2],[3,4],[5,6]]
for row in rows:
    df.loc[len(df)] = row
Run Code Online (Sandbox Code Playgroud)

  • 这个!我已经搜索了很长时间,这是第一篇真正展示如何为行分配特定值的文章!奖励问题:列名/值对的语法是什么?我想这一定是使用字典的东西,但是我似乎无法正确地做到这一点。 (2认同)
  • 这效率不高,因为它在扩展时实际上会复制整个DataFrame。 (2认同)

Nas*_*ibi 67

有效追加请参阅如何向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
Run Code Online (Sandbox Code Playgroud)

要么:

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
Run Code Online (Sandbox Code Playgroud)


W.P*_*ill 57

您可以使用该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
Run Code Online (Sandbox Code Playgroud)

  • 你可能还会提到`f.append(<stuff>)`创建一个新对象,而不是简单地附加到当前对象,所以如果你试图追加到脚本中的数据帧,你需要说`f = f.append(<stuff>)` (31认同)
  • 有没有办法做到这一点? (2认同)

hky*_*kyi 41

为了Pythonic的方式,这里添加我的答案:

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
Run Code Online (Sandbox Code Playgroud)


Bri*_*rns 19

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

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)
Run Code Online (Sandbox Code Playgroud)

    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


小智 14

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

虽然这个片段是微不足道的,但在实际数据中我有1,000行和多列,我希望能够按不同的列进行分组,然后对多个taget列执行下面的统计.因此,一次一行地构建数据帧的可靠方法是非常方便的.谢谢@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)
Run Code Online (Sandbox Code Playgroud)


Qin*_*nsi 13

想出一个简单而好的方法:

>>> 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
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这将在幕后复制整个 DataFrame。底层数组无法扩展,因此必须复制它们。 (2认同)

Roc*_*tar 10

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

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'))
Run Code Online (Sandbox Code Playgroud)

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

df = df.append([{ 'lib': "name_20", 'qty1': 20, 'qty2': 400  }])
Run Code Online (Sandbox Code Playgroud)


Jac*_*iel 8

创建一个新记录(数据框)并添加到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])
Run Code Online (Sandbox Code Playgroud)


qwr*_*qwr 7

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

对于c列和n行,这使用一个字典和c 个列表,而不是一个列表和n 个字典。list-of-dictionaries 方法让每个字典存储所有键,并且需要为每一行创建一个新字典。这里我们只附加到列表,这是恒定的时间,理论上非常快。

# 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
Run Code Online (Sandbox Code Playgroud)


Pra*_*kar 6

如果您总是想在最后添加一个新行,请使用以下命令:

df.loc[len(df)] = ['name5', 9, 0]
Run Code Online (Sandbox Code Playgroud)


小智 5

这是在熊猫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]) 
Run Code Online (Sandbox Code Playgroud)

它可以用于在空的或填充的熊猫DataFrame中插入/追加一行