向pandas DataFrame添加一行


867

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

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

res = DataFrame(columns=('lib', 'qty1', 'qty2'))

然后,我可以添加新行,并使用以下字段填充字段:

res = res.set_value(len(res), 'qty1', 10.0)

它有效,但看起来很奇怪:-/(添加字符串值失败)

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


70
注意,这是构建大型DataFrame的非常低效的方法;追加一行时,必须创建新数组(复制现有数据)。
Wes McKinney

5
@WesMcKinney:谢谢,我真的很高兴。将添加到大型表是否很快?
最大

4
如果对您来说效率太低,则可以预分配其他行,然后更新它。
user1154664

Answers:


568
>>> 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

25
考虑添加索引以预分配内存(请参阅我的答案)
FooBar 2014年

34
@MaximG:我强烈建议升级。当前Pandas版本是0.15.0。
2014年

44
.loc正在引用索引列,因此,如果您正在使用索引不是由0开头的连续整数序列(如您的示例)的预先存在的DataFrame,.loc将覆盖现有行或插入行,或者在索引中造成差距。附加现有的非零长度数据帧的更健壮(但并非df.loc[df.index.max() + 1] = [randint(...万无一失)的方法是:或按照@FooBar建议的那样预填充索引。
滚刀

4
@hobs df.index.max()nanDataFrame为空时。
flow2k

4
@hobs我想到的一个解决方案是使用三元运算符:df.loc[0 if pd.isnull(df.index.max()) else df.index.max() + 1]
flow2k

473

如果可以预先获取该数据帧的所有数据,则有一种比附加到数据帧快得多的方法:

  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)               

48
对于无法提前获取所有数据的情况,我也已经做好了这样做的准备。速度差异惊人。
2014年

47
从pandas docs复制: 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.pandas.pydata.org/pandas-docs/stable/…
thikonom 2015年

5
这很棒!除非我创建数据框时,
否则

5
@ user5359531在这种情况下,您可以使用命令字典
ShikharDua '16

20
@ user5359531您可以手动指定列,顺序将被保留。pd.DataFrame(rows_list,columns = ['C1','C2','C3'])将达到目的
Marcello Grechi Lins

287

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


6
嗨,那么使用append()或concat()的方法的答案是什么。我有同样的问题,但仍在设法解决。
notilas 2014年

109
这是正确的答案,但这不是一个很好的答案(仅链接)。
jwg

5
我认为@fred的答案更正确。IIUC这个答案的问题在于,每当追加一行时,它都会不必要地复制整个DataFrame。使用.loc可以避免的机制,尤其是当您小心时。
肯·威廉姆斯

7
但是,如果要使用DataFrame.append(),则必须确保行数据首先也是DataFrame,而不是列表。
StayFoolish

201

已经很长时间了,但是我也面临着同样的问题。并在这里找到了很多有趣的答案。所以我很困惑使用什么方法。

在向数据帧添加很多行的情况下,我对速度性能感兴趣。因此,我尝试了4种最流行的方法并检查了它们的速度。

使用新版本的软件包在2019年更新。在@FooBar评论也会更新

速度表现

  1. 使用.append(NPE的答案
  2. 使用.loc(弗雷德的答案
  3. 使用.loc进行预分配(FooBar的答案
  4. 最后使用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     |
|------------|-------------|-------------|-------------|

也感谢@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)

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


4
使用df2.index.max()for会.loc不必要地增加计算复杂性。简单df2.loc[i] = ...就能做到。对我来说,时间从10s减少到8.64s
krassowski 19'Jan

请从列表中删除我的名字,因为您没有遵循我的测试方法:您没有通过提供适当大小的索引来预分配内存。
FooBar

@FooBar嗨!很高兴您看到作者的回答:)您说得对,我错过了这一要点。我宁愿在结果表中再添加一行,因为您的方法将显示不同的结果!
Mikhail_Sam '19

@Mikhail_Sam您将如何使用数据透视表以最快的方法dict将其写入Excel文件?
FabioSpaghetti

1
只是想对为什么“ Dict to Pandas DataFrame”是一种更好的方法再发表评论。在我对表中具有多种不同数据类型的数据集的实验中,使用Pandas的append方法会破坏类型,而使用Dict并仅从中创建DataFrame似乎可以保持原始数据类型的完整性。
trumpetlicks 19/12/04

109

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

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 vs 2.29s


3
好答案。这应该是规范,这样行空间就不必增量分配。
2014年

8
增大数组(12)的大小和行数(500)会使速度差异更加明显:313ms vs 2.29s
Tickon 2015年

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

2
这个!我已经搜索了很长一段时间,这是第一篇真正显示如何为行分配特定值的文章!奖励问题:列名/值对的语法是什么?我想这一定是使用dict的东西,但是我似乎无法正确理解。
jhin

3
这效率不高,因为它在扩展时实际上会复制整个DataFrame。
防水

72

为了高效地附加,请参见如何向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

用户要求提供工具(添加新行)。在这里,我们看到如何在已定义的索引中添加一行或添加一列。
Guilherme Felipe Reis,

1
与dict方法相比,有关此方法的任何基准测试
PirateApp

这是无效的,因为它实际上复制了整个DataFrame。
防水

66

您可以使用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

37
您可能还会提到f.append(<stuff>)创建一个新对象,而不是简单地附加到当前对象,因此,如果您尝试附加到脚本中的数据帧,则需要说一下f = f.append(<stuff>)
Blairg23,2016年

2
有办法做到这一点吗?
哈哈

@哈哈,不。参见github.com/pandas-dev/pandas/issues/2801-无法扩展基础数组,因此必须将其复制。
防水

46

为了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

26

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

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)

给予

    我加倍
0 0 0 0
1 1 2 1
2 2 4 4
3 3 6 9
4 4 8 16
5 5 10 25

15

这不是对OP问题的答案,而是一个玩具示例,用于说明@ShikharDua的答案,在上面我发现它非常有用。

尽管这个片段是微不足道的,但在实际数据中,我有1000行和许多列,我希望能够按不同的列进行分组,然后对一个以上的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)

