可能加速 pandas 申请
possible speed up of pandas apply
我定义了两个将在我的程序中反复使用的函数:
第一个函数是将字符串转为日期时间,第二个函数是读取一个csv文件,提取事件发生前的一个值和事件后的一个值,return其余数据事件后的框架。
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 方法。有没有办法加快速度?谢谢
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_times
收集到对 find_values
的一次调用中可能是另一个
现在假设您已经在节俭地调用 find_values
,让我们继续讨论如何提高它的速度。
你是对的,在这里使用 apply
也是一个潜在的瓶颈,因为它为数据帧的每一行调用一次 Python 函数。您可以使用 pd.read_csv
的内置日期字符串解析功能,而不是使用 to_timestamp
解析时间字符串:
df = pd.read_csv(filename, parse_dates=[0])
这会将第 0 个索引列解析为日期字符串。这将使
df['Timestamp']
数据类型为 datetime64[ns]
的列。
这太棒了,因为它可以很容易地找到 event_time
(我假设它与 newstime
相同)适合 df['Timestamp']
的索引。此外,与在 Python datetime.datetime
对象上进行的等效计算相比,在 datetime64s 上执行日期计算通常要快得多。
要找到适合 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]
从 df
中复制了一个 copy 数据。这是很多不必要的复制。
相反,您可以使用
price_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()
我定义了两个将在我的程序中反复使用的函数:
第一个函数是将字符串转为日期时间,第二个函数是读取一个csv文件,提取事件发生前的一个值和事件后的一个值,return其余数据事件后的框架。
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 方法。有没有办法加快速度?谢谢
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_times
收集到对 find_values
的一次调用中可能是另一个
现在假设您已经在节俭地调用 find_values
,让我们继续讨论如何提高它的速度。
你是对的,在这里使用 apply
也是一个潜在的瓶颈,因为它为数据帧的每一行调用一次 Python 函数。您可以使用 pd.read_csv
的内置日期字符串解析功能,而不是使用 to_timestamp
解析时间字符串:
df = pd.read_csv(filename, parse_dates=[0])
这会将第 0 个索引列解析为日期字符串。这将使
df['Timestamp']
数据类型为 datetime64[ns]
的列。
这太棒了,因为它可以很容易地找到 event_time
(我假设它与 newstime
相同)适合 df['Timestamp']
的索引。此外,与在 Python datetime.datetime
对象上进行的等效计算相比,在 datetime64s 上执行日期计算通常要快得多。
要找到适合 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]
从 df
中复制了一个 copy 数据。这是很多不必要的复制。
相反,您可以使用
price_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()