You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在R语言数据框中按产品分组转换日期为自起始日期起的天数

解决按产品维度计算起始日后天数的问题

我来帮你搞定这个日期计算的问题!你想要的是每个产品从自己的首次出现日期开始计算经过的天数,核心问题在于之前的分组操作里没有正确获取分组内的起始日期,下面给你详细说明正确的解法和错误原因:

正确解法(推荐)

dplyr的分组功能结合first()函数,就能精准获取每个产品的起始日期,再计算日期差即可:

library(dplyr)

# 计算每个产品自起始日起的天数
result_df <- df1 %>%
  group_by(Product) %>%
  # 用first(Dates)获取分组内的第一个日期,日期相减后转成数值得到天数
  mutate(Days = as.numeric(Dates - first(Dates))) %>%
  ungroup() # 记得取消分组,避免后续操作受影响

运行后得到的结果和你期望的desired_df完全一致:

# 部分结果展示
# Dates       Product Days
# 1 2021-01-01 Banana    0
# 2 2021-01-02 Banana    1
# ...
# 6 2021-01-06 Apple     0
# 7 2021-01-07 Apple     1
# ...
# 11 2021-01-11 Orange    0
# 12 2021-01-12 Orange    1

为什么你之前的方法出错?

你尝试的这段代码:

df1 %>% group_by(Product) %>% mutate(Days = as.numeric(Dates - Dates[1]))

问题出在Dates[1]——在dplyr的分组环境中,Dates[1]并不会自动指向当前分组的第一个日期,而是仍然引用整个原始数据框的第一行日期(也就是2021-01-01)。所以Apple的日期减去这个值就得到了5、6...,Orange得到10、11...,自然不符合需求。

first(Dates)dplyr专门为分组操作设计的函数,能准确提取每个分组内的第一个元素,完美解决这个问题。

关于你补充的lubridate方法的说明

你提到的这段代码虽然能工作:

df1 %>% group_by(Product) %>% mutate(Days=lubridate::day(Dates)-first(lubridate::day(Dates)))

但它有局限性:如果产品的日期跨月(比如起始日是1月31日,后续日期是2月1日),用day()提取日期计算就会得到错误的结果(1-31=-30)。而直接用日期相减的方法,不管跨月、跨年都能正确计算天数差,适用性更强。

其他思路(可选)

如果不想用dplyr,也可以用基础R的ave()函数实现:

df1$Days <- ave(as.numeric(df1$Dates), df1$Product, FUN = function(x) x - x[1])

这个方法不需要加载额外包,同样能得到正确结果。

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

火山引擎 最新活动