2013-03-14 228 views
13

對於python/pandas,我發現df.to_csv(fname)的工作速度爲每分鐘約100萬行。我有時可以將性能提高7倍,如下所示:將大型DataFrame輸出到CSV文件的最快方法是什麼?

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 ? 

注:我測試使用本地驅動器上的大熊貓0.9.1完成在Linux服務器。

+0

我剛剛使用內置的to_excel,然後使用to_csv DataFrame方法從DataFrame組中以批量方式導出約1.7K報告,並且部分報告(特別是較大的文件)出現損壞。我現在對這些內置程序頗感懷疑,並計劃爲我的工作流程自行創建自己的導出功能。 – 2013-03-14 19:00:20

+2

@DavidMarx你能發佈一個損壞的文件,DataFrame和你的代碼的例子嗎?這將有助於我們極大地調試問題。謝謝。 – 2013-03-14 23:16:24

+0

這是我爲我的辦公室設計的一種主力工具。我會看看我是否不能用對工作不敏感的數據複製問題。 – 2013-03-15 00:56:42

回答

1

您的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而不是直接輸出,然後每隔一段時間將其轉儲爲實際文件。

10

Lev。熊貓已經重寫了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 

所以吞吐量爲單個D型細胞(例如浮子),不能太寬爲約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 
+0

這是非常好的改進。謝謝。 – 2013-03-22 18:07:27

+2

對於這種類型的數據集,FWIW通常可以存儲在HDF5中,尤其是如果您有任何需要查詢,請參閱http://pandas.pydata.org/pandas-docs/dev/io.html#hdf5-pytables,以及http://pandas.pydata.org/pandas-docs/dev/cookbook.html#hdfstore – Jeff 2013-03-22 18:38:20

+0

我試圖輸出一個100,000 * 100,000的數據幀,這需要花費很長時間...... =( – alvas 2016-11-29 04:52:29

2

使用塊大小。我發現這讓地獄變得非常不同。如果你手頭有內存,可以使用很好的chunksize(行數不要)進入內存,然後再寫入一次。

+0

是默認的塊大小1或者某個東西?你使用什麼樣的塊?它對我來說似乎沒有什麼不同,甚至設置chunksize = 500000 – wordsforthewise 2017-10-28 23:16:18

+1

發現它,它可能是1 ... https://github.com/pandas-dev/pandas/blob /v0.20.3/pandas/io/formats/format.py#L1555 – wordsforthewise 2017-10-28 23:19:29

+0

@wordsforthewise如果列數> 100000,chunksize只有1,否則它是100000 //列數 – Matt 2017-11-23 08:50:40

相關問題