可能加快大熊猫的速度

时间:2015-01-20 01:22:13

标签: python performance pandas dataframe cython

我定义了两个将在我的程序中反复使用的函数:

第一个函数是将字符串转换为datetime,第二个函数是读取csv文件并在事件发生前提取一个值,在事件发生后立即提取一个值,并在事件发生后返回其余数据帧。 / p>

def to_timestamp(timestr):
   return datetime.datetime.strptime(timestr,'%H:%M:%S.%f')
def find_values(df,ticker,event_time):
   df=pd.read_csv(ticker+'.csv',sep=',')
   df['Time'] = df['Timestamp'].apply(to_timestamp)
   df_earlier = df[df['Time']<=newstime]
   df_later = df[df['Time']>newstime]
   price_1=df_earlier['Price'].iloc[-1]
   price_2=df_later['Price'].iloc[0]
   return (price_1,Price_2,df_later)

csv文件具有以下形式:

     Timestamp,       Price 
   04:15:01.274, 35.50
   04:15:01.353, 35.71
   04:15:05.184, 37.37
   05:36:25.240, 37.60
   05:44:40.678, 36.51
   …

这两个函数都有效,但如果我在数千个csv文件中使用它们,它们会非常慢。我认为主要的瓶颈是apply方法。反正有加速吗?谢谢

1 个答案:

答案 0 :(得分:2)

def find_values(ticker, event_time):
    filename = ticker+'.csv'
    df = pd.read_csv(filename, parse_dates=[0])
    idx = df['Timestamp'].searchsorted(event_time, side='right')
    price_1, price_2 = df['Price'].iloc[idx-1:idx+1]
    df_later = df.iloc[idx:]
    return price_1, price_2, df_later

例如,使用您发布的数据:

In [176]: p1, p2, df_later = find_values('ABC', pd.Timestamp('4:15:03'))

In [177]: p1, p2
Out[177]: (35.710000000000001, 37.369999999999997)

In [178]: df_later
Out[178]: 
                   Timestamp  Price
2 2015-01-19 04:15:05.184000  37.37
3 2015-01-19 05:36:25.240000  37.60
4 2015-01-19 05:44:40.678000  36.51

如果csv很大,解析csv可能会很昂贵。因此,你不想要 如果您可以提供帮助,请多次致电pd.read_csv。通过扩展,你 每个自动收报机不应多次拨打find_values。如果你确实需要 对同一个自动收报机不止一次致电find_values,需要考虑 如何重新编写算法,以便理想地调用pd.read_csv 只有一次。缓存pd.read_csv返回的值可能是一种方式,或 收集event_timesfind_values的一个电话可能是另一个 方式。

现在假设你已经吝啬地调用了find_values,让我们继续讨论如何提高它的速度。

你是对的,在这里使用apply也是一个潜在的瓶颈,因为它为数据帧的每一行调用一次Python函数。您可以改为使用to_timestamp的内置日期字符串解析功能,而不是使用pd.read_csv解析时间字符串:

df = pd.read_csv(filename, parse_dates=[0])

这会将第0个索引列解析为日期字符串。这将使 df['Timestamp']一个dtype为datetime64[ns]的列。 这太棒了,因为它使找到event_time(我假设与newstime相同)的索引很容易融入df['Timestamp']。此外,日期计算通常可以在datetime64s上执行得比在Python datetime.datetime对象上完成的等效计算快得多。

要查找适合event_time的整数索引,请使用the searchsorted method

idx = df['Timestamp'].searchsorted(event_time)

idx将是event_time的整数索引,如果要将其df['Timestamp']插入df['Timestamp'],同时保持df_earlier = df[df['Time']<=newstime] 的排序。


接下来,请注意使用

df['Time']<=newstime

也很昂贵,因为它形成(可能很大的)数据帧只是为了挑选一个值。由于df[df['Time']<=newstime]是布尔掩码,因此新数据帧dfprice_1, price_2 = df['Price'].iloc[idx-1:idx+1] 生成副本数据。这是很多不必要的复制。

相反,您可以使用

df_later = df.iloc[idx:]

只需选择您想要的值而无需额外的复制。

最后,您可以使用

df_later

定义df_later。由于这使用基本切片而不是布尔掩码,df df[df['Time']>event_time]的视图。生成速度比df_later更快,因为没有复制。但请注意,这意味着df中的基础数据与df_later下面的数据完全相同。因此,修改df也会修改df_later,反之亦然。如果您不希望df_later = df.iloc[idx:].copy() 成为视图,请使用

{{1}}