使用tidyverse计算Moving Range时结果全为NA的问题排查
问题分析与解决方案
错误原因
你的代码生成全NA的MR列,核心问题有两个:
- 分组去重逻辑错误:
group_by(Venture, Section)后执行distinct(Type,.keep_all = TRUE),但每个Venture+Section分组内的Type完全重复(比如Sect111的两条数据Type都是1),去重后每个分组仅保留1条数据,length(Pay)始终为1,触发else分支赋值NA。 - MR计算写法冗余且不匹配行数:即便分组后有多条数据,
map_dbl返回的结果长度是length(Pay)-1,无法与分组行数匹配,会导致第一行自动填充NA,且写法远不如直接用滞后值计算简洁。
另外,max(Pay[.x], Pay[.x-1]) - min(Pay[.x], Pay[.x-1])完全等价于abs(Pay[.x] - Pay[.x-1]),可以直接简化。
修正方案
根据你的需求,分两种常见场景给出修正代码:
场景1:保留原分组(Venture+Section),去掉多余去重
如果目标是在每个Venture+Section分组内计算Pay的移动范围(同一Section内的两条Pay值),直接去掉distinct步骤,用lag()函数计算绝对值差:
library(tidyverse) Df <- structure(list( Venture = c("N", "N", "N", "N", "R", "R", "R", "R", "S", "S", "S", "S"), Type = c(1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2), Section = c("Sect111", "Sect111", "Sect112", "Sect112", "Sect113", "Sect113", "Sect114", "Sect114", "Sect115", "Sect115", "Sect116", "Sect116"), Pay = c(102029, 102271, 679263, 669249, 203499, 218765, 495000, 487562, 773432, 765423, 233345, 245690)), class = "data.frame", row.names = c(NA, -12L)) df2 <- Df %>% group_by(Venture, Section) %>% mutate(MR = abs(Pay - lag(Pay)))
运行后,每个分组的第二行MR为两条Pay的绝对值差,第一行因无前值为NA,符合移动范围的定义。
场景2:按Venture+Type分组,保留每个Section的唯一值
如果目标是在同一Venture+Type下,计算不同Section的Pay移动范围,调整分组逻辑并修正去重条件:
library(tidyverse) Df <- structure(list( Venture = c("N", "N", "N", "N", "R", "R", "R", "R", "S", "S", "S", "S"), Type = c(1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2), Section = c("Sect111", "Sect111", "Sect112", "Sect112", "Sect113", "Sect113", "Sect114", "Sect114", "Sect115", "Sect115", "Sect116", "Sect116"), Pay = c(102029, 102271, 679263, 669249, 203499, 218765, 495000, 487562, 773432, 765423, 233345, 245690)), class = "data.frame", row.names = c(NA, -12L)) df2 <- Df %>% group_by(Venture, Type) %>% distinct(Section,.keep_all = TRUE) %>% # 每个Section保留一条数据 mutate(MR = abs(Pay - lag(Pay)))
此代码会在每个Venture+Type分组内(包含两个不同Section的Pay值)计算移动范围。
内容的提问来源于stack exchange,提问作者DB5
相关产品推荐
相关产品推荐

