如何用Python按连续3天增减趋势为DataFrame分组?
连续3天趋势分组与分段斜率实现方案
直接上可运行的代码与逻辑拆解:
1. 准备数据与标记每日趋势
用diff()计算每日数值变化,生成趋势标记列:
import pandas as pd import numpy as np from sklearn.linear_model import LinearRegression # 示例数据 df = pd.DataFrame({ 'date': pd.date_range('2022-09-01', periods=10), 'value': [10, 8, 6, 7, 9, 12, 10, 8, 7, 9] }) # 标记每日趋势:1=上升,-1=下降,0=持平 df['trend'] = df['value'].diff().map(lambda x: 1 if x > 0 else (-1 if x < 0 else 0))
2. 识别连续3天趋势并生成分组
核心思路是先找出连续相同趋势的"块",再筛选出长度≥3的块作为分组分界,最后统一分组编号:
# 标记连续相同趋势的块(每次趋势变化则块编号+1) df['trend_block'] = (df['trend'] != df['trend'].shift()).cumsum() # 计算每个块的长度 df['block_len'] = df.groupby('trend_block')['trend'].transform('count') # 标记需要独立分组的块:长度≥3的上升/下降块 df['is_valid_group'] = (df['block_len'] >= 3) & (df['trend'] != 0) # 生成最终分组编号:每个有效块对应唯一分组,无效块归为0 df['group'] = df['is_valid_group'].cumsum() # 把同一趋势块内的行统一为该块的分组编号 df['group'] = df.groupby('trend_block')['group'].transform('max').fillna(0).astype(int)
3. 计算分段线性斜率
对每个分组用线性回归拟合斜率,将日期转换为距离分组起始日的天数作为自变量:
def get_segment_slope(group): # 将分组内的日期转为连续数值(第0天、第1天...) X = np.arange(len(group)).reshape(-1, 1) y = group['value'].values reg = LinearRegression(fit_intercept=True) reg.fit(X, y) return reg.coef_[0] # 计算每个分组的斜率并合并回原表 slope_df = df.groupby('group').apply(get_segment_slope).reset_index(name='segment_slope') df = df.merge(slope_df, on='group', how='left')
关键逻辑说明
- 趋势块标记:通过
trend != trend.shift()判断趋势是否变化,累积计数得到每个连续趋势的块ID - 有效分组筛选:只有长度≥3的上升/下降块才会触发新分组,持平块不会触发分组拆分
- 斜率计算:用简单线性回归拟合每个分组内的数值变化,得到分段斜率
自定义调整点
- 如果需要忽略持平(即把持平视为延续之前的趋势),可以先把
trend中的0替换为前一个非0值:df['trend'] = df['trend'].replace(0, method='ffill') - 若希望未达到3天连续趋势的初始数据单独分组,可调整
group的初始值逻辑
内容的提问来源于stack exchange,提问作者dana
相关产品推荐
相关产品推荐

