我定义了两个将在我的程序中反复使用的函数:
第一个函数是将字符串转换为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方法。反正有加速吗?谢谢
答案 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_times
到find_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]
是布尔掩码,因此新数据帧df
从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()
成为视图,请使用
{{1}}