从这个question和其他人看来,似乎不建议使用concat
或append
来构建pandas数据帧,因为它每次都会重新复制整个数据帧。
我的项目涉及每30秒检索一小部分数据。这可能会持续3天的周末,因此有人可以轻易地期望一次创建超过8000行。向此数据框添加行的最有效方法是什么?
答案 0 :(得分:35)
我使用了这个答案的df.loc[i] = [new_data]
建议,但我有> 500,000行,这非常慢。
虽然给出的答案对OP的问题有好处,但我发现它更有效率,在前面处理大量行(而不是OP描述的欺骗行为)时使用csvwriter来添加数据到内存中的CSV对象,然后最后使用pandas.read_csv(csv)
生成所需的DataFrame输出。
from io import BytesIO
from csv import writer
import pandas as pd
output = BytesIO()
csv_writer = writer(output)
for row in iterable_object:
csv_writer.writerow(row)
output.seek(0) # we need to get back to the start of the BytesIO
df = pd.read_csv(output)
return df
这对于~500,000行来说快了1000倍,随着行数增加,速度提升只会变大(the df.loc[1] = [data]
相对来说会慢得多)
希望这可以帮助那些在处理比OP更多行时需要效率的人。
答案 1 :(得分:17)
您可以使用loc
在不存在的索引上就地向DataFrame添加行。来自Pandas documentation:
In [119]: dfi
Out[119]:
A B C
0 0 1 0
1 2 3 2
2 4 5 4
In [120]: dfi.loc[3] = 5
In [121]: dfi
Out[121]:
A B C
0 0 1 0
1 2 3 2
2 4 5 4
3 5 5 5
正如预期的那样,使用loc
要比append
(大约14倍)快得多:
import pandas as pd
df = pd.DataFrame({"A": [1,2,3], "B": [1,2,3], "C": [1,2,3]})
%%timeit
df2 = pd.DataFrame({"A": [4], "B": [4], "C": [4]})
df.append(df2)
# 1000 loops, best of 3: 1.61 ms per loop
%%timeit
df.loc[3] = 4
# 10000 loops, best of 3: 113 µs per loop
答案 2 :(得分:2)
您需要将问题分为两部分:
如果您的数据很关键(也就是说,您不能丢失它) - 将其发送到队列,然后批量从队列中读取它。
队列将提供可靠(保证)接受,并且您的数据不会丢失。
您可以从队列中读取数据并将其转储到数据库中。
现在,您的Python应用程序只是从数据库中读取数据,并以适合应用程序的任何时间间隔进行分析 - 也许您希望按小时平均值进行分析;在这种情况下,您将每小时运行一次脚本以从数据库中提取数据,并可能将结果写入另一个数据库/表/文件中。
底线 - 分割收集和分析应用程序的部分。
答案 3 :(得分:1)
假设您的数据帧已按顺序编入索引,则您可以:
首先检查下一个索引值是什么以创建新行:
myindex = df.shape[0]+1
然后使用'at'写入每个所需的列
df.at[myindex,'A']=val1
df.at[myindex,'B']=val2
df.at[myindex,'C']=val3
答案 4 :(得分:1)
汤姆·哈维的反应很好。但是,我想基于pandas.DataFrame.from_dict添加一个更简单的答案。
通过将一行中的数据添加到列表中,然后将此列表添加到字典中,然后可以使用pd.DataFrame.from_dict(dict)
创建一个数据框而无需迭代。
如果字典的每个值都是一行。您可以只使用:
pd.DataFrame.from_dict(dictionary,orient='index')
小例子:
# Dictionary containing the data
dic = {'row_1':['some','test','values',78,90],'row_2':['some','test','values',100,589]}
# Creation of the dataframe
df = pd.DataFrame.from_dict(dic,orient='index')
df
0 1 2 3 4
row_1 some test values 78 90
row_2 some test values 100 589
答案 5 :(得分:0)
sundance 的回答在用法上可能是正确的,但基准测试是错误的。 正如 moobie 正确指出的那样,在此示例中已经存在索引3,这使访问方式比不存在索引时更快。看看这个:
%%timeit
test = pd.DataFrame({"A": [1,2,3], "B": [1,2,3], "C": [1,2,3]})
for i in range(0,1000):
testrow = pd.DataFrame([0,0,0])
pd.concat([test[:1], testrow, test[1:]])
每个循环2.15 s±88毫秒(平均±标准偏差,共7次运行,每个循环1次)
%%timeit
test = pd.DataFrame({"A": [1,2,3], "B": [1,2,3], "C": [1,2,3]})
for i in range(0,1000):
test2 = pd.DataFrame({'A': 0, 'B': 0, 'C': 0}, index=[i+0.5])
test.append(test2, ignore_index=False)
test.sort_index().reset_index(drop=True)
每循环972 ms±14.4 ms(平均±标准偏差,共运行7次,每个循环1次)
%%timeit
test = pd.DataFrame({"A": [1,2,3], "B": [1,2,3], "C": [1,2,3]})
for i in range(0,1000):
test3 = [0,0,0]
test.loc[i+0.5] = test3
test.reset_index(drop=True)
每个循环1.13 s±46毫秒(平均±标准偏差,共7次运行,每个循环1次)
当然,这纯粹是综合的,我承认并没有期望得到这些结果,但是似乎在不存在索引的情况下,.loc
和.append
的表现非常相似。只是把它留在这里。
答案 6 :(得分:0)
我从SQL Server返回了70万行数据。 以上所有事情对我来说都花费了很长时间。 以下方法可以大大节省时间。
from collections import defaultdict
dict1 = defaultdict(list)
for row in results:
dict1['column_name1'] = row['column_name1']
dict1['column_name20'] = row['column_name20']
df = pd.DataFrame(dict1)
这就是我所需要的。