如何使用dplyr计算data.frame各时间点A/B类数值的比值
问题背景
现有data.frame格式数据集,需按Type分类分组计算衍生变量,示例数据构造代码:
df = data.frame(time = rep(seq(10),each=2),Type=rep(c("A","B"),times=10),value = runif(20))
目标是生成新的data.frame,输出每个time时间点下,Type=A的value与Type=B的value的比值。
之前尝试用如下代码实现:
df2 <- df |> group_by(time) |> mutate(new_value= value[Type=="A"] / value[Type=="B"],.keep="none")
运行后每个时间点返回2条重复的new_value记录,不符合预期。
问题原因
这是dplyr包中mutate()函数的默认行为导致的:mutate()不会改变输入数据的行数,按time分组后每组固定有2行(分别对应A、B两个类型),即使你计算出的A/B比值是长度为1的单值,mutate()也会自动把这个值循环填充到组内所有行,自然就出现了每个时间点两条重复值的情况。
修正方案
如果需要每个时间点仅输出1条比值记录,把mutate()替换为summarise()即可,该函数会把每个分组的计算结果折叠为单行:
library(dplyr) df2 <- df |> group_by(time) |> summarise( new_value = value[Type == "A"] / value[Type == "B"], .groups = "drop" )
如果需要保留原始数据集的所有行,同时在每行附上同时间点的A/B比值,原来的mutate()写法本身没有错误,重复值是符合逻辑的正常输出——同一个时间点下,无论是A类行还是B类行,对应的同组A/B比值本来就是同一个值。如果不需要重复记录,在计算后加一层筛选即可:
df2 <- df |> group_by(time) |> mutate(new_value = value[Type=="A"] / value[Type=="B"]) |> # 筛选A类或B类行都可以,同组比值完全一致 filter(Type == "A") |> select(time, new_value)
以上写法的生效前提是:每个
time分组下有且仅有1条A类记录、1条B类记录。如果存在某类记录缺失、某类对应多条记录的情况,会出现计算长度不匹配的报错,计算前建议先校验分组内的类型分布。
内容的提问来源于stack exchange,提问作者Joezerz
相关产品推荐
相关产品推荐

