在大循环中优化时间熊猫to_csv

时间:2019-11-22 12:33:41

标签: python pandas

我正在使用400.000行数据框(实际上是更大的数据框,但出于测试目的,我使用此维度)。

我需要根据两个条件将多个文件导出到txt / csv:#RIC和日期。

围绕这些条件变得非常缓慢,因此,我正在寻找更快的方法来实现这一目标。

这是我的初衷:

def SaveTxt(df, output_folder=None):

# Start time
start_time = time.time()
# Data Frame with date
df['Date'] = pd.to_datetime(df['Date-Time']).dt.date
dates = df['Date'].unique()
ticks = df['#RIC'].unique()

for tick in ticks:
    for date in dates:
        # print(date, tick)
        # Filtering by instrument and date
        temp_df = df[(df['#RIC'] == tick) & (df['Date'] == date)]
        if temp_df.empty:
            pass
        else:
            # Saving files
            if output_folder in [None, ""]:
                temp_df.to_csv("%s_%s.txt" % (date, tick))
            else:
                temp_df.to_csv("%s\\%s_%s.txt" % (output_folder, date, tick))


# Elapsed time
elapsed_time = time.time() - start_time
elapsed_time = time.strftime("%H:%M:%S", time.gmtime(elapsed_time))
# Priting elapsed time
print('Elapsed time: %s' % elapsed_time)

对于400.000行(相当于5天的数据),运行此脚本需要3分钟。一年下来,花了6个小时,而我没有尝试10年,但是我认为这不是一个好主意。

解决方案

我试图从 df 中删除每个循环中使用的数据,但是这种情况不起作用(也许这将删除数据帧的大小并加快代码的速度):

df = df[(df['#RIC'] != tick) & (df['Date'] != date)]

我认为这应该删除数据框中的每个滴答和日期,但它是单独应用此条件的。

如果您能解决此问题,我将不胜感激。

谢谢

修改

不知道这是否是共享数据样本的最佳方法(我无法通过代理上传)


#RIC    Date       Price    Volume
DIJF21  16/10/2019  4.64    15
DIJF21  16/10/2019  4.64    40
DIJF21  16/10/2019  4.64    100
DIJF21  16/10/2019  4.64    5
DIJF21  16/10/2019  4.64    1765
DIJF21  16/10/2019  4.64    10
DIJF21  16/10/2019  4.64    100
DIJF21  16/10/2019  4.64    1000
DIJF21  16/10/2019  4.64    5
DIJF21  16/10/2019  4.64    20
DIJF21  16/10/2019  4.64    80
DIJF21  16/10/2019  4.64    25
DIJF21  16/10/2019  4.64    25
DIJF21  16/10/2019  4.64    150
DIJF20  15/10/2019  4.905   2000
DIJF20  15/10/2019  4.905   2000
DIJF20  15/10/2019  4.903   10

3 个答案:

答案 0 :(得分:4)

我建议您考虑使用协程 https://docs.python.org/3/library/asyncio-task.html

类似的东西:

import asyncio


df['Date'] = pd.to_datetime(df['Date-Time']).dt.date
dates = df['Date'].unique()
ticks = df['#RIC'].unique()


async def tick_func(tick):
    for date in dates:
        temp_df = df[(df['#RIC'] == tick) & (df['Date'] == date)]
        if temp_df.empty:
            pass
        else:
            if output_folder in [None, ""]:
                temp_df.to_csv("%s_%s.txt" % (date, tick))
            else:
                temp_df.to_csv("%s\\%s_%s.txt" % (output_folder, date, tick))



asyncio.new_event_loop()
asyncio.set_event_loop(asyncio.new_event_loop())
loop = asyncio.get_event_loop()
tasks = [tick_func(tick) for tick in ticks]
loop.run_until_complete(asyncio.gather(*tasks))
loop.close()

答案 1 :(得分:1)

我快速地回答了这个问题,似乎瓶颈是用于将数据按fortick分组的双重嵌套date循环。

也许您可以考虑使用groupby function在单个函数调用中执行groupby操作。代码看起来像这样:

grouped_df = df.groupby(['#RIC', 'Date'])

打印grouped_df以确保它看起来像您期望的样子。然后,您可以遍历此分组的数据帧一次,然后将不同的组保存到文件系统中(根据需要)。

请告诉我这是否可行,或者您是否遇到任何其他问题。

编辑:要跟踪@Thales注释,有一些online resources讨论了如何将大型数据帧保存到csv文件中。从这些资源中,我喜欢使用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

答案 2 :(得分:1)

事先提供数据样本以测试答案将很有帮助。像这样,我只是希望它能正常工作;)

您应该能够将groupby与自定义函数一起使用,该自定义函数将应用于每个组,如下所示:

def custom_to_csv(temp_df, output_folder):
    date, tick = temp_df.name
    # Saving files
    if output_folder in [None, ""]:
        temp_df.to_csv("%s_%s.txt" % (date, tick))
    else:
        temp_df.to_csv("%s\\%s_%s.txt" % (output_folder, date, tick))

df.groupby(['Date', '#RIC']).apply(custom_to_csv, (output_folder))

编辑:已更改 dftemp_df(output_folder,)(output_folder)