首页 > 解决方案 > 如何快速子集许多数据帧?

问题描述

我有 180 个DataFrame对象,每个对象有 3130 行,内存大约 300KB。该指数为 2000年 1 月 3 日至 2011 年 12 月 31 日的DatetimeIndex工作日:

from datetime import datetime
import pandas as pd
freq = pd.tseries.offsets.BDay()

index = pd.date_range(datetime(2000,1,3), datetime(2011,12,31), freq=freq)

df = pd.DataFrame(index=index)
df['A'] = 1000.0
df['B'] = 2000.0
df['C'] = 3000.0
df['D'] = 4000.0
df['E'] = 5000.0
df['F'] = True
df['G'] = 1.0
df['H'] = 100.0

我利用 numpy/pandas 矢量化对所有数据进行预处理,然后我必须每天循环遍历数据帧。为了防止“前瞻性偏差”的可能性并从未来获取数据,我必须确保每天我只返回我的数据帧的一个子集,直到那个数据点。我解释:如果我正在处理的当前数据点是datetime(2010,5,15)我需要来自datetime(2000,1,3)to 的数据datetime(2010,5,15)。您应该无法访问比 更新的数据datetime(2010,5,15)。使用这个子集,我将进行其他无法矢量化的计算,因为它们是路径相关的。

我像这样修改了我的原始循环:

def get_data(datapoint):
    return df.loc[:datapoint]
    
calendar = df.index

for datapoint in calendar:
    x = get_data(datapoint)   

这种代码非常缓慢。提高速度的最佳选择是什么?如果我不尝试防止前瞻偏差,我的生产代码需要大约 3 分钟才能运行,但风险太大。使用这样的代码需要 13 分钟,这是不可接受的。

%%时间

一个稍快的选项是使用iloc而不是,loc但它仍然很慢:

def get_data2(datapoint):
    idx = df.index.get_loc(datapoint)
    return df.iloc[:idx]

for datapoint in calendar:
    x = get_data(datapoint)  

每个循环 371 毫秒 ± 23.2 毫秒(平均值 ± 标准偏差。7 次运行,每个循环 1 个)

for datapoint in calendar:
    x = get_data2(datapoint)

每个循环 327 毫秒 ± 7.05 毫秒(平均值 ± 标准偏差。7 次运行,每个循环 1 个)

原始代码并没有试图防止前瞻偏差的可能性,而是在DataFrame为每个数据点调用时简单地返回了整体。在这个例子中快 100 倍,实际代码快 4 倍。

def get_data_no_check():
    return df

for datapoint in calendar:
    x = get_data_no_check() 

每个循环 2.87 毫秒 ± 89.8 微秒(平均值 ± 标准偏差。7 次运行,每次 100 次循环)

标签: pythonpandasdataframenumpy

解决方案


看看这是否适合你:

datapoint_range = pd.date_range(datetime(2000,1,3), datetime.now(), freq=freq)
datapoint = datapoint_range[-1]

逻辑是:将结束日期替换为今天,以确保不是将来的日期。然后获取范围的最后日期。

然后用你的df.loc[:datapoint]来获得你想要的范围。


推荐阅读