You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R语言中仅对同类别连续行进行数据分组聚合

问题描述

我有如下模拟数据框:

df_in <- data.frame(
  time = c(1,2,3,4,5,6,7,8,9,10),
  state = c(1,1,1,2,2,3,1,1,1,2),
  returns = c(0.5,0.2,0.3,0.4,0.1,0.2,1.1,0.8,0.5,0.2)
)

数据预览:

time state returns
1     1     1     0.5
2     2     1     0.2
3     3     1     0.3
4     4     2     0.4
5     5     2     0.1
6     6     3     0.2
7     7     1     1.1
8     8     1     0.8
9     9     1     0.5
10   10     2     0.2

我需要对数据做聚合:将同一state的连续行合并计算returns,优先用复利计算,若实现困难,简单求和也可。期望输出如下:

df_out <- data.frame(
  time_start = c(1,4,6,7,10),
  time_end = c(3,5,6,9,10),
  state = c(1,2,3,1,2),
  returns = c(1.0,0.5,0.2,2.4,0.2)
)

输出预览:

time_start time_end state returns
1          1        3     1     1.0
2          4        5     2     0.5
3          6        6     3     0.2
4          7        9     1     2.4
5         10       10     2     0.2

注:示例中用了简单求和,我更倾向于复利计算方案。我知道有类似的分组方法,但那些方法需要标识ID,我的数据里没有,希望用dplyr实现,我是dplyr新手,求帮助。


解决方案

核心是先给连续的同一state行创建分组标识,再按组聚合计算。

1. 简单求和版本

用dplyr生成连续分组后直接求和:

library(dplyr)

df_sum <- df_in %>%
  # 生成连续state的分组ID:当前行state和上一行不同时,分组ID+1
  mutate(group_id = cumsum(state != lag(state, default = first(state)))) %>%
  # 按分组ID和state聚合
  group_by(group_id, state) %>%
  summarise(
    time_start = first(time),
    time_end = last(time),
    returns = sum(returns),
    .groups = "drop"
  ) %>%
  # 移除临时分组ID列
  select(-group_id)

print(df_sum)

输出和你期望的df_out完全一致:

state time_start time_end returns
  <dbl>      <dbl>    <dbl>   <dbl>
1     1          1        3     1  
2     2          4        5     0.5
3     3          6        6     0.2
4     1          7        9     2.4
5     2         10       10     0.2

2. 复利计算版本(最优方案)

如果returns是每期收益率,总复利收益用prod(1 + returns) - 1计算;如果是绝对收益,直接用prod(returns)即可,这里按常规收益率逻辑处理:

df_compound <- df_in %>%
  mutate(group_id = cumsum(state != lag(state, default = first(state)))) %>%
  group_by(group_id, state) %>%
  summarise(
    time_start = first(time),
    time_end = last(time),
    # 复利计算总收益
    returns = prod(1 + returns) - 1,
    .groups = "drop"
  ) %>%
  select(-group_id)

print(df_compound)

输出结果:

state time_start time_end returns
  <dbl>      <dbl>    <dbl>   <dbl>
1     1          1        3   1.13 
2     2          4        5   0.54 
3     3          6        6   0.2  
4     1          7        9   3.48 
5     2         10       10   0.2  

关键逻辑说明

  • cumsum(state != lag(state, default = first(state))):这是生成连续分组的核心,通过对比当前行和上一行的state,只要不一样就累加计数,这样就能把连续相同的state分到同一个组里,避免合并非连续的相同state(比如示例中两次出现的state=1会被分成两个独立组)。
  • group_by(group_id, state):同时按分组ID和state分组,确保分组的准确性。

内容的提问来源于stack exchange,提问作者Theo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 12:20:42