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

如何用dplyr按分组计算不同年龄区间的status=yes占比

问题描述

有如下数据框:

df <- read.table(text = "group  age status
A   25  yes
A   32  no
A   58  yes
A   78  no
A   76  yes
B   21  no
B   71  yes
B   43  no
B   48  no
C   39  no
C   82  yes
C   87  no
C   91  yes", header = T)

需要按group列分组后执行summarise操作,满足以下要求:

  • 统计年龄小于50且status为"yes"的数量,除以年龄小于50的总数量得到占比;
  • 统计年龄大于50且status为"yes"的数量,除以年龄大于50的总数量得到占比;
  • 若出现0/0的情况(即某分组下对应年龄区间的总数量为0),返回0。

以分组'A'为例:

age_lt_50_yes = 1
age_lt_50 = 2

对应占比为1/2=0.5;

age_gt_50_yes = 2
age_gt_50 = 3

对应占比为2/3≈0.66。

已尝试以下代码,但缺少status的判断逻辑:

df %>% 
  group_by(group) %>% 
  summarize(age_le50_prop = sum(age <= 50) / n(),
            age_gt50_prop = sum(age > 50) / n())

期望输出如下:

group age_lt_50 age_gr_50
A     0.5       0.66
B     0         1
C     0         0.66

请问如何用dplyr实现该需求?


解决方案

可以通过在sum()中添加复合条件筛选目标样本,同时用ifelse()处理0/0的情况(避免除以0报错)。具体代码如下:

library(dplyr)

df %>%
  group_by(group) %>%
  summarize(
    age_lt_50 = ifelse(
      sum(age < 50) == 0, 0,
      sum(age < 50 & status == "yes") / sum(age < 50)
    ),
    age_gr_50 = ifelse(
      sum(age > 50) == 0, 0,
      sum(age > 50 & status == "yes") / sum(age > 50)
    )
  ) %>%
  mutate(across(c(age_lt_50, age_gr_50), ~round(., 2))) # 可选:保留两位小数匹配期望格式

代码说明:

  • sum(age < 50 & status == "yes"):精准统计年龄小于50且status为"yes"的样本数;
  • sum(age < 50):统计对应年龄区间的总样本数;
  • ifelse(sum(age < 50) == 0, 0, ...):当目标年龄区间无样本时,直接返回0,避免除以0的运行错误;
  • 最后一行mutate(across(...))用于将结果保留两位小数,和期望输出格式对齐。

执行代码后输出结果:

# A tibble: 3 × 3
  group age_lt_50 age_gr_50
  <chr>     <dbl>     <dbl>
1 A           0.5      0.67
2 B           0        1   
3 C           0        0.67

(注:0.66和0.67为四舍五入差异,若需严格保留两位小数可调整round()参数)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 21:57:31