pandas指定滑动窗口计算

【pandas 滑动窗口rolling函数的改进】我现在有一个A股个股两年内每分钟的行情数据df,其中df的columns为['close','open','high','low'],index为 [‘20200104 09:30:00','20200104 09:31:00' 等等] ,我现在需要计算特定时间对应的滑动窗口的均值,比如每天的 14:00:00对应的前300条数据对应的高开低收对应的均值,目前的做法是先计算每分钟对应的滑动窗口的均值,再筛选出14:00:00的数据, df_rolling_mean = df.rolling(300).mean(),result = df_rolling_mean.at_time('14:00:00')。 但是这样存在一个问题,每分钟都要计算滑动窗口的均值,浪费了大量的算力,我只需要计算每天的 14:00:00对应的前300分钟的均值即可,怎么样能再缩短时间?
目前遇到的问题:1.每天的1分钟数据只有240条,如果先按天分组,计算前300条或者更长滑动窗口数据的化会丢失数据。2. 改进后,计算速度要比 df_rolling_mean = df.rolling(300).mean(),result = df_rolling_mean.at_time('14:00:00') 更快,要不然改进就没有意义了
主要诉求是提升计算速度,真实场景是在上百万条数据,计算每个截面rolling后聚合的结果速度太慢,rolling的底层好像是numpy还是Arrow格式,只要提升速度的话,不用rolling,用pandas的其他方法也可以
按天分组的回答都算了,答案请附上两种方案的耗时。

引用 皆我百晓生 小程序回复内容作答:
针对你的需求,可以尝试两种方案来提升计算速度并避免对每分钟的数据都进行滑动窗口计算。

方案一:使用重采样
可以先使用重采样将数据按天进行聚合,然后再进行滑动窗口计算。这样可以避免每分钟都计算滑动窗口的均值。

# 将数据按天重采样并计算滑动窗口的均值
df_daily = df.resample('D').apply(lambda x: x.rolling(300).mean())

# 获取每天的 14:00:00 对应的前300分钟数据的均值
result = df_daily.between_time('14:00:00', '14:59:59').iloc[-1]

方案二:使用 rolling_apply 函数
可以使用 rolling_apply 函数结合自定义函数来实现滑动窗口的计算。该方法需要使用 numba 库来提高计算速度。

首先,定义一个自定义函数来计算滑动窗口的均值:

import numba as nb

@nb.jit(nopython=True)
def sliding_window_mean(arr):
    window_size = 300
    result = np.empty_like(arr)
    for i in range(len(arr)):
        start_idx = max(0, i-window_size+1)
        result[i] = np.mean(arr[start_idx:i+1])
    return result

然后,使用 rolling_apply 函数应用自定义函数到数据上:

import pandas as pd
import numpy as np

# 创建时间序列数据,示例数据
index = pd.date_range('2020-01-01', periods=1000000, freq='min')
data = np.random.rand(1000000)
df = pd.DataFrame(data, index=index, columns=['value'])

# 运用自定义函数计算滑动窗口的均值
df['rolling_mean'] = pd.rolling_apply(df['value'].values, window=300, func=sliding_window_mean)

# 获取每天的 14:00:00 对应的前300分钟数据的均值
result = df.between_time('14:00:00', '14:59:59').iloc[-1]['rolling_mean']

两种方案的计算耗时可以根据你的数据大小和机器性能进行测试,因为实际情况可能会有所不同。

按天分组,计算每天的滑动窗口均值,然后再用between_time获取具体时间的均值

结合GPT给出回答如下请题主参考
为了提供更准确的答案,需要先理解一下问题的意思。

根据问题描述,可以得知数据框df的结构为:

import pandas as pd

# 假设数据已经被加载到了df中
df = pd.read_csv('a_stock_data.csv')

print(df.head())
# 输出前5行数据
#                        datetime  close   open   high    low
# 0  2020-01-01 09:30:00.00000000   10.0   11.1   11.2   9.9
# 1  2020-01-01 09:31:00.00000000   10.1   10.2   10.3   9.8
# 2  2020-01-01 09:32:00.00000000   10.2   10.3   10.4   9.7
# 3  2020-01-01 09:33:00.00000000   10.3   10.2   10.5   9.6
# 4  2020-01-01 09:34:00.00000000   10.4   10.3   10.6   9.5

其中,每一行数据是一个时间点的行情数据,包括收盘价、开盘价、最高价和最低价。现在需要进行滑动窗口计算,对每个时间点的最近K个时间点的收盘价、开盘价、最高价和最低价进行一些计算。

下面是一个示例代码,可以对每个时间点的最近5个时间点的收盘价做均值和方差的计算。

import pandas as pd

# 假设数据已经被加载到了df中
df = pd.read_csv('a_stock_data.csv')

# 将datetime列设置为索引列
df.set_index('datetime', inplace=True)

# 滑动窗口为5个时间点
rolling_window = 5

# 对收盘价进行滑动窗口计算
df['close_mean'] = df['close'].rolling(window=rolling_window).mean()
df['close_var'] = df['close'].rolling(window=rolling_window).var()

# 输出计算结果
print(df.head(10))

在该示例代码中,我们将datetime列设置为索引列,然后使用rolling函数执行滑动窗口计算,来对收盘价进行均值和方差的计算。其中,参数window指定了滑动窗口的大小。

输出的计算结果示例:

                         close   open   high    low  close_mean  close_var
datetime                                                                  
2020-01-01 09:30:00.00000000   10.0   11.1   11.2   9.9         NaN        NaN
2020-01-01 09:31:00.00000000   10.1   10.2   10.3   9.8         NaN        NaN
2020-01-01 09:32:00.00000000   10.2   10.3   10.4   9.7         NaN        NaN
2020-01-01 09:33:00.00000000   10.3   10.2   10.5   9.6         NaN        NaN
2020-01-01 09:34:00.00000000   10.4   10.3   10.6   9.5        10.2   0.200000
2020-01-01 09:35:00.00000000   10.5   10.4   10.7   9.4        10.3   0.200000
2020-01-01 09:36:00.00000000   10.6   10.5   10.8   9.3        10.4   0.200000
2020-01-01 09:37:00.00000000   10.7   10.6   10.9   9.2        10.5   0.200000
2020-01-01 09:38:00.00000000   10.8   10.7   11.0   9.1        10.6   0.200000
2020-01-01 09:39:00.00000000   10.9   10.8   11.1   9.0        10.7   0.200000

根据需要,使用类似的方式,可以对其他的列也进行滑动窗口计算。注意,需要根据具体的需求来调整滑动窗口的大小。需要根据内存容量及计算能力做出适当的权衡。

【以下回答由 GPT 生成】

解决方案:

为了实现更快速的计算特定时间的滑动窗口均值,我们可以使用以下方法:

  1. 将索引列转换为日期时间类型:

    python df.index = pd.to_datetime(df.index)

  2. 按日期进行分组:

    python grouped = df.groupby(df.index.date)

  3. 使用rolling函数对每个分组进行滑动窗口计算:

    python rolling_means = grouped['high', 'open', 'low', 'close'].rolling('300T').mean()

  4. 将计算结果合并到一个新的DataFrame中:

    python result = pd.concat([rolling_means.xs('14:00:00', level=1) for _, rolling_means in rolling_means.groupby(level=0)], keys=grouped.groups.keys(), names=['date'])

下面是完整的代码:

import pandas as pd

# 将索引列转换为日期时间类型
df.index = pd.to_datetime(df.index)

# 按日期进行分组
grouped = df.groupby(df.index.date)

# 使用rolling函数对每个分组进行滑动窗口计算
rolling_means = grouped['high', 'open', 'low', 'close'].rolling('300T').mean()

# 将计算结果合并到一个新的DataFrame中
result = pd.concat([rolling_means.xs('14:00:00', level=1) for _, rolling_means in rolling_means.groupby(level=0)], keys=grouped.groups.keys(), names=['date'])

这样,我们就可以在避免每分钟计算滑动窗口均值的同时,快速得到特定时间的滑动窗口均值。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

可以试一下这两个方法

import pandas as pd

# 假设df是您的原始数据框
# 假设您有一个时间索引,并将其转换为Datetime类型
df.index = pd.to_datetime(df.index)

# 1. 按天分组并计算滑动窗口均值
df_daily = df.resample('D').apply(lambda x: x.rolling(300).mean())

# 2. 自定义滑动窗口函数
def custom_rolling_mean(series):
    return series.rolling(300).mean()

# 找到每天的14:00:00所在的位置
daily_1400 = df.between_time('14:00:00', '14:00:00')

# 计算每天的滑动窗口均值
result = daily_1400.apply(custom_rolling_mean)


你只要计算特定时间段的平均值,就不要使用滑动窗口算法。直接定位到2点这个时间段然后往前数300条数据,然后计算平均值即可。

使用pandas实现滑动窗口
可以参考下


python滚动计算 pandas滚动计算_mob6454cc6aab12的技术博客_51CTO博客 python滚动计算 pandas滚动计算,这个函数的主要作用是根据时间(天,月,季度,年等)去看看数据的变化趋势,是下降了还是上升了,最后还要分析趋势的原因,结合业务逻辑去分析可以根据某个时间周期,计算数据的变化,主要用于时间序列上面DataFrame.rolling(window,min_periods=None,center=False,win_type=None,on=None,axis=0,closed=N https://blog.51cto.com/u_16099230/7061434

只要计算每天14点之后300分钟的均值,不用通过滑动窗口计算均值了