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

如何按ID分组创建滚动Top3出行频次最高的国家列?

问题:按ID分组实现滚动Top3出行国家统计

我们有一个包含ID、Country、Date三列的DataFrame,记录人员的出行历史。需要新增Pref1、Pref2、Pref3三列,分别表示每行日期之前,对应ID人员出行次数最多的滚动Top3国家(次数相同时,优先选择最近出行的国家)。

示例输入数据:

mydata <- data.frame(
  ID = c('A1B1', 'A1B1', 'A1B1', 'A1B1', 'A1B1', 'A1B1', 'A1B1', 'A1B1', 'A2B2', 'A2B2', 'A2B2', 'A2B2', 'A2B2', 'A2B2'),
  Country = c('Japan', 'USA', 'USA', 'USA', 'Germany', 'Germany', 'Japan', 'France', 'UK', 'Spain', 'Spain', 'UK', 'UK', 'Brazil'),
  Date = as.Date(c('2010/01/02', '2010/04/18', '2011/03/22', '2011/11/23', '2012/05/09', '2012/09/11', '2014/01/06', '2015/12/11', '2010/04/03', '2010/05/11', '2011/05/01', '2012/03/01', '2013/01/03', '2014/01/04'))
)

期望输出的核心逻辑是:每一行的Top3只统计该行日期之前的出行记录,次数相同则按最近出行日期排序,不足3个的用NA填充。


解决方案(R语言实现)

我们可以用dplyr结合purrr来实现这个滚动统计,步骤清晰且容易理解:

  1. 先按ID分组,确保每组内的记录按Date升序排列(这一步是基础,保证我们处理的都是历史记录)
  2. 对每组内的每一行,提取该行之前的所有出行记录
  3. 统计这些历史记录中每个国家的出行次数,同时记录每个国家的最近出行日期
  4. 按「次数降序→最近日期降序」排序,取前3个国家作为Pref1-Pref3
  5. 将结果合并回原DataFrame,清理中间辅助列

完整代码如下:

library(dplyr)
library(purrr)

result <- mydata %>%
  arrange(ID, Date) %>%
  group_by(ID) %>%
  mutate(
    # 对每一行,获取该行之前的所有历史出行记录
    history = map(row_number(), ~ slice(cur_data(), 1:(.x - 1))),
    # 处理历史记录,生成符合要求的Top3国家列表
    top_countries = map(history, function(df) {
      if(nrow(df) == 0) {
        # 没有历史记录时直接返回3个NA
        return(c(NA, NA, NA))
      }
      # 统计每个国家的出行次数和最近出行日期
      df_summary <- df %>%
        group_by(Country) %>%
        summarise(
          count = n(),
          last_date = max(Date),
          .groups = "drop"
        ) %>%
        # 先按出行次数降序,次数相同则按最近日期降序排序
        arrange(desc(count), desc(last_date)) %>%
        pull(Country)
      # 填充到固定3个元素,不足的补NA
      c(df_summary[1:3], rep(NA, max(0, 3 - length(df_summary))))
    }),
    # 将Top3列表拆分为三列
    Pref1 = map_chr(top_countries, ~ .x[1]),
    Pref2 = map_chr(top_countries, ~ .x[2]),
    Pref3 = map_chr(top_countries, ~ .x[3])
  ) %>%
  # 移除中间生成的辅助列
  select(-history, -top_countries) %>%
  ungroup()

# 查看最终结果
print(result)

代码逻辑细节解释

  • arrange(ID, Date):确保每个ID的记录严格按时间顺序排列,这样处理每一行时,前面的记录都是更早的历史出行数据。
  • map(row_number(), ~ slice(cur_data(), 1:(.x - 1))):针对每组内的第n行,提取前n-1行作为该行的历史出行记录。
  • summarise(count = n(), last_date = max(Date)):既统计每个国家的出行次数,又记录该国家最近一次出行的日期,用于解决次数相同时的排序问题。
  • arrange(desc(count), desc(last_date)):先按出行次数从多到少排序,次数相同的情况下,最近去过的国家排在更前面,符合需求中的优先级规则。
  • c(df_summary[1:3], rep(NA, max(0, 3 - length(df_summary)))):保证我们总是得到3个元素的列表,不足3个国家时用NA填充,方便后续拆分为三列。

运行这段代码后,得到的结果就和你期望的完全一致啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 23:12:45