提问人:PhE 提问时间:5/23/2012 最后编辑:Mateen UlhaqPhE 更新时间:7/29/2023 访问量:2202208
通过一次追加一行来创建 Pandas DataFrame
Create a Pandas Dataframe by appending one row at a time
问:
如何创建一个空的,然后逐个添加行?DataFrame
我创建了一个空的:DataFrame
df = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))
然后,我可以在末尾添加一个新行,并用以下命令填充单个字段:
df = df._set_value(index=len(df), col='qty1', value=10.0)
它一次只适用于一个字段。添加新行的更好方法是什么?df
答:
您可以使用 .有关详细信息和示例,请参阅合并、联接和连接。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)
评论
.loc
DataFrame.append()
如果可以预先获取数据框的所有数据,则有一种比追加到数据帧更快的方法:
- 创建一个词典列表,其中每个词典对应于一个输入数据行。
- 从此列表创建数据框。
我有一个类似的任务,逐行附加到数据框需要 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)
评论
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 数据帧添加额外行和放大设置。
在不存在的键索引数据上添加行。例如: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
评论
您可以使用 ,其中带有索引的行将是您在 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
评论
.loc
引用索引列,因此,如果您使用的是预先存在的 DataFrame,其索引不是以 0 开头的连续整数序列(如示例中所示),则将覆盖现有行、插入行或在索引中创建间隙。用于附加现有非零长度数据帧的更可靠(但不是万无一失)的方法是:或按照@FooBar建议预填充索引。.loc
df.loc[df.index.max() + 1] = [randint(...
df.index.max()
nan
df.loc[0 if pd.isnull(df.index.max()) else df.index.max() + 1]
如果您事先知道条目的数量,则应通过提供索引来预先分配空间(以不同答案中的数据为例):
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
评论
mycolumns = ['A', 'B']
df = pd.DataFrame(columns=mycolumns)
rows = [[1,2],[3,4],[5,6]]
for row in rows:
df.loc[len(df)] = row
评论
len(df.index)
您可以使用该选项将单行追加为字典。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
评论
f.append(<stuff>)
f = f.append(<stuff>)
这不是对 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)
创建新记录(数据框)并添加到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])
另一种方法(可能不是很高性能):
# 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
为了 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
让一切变得简单。通过将列表作为输入,该列表将作为行附加到数据框中:
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)
您还可以构建列表列表并将其转换为数据帧 -
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
在向 DataFrame 添加大量行的情况下,我对性能感兴趣。因此,我尝试了四种最流行的方法并检查了它们的速度。
性能
- 使用 .append(NPE 的答案)
- 使用 .loc (fred 的答案)
- 将 .loc 与预分配一起使用(FooBar 的答案)
- 最后使用 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.:我相信我的实现并不完美,也许可以做一些优化。
评论
df2.index.max()
.loc
df2.loc[i] = ...
for i in range (0,5):
for i in range( 1,numOfRows-4):
timeit.timeit
我想出了一个简单而不错的方法:
>>> 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
请注意注释中提到的性能警告。
评论
以下是在 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 中插入/追加一行。
评论
我们经常看到要分配给一个 DataFrame 行的构造。Mikhail_Sam发布了包含此构造以及最终使用 dict 和 create DataFrame 的方法等基准测试。他发现后者是迄今为止最快的。df.loc[subscript] = …
但是,如果我们用 替换他代码中的 (使用预分配的 DataFrame) ,结果就会发生重大变化,因为该方法的执行方式与使用 dict 的方法类似。因此,我们应该更经常地考虑使用。但是请注意,它采用从零开始的下标,该下标可能与 DataFrame.index 不同。df3.loc[i] = …
df3.values[i] = …
df.values[subscript] = …
.values
评论
# .loc with prealloc
您可以使用生成器对象来创建 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 }])
与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
评论
熊猫。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)
评论
如果要在末尾添加一行,请将其附加为列表:
valuestoappend = [va1, val2, val3]
res = res.append(pd.Series(valuestoappend, index = ['lib', 'qty1', 'qty2']), ignore_index = True)
在添加一行之前,我们必须将 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
为此,您可以连接两个 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])
评论
您所需要的只是或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]
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
评论
从 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。但是你明白为什么吗?
以下是最重要的原因,摘自我在这里的帖子。
- 一次性追加到列表并创建 DataFrame 总是更便宜/更快。
- 列表占用的内存更少,并且是一种更轻量级的数据结构,可用于处理、追加和删除。
dtypes
自动推断您的数据。另一方面,创建一个 NaN 的空帧会自动使它们成为 ,这很糟糕。object
- 系统会自动为您创建一个索引,而您不必注意将正确的索引分配给要追加的行。
这是积累数据的正确方法™
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()
这些选项太可怕了
在循环中
追加
或连接
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)
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]
证据在布丁中
对这些方法进行计时是了解它们在内存和实用性方面有多大差异的最快方法。
正是这样的帖子提醒了我为什么我是这个社区的一员。人们明白教人们用正确的代码获得正确答案的重要性,而不是用错误的代码获得正确的答案。现在,您可能会争辩说,使用它不是问题,或者如果您只向 DataFrame 添加一行。然而,人们经常在这个问题上添加不止一行 - 通常要求是使用来自函数的数据在循环中迭代添加一行(参见相关问题)。在这种情况下,重要的是要了解迭代增长 DataFrame 不是一个好主意。loc
append
评论
如果 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)
评论
如果您有一个数据框,并且想要将列表作为新行添加到 ,则只需执行以下操作即可:df
new_list
df
df.loc[len(df)] = new_list
如果要在 Data Frame 下添加新的数据框,则可以使用:new_df
df
df.append(new_df)
如果您总是想在末尾添加新行,请使用以下命令:
df.loc[len(df)] = ['name5', 9, 0]
评论
df.reset_index()
以下是 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()
df
df.astype(copy=False)
如果您不想显式设置索引,请使用例如 .请注意,如果为空,则失败。df.loc[df.index.max() + 1, :] = additional_row
df.index.max()
df
不幸的是,如何向 pandas 数据帧添加额外的行已被标记为重复并指向此问题。这篇文章的标题“一次附加一行”意味着定期向 DataFrame 添加多行是一个好主意。我同意以前的许多评论,即这可能没有很多用例。但是,向 DataFrame 添加单行的频率更高,即使它仍然是边缘情况。
评论