python/pandasの場合、df.to_csv(fname)は1分あたり約1 mln行の速度で動作することがわかります。このような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
注:パフォーマンスの向上は、dtypeによって異なります。しかし、(少なくとも私のテストでは)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(例:float)のスループットは約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を使用すると、時間を2倍に短縮できます。もちろん、これには柔軟性の低下が伴います(_aa.to_csv
_と比較した場合)。
Python 3.7、pandas 0.23.4、numpy 1.15.2(xrange
はrange
Python 3)の質問からの投稿された関数。
PS。インデックスを含める必要がある場合、savetxt
は問題なく機能します。df.rest_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
を使用して、たまに実際のファイルにダンプすることができます。