14

想出了一种简单而又不错的方法:

>>> 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

1
请注意,这将在后台复制整个DataFrame。基础数组无法扩展,因此必须将其复制。
防水

10

您可以使用生成器对象创建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  }])

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])


5

除了ShikharDua的答案中的字典列表之外,我们还可以将表表示为list字典,假设我们事先知道各列,则每个列表按行顺序存储一列。最后,我们构造一次DataFrame。

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

# 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

5

如果要在行末添加行,请将其添加为列表

valuestoappend = [va1,val2,val3]
res = res.append(pd.Series(valuestoappend,index = ['lib', 'qty1', 'qty2']),ignore_index = True)

4

另一种方法(可能不是很出色):

# 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

1

简单点。通过将列表作为输入,将其添加为数据帧中的行:

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)

1

您需要的是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] 

0

我们经常看到df.loc[subscript] = …分配给一个DataFrame行的结构。Mikhail_Sam发布了基准测试,其中包含此构造以及使用dict的方法,最后创建了DataFrame。他发现后者是迄今为止最快的。但是,如果我们用替换df3.loc[i] = …其代码中的(使用预分配的DataFrame)df3.values[i] = …,结果将发生显着变化,因为该方法的性能类似于使用dict的方法。因此,我们应该更多地考虑使用df.values[subscript] = …。但是请注意,.values它采用从零开始的下标,该下标可能与DataFrame.index不同。


这样的代码示例将很有用
baxx

1
@baxx -一个代码示例是在基准链接(# .loc with prealloc),另一个例子是在质疑我把数据从一个数据帧大熊猫的每一行与行的其余数据进行比较,是有办法来加速计算?及其公认的答案。
阿玛利

0

pandas.DataFrame.append

DataFrame.append(自身,其他,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)

0

在添加行之前,我们必须将数据帧转换为字典,在那里您可以看到键在数据帧中为列,并且列的值再次存储在字典中,但是每一列的键都是数据帧中的索引号。这个想法让我写了下面的代码。

df2=df.to_dict()
values=["s_101","hyderabad",10,20,16,13,15,12,12,13,25,26,25,27,"good","bad"] #this is 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 key of sub dictionary
    i+=1

0

您可以为此连接两个DataFrame。我基本上遇到了这个问题,将新行添加到具有字符索引(非数字)的现有DataFrame中。因此,我在pipe()中输入新行的数据,并在列表中输入索引。

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])

-1

这将有助于将一个项目添加到一个空的DataFrame中。问题在于df.index.max() == nan第一个索引:

df = pd.DataFrame(columns=['timeMS', 'accelX', 'accelY', 'accelZ', 'gyroX', 'gyroY', 'gyroZ'])

df.loc[0 if math.isnan(df.index.max()) else df.index.max() + 1] = [x for x in range(7)]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.