[英]What is the fastest way to output large DataFrame into a CSV file?
對於 python/pandas,我發現 df.to_csv(fname) 以每分鍾約 100 萬行的速度工作。 我有時可以像這樣將性能提高 7 倍:
def df2csv(df,fname,myformats=[],sep=','):
"""
# function is faster than to_csv
# 7 times faster for numbers if formats are specified,
# 2 times faster for strings.
# Note - be careful. It doesn't add quotes and doesn't check
# for quotes or separators inside elements
# We've seen output time going down from 45 min to 6 min
# on a simple numeric 4-col dataframe with 45 million rows.
"""
if len(df.columns) <= 0:
return
Nd = len(df.columns)
Nd_1 = Nd - 1
formats = myformats[:] # take a copy to modify it
Nf = len(formats)
# make sure we have formats for all columns
if Nf < Nd:
for ii in range(Nf,Nd):
coltype = df[df.columns[ii]].dtype
ff = '%s'
if coltype == np.int64:
ff = '%d'
elif coltype == np.float64:
ff = '%f'
formats.append(ff)
fh=open(fname,'w')
fh.write(','.join(df.columns) + '\n')
for row in df.itertuples(index=False):
ss = ''
for ii in xrange(Nd):
ss += formats[ii] % row[ii]
if ii < Nd_1:
ss += sep
fh.write(ss+'\n')
fh.close()
aa=DataFrame({'A':range(1000000)})
aa['B'] = aa.A + 1.0
aa['C'] = aa.A + 2.0
aa['D'] = aa.A + 3.0
timeit -r1 -n1 aa.to_csv('junk1') # 52.9 sec
timeit -r1 -n1 df2csv(aa,'junk3',myformats=['%d','%.1f','%.1f','%.1f']) # 7.5 sec
注意:性能的提高取決於 dtypes。 但是,to_csv() 的執行速度比未優化的 Python 慢得多,這始終是正確的(至少在我的測試中)。
如果我有一個 4500 萬行的 csv 文件,那么:
aa = read_csv(infile) # 1.5 min
aa.to_csv(outfile) # 45 min
df2csv(aa,...) # ~6 min
問題:
What are the ways to make the output even faster?
What's wrong with to_csv() ? Why is it soooo slow ?
注意:我的測試是在 Linux 服務器的本地驅動器上使用 pandas 0.9.1 完成的。
列夫。 Pandas 重寫了to_csv
以大幅提高原生速度。 該過程現在是 i/o 綁定的,說明了許多微妙的 dtype 問題和引用案例。 這是我們與 0.10.1(即將發布的 0.11)版本相比的性能結果。 這些以ms
,比率越低越好。
Results:
t_head t_baseline ratio
name
frame_to_csv2 (100k) rows 190.5260 2244.4260 0.0849
write_csv_standard (10k rows) 38.1940 234.2570 0.1630
frame_to_csv_mixed (10k rows, mixed) 369.0670 1123.0412 0.3286
frame_to_csv (3k rows, wide) 112.2720 226.7549 0.4951
因此,單個 dtype(例如浮點數)的吞吐量,不太寬,大約為 20M 行/分鍾,這是上面的示例。
In [12]: df = pd.DataFrame({'A' : np.array(np.arange(45000000),dtype='float64')})
In [13]: df['B'] = df['A'] + 1.0
In [14]: df['C'] = df['A'] + 2.0
In [15]: df['D'] = df['A'] + 2.0
In [16]: %timeit -n 1 -r 1 df.to_csv('test.csv')
1 loops, best of 1: 119 s per loop
在 2019 年,對於這樣的情況,最好只使用 numpy。 看時間:
aa.to_csv('pandas_to_csv', index=False)
# 6.47 s
df2csv(aa,'code_from_question', myformats=['%d','%.1f','%.1f','%.1f'])
# 4.59 s
from numpy import savetxt
savetxt(
'numpy_savetxt', aa.values, fmt='%d,%.1f,%.1f,%.1f',
header=','.join(aa.columns), comments=''
)
# 3.5 s
因此,您可以使用 numpy 將時間減少兩倍。 當然,這是以降低靈活性為代價的(與aa.to_csv
相比)。
以 Python 3.7、pandas 0.23.4、numpy 1.15.2 為基准( xrange
被range
替換,以使問題中發布的函數在 Python 3 中工作)。
附注。 如果您需要包含索引, savetxt
可以正常工作 - 只需傳遞df.reset_index().values
並相應地調整格式字符串。
使用塊大小。 我發現這有很大的不同。 如果您手頭有內存,請使用良好的塊大小(行數)進入內存,然后寫入一次。
您的df_to_csv
函數非常好,除了它做了很多假設並且不適用於一般情況。
如果它對您有用,那很好,但請注意,這不是通用的解決方案。 CSV 可以包含逗號,那么如果要寫入這個元組會發生什么? ('a,b','c')
python csv
模塊會引用該值,以便不會出現混淆,並且如果任何值中存在引號,則會轉義引號。 當然,生成在所有情況下都有效的東西要慢得多。 但我想你只有一堆數字。
你可以試試這個,看看它是否更快:
#data is a tuple containing tuples
for row in data:
for col in xrange(len(row)):
f.write('%d' % row[col])
if col < len(row)-1:
f.write(',')
f.write('\n')
不知道這樣會不會更快。 如果不是,那是因為完成了太多的系統調用,因此您可能會使用StringIO
而不是直接輸出,然后每隔一段時間將其轉儲到真實文件中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.