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

R语言中简化多选问题百分比频率表生成代码的方法

简化烘焙产品购买渠道频率表生成代码

背景

我运营一家大型烘焙品牌,开展了客户购买历史调查:询问客户是否购买过macaron、cookie、scone、candy等产品,以及对应的购买渠道(online、local store、chain store),客户可勾选所有符合的选项。调查结果已整理成长格式数据集mockdf,生成代码如下:

set.seed(2)

record_id<- c(1:1000)
a_method_1 <- sample(c(1:2), replace = T, size = 1000)
b_method_1<-sample(c(1:2), replace = T, size = 1000)
c_method_1<- sample(c(1:2), replace = T, size = 1000)

a_method_2 <- sample(c(1:2), replace = T, size = 1000)
b_method_2<-sample(c(1:2), replace = T, size = 1000)
c_method_2<- sample(c(1:2), replace = T, size = 1000)

a_method_3 <- sample(c(1:2), replace = T, size = 1000)
b_method_3<-sample(c(1:2), replace = T, size = 1000)
c_method_3<- sample(c(1:2), replace = T, size = 1000)

a_method_4 <- sample(c(1:2), replace = T, size = 1000)
b_method_4<-sample(c(1:2), replace = T, size = 1000)
c_method_4<- sample(c(1:2), replace = T, size = 1000)

mockdf<- data.frame(record_id, a_method_1, b_method_1, c_method_1,
                    a_method_2, b_method_2, c_method_2, 
                    a_method_3, b_method_3, c_method_3,
                    a_method_4, b_method_4, c_method_4)

set.seed(2)
mockdf<- mockdf %>% mutate(
  across(.cols= (c(2:13)),
         .fns = ~ifelse(rbinom(n(), 1, 0.1), NA, .x))
)  # 添加NA模拟真实数据

mockdf<- mockdf %>% mutate(across(c(2:13), ~factor(.x, levels= c(1,2),
                                                   labels = c("checked", "unchecked"))))

mockdf<- mockdf %>% pivot_longer(c(2:13), names_to = "source_type") %>% 
  mutate(product = case_when(endsWith(source_type, "1")~ "macaron", 
                             endsWith(source_type, "2")~ "cookie",
                             endsWith(source_type, "3")~ "scone",
                             endsWith(source_type, "4")~ "candy",
                             TRUE~ NA), 
         method = case_when(startsWith(source_type, "a")~ "online", 
                            startsWith(source_type, "b")~ "local store", 
                            startsWith(source_type, "c")~"chain store", 
                            TRUE~ NA)) %>% 
  select(-source_type)

head(mockdf)
#  record_id value     product method     
#      <int> <fct>     <chr>   <chr>      
#1         1 checked   macaron online     
#2         1 unchecked macaron local store
#3         1 unchecked macaron chain store
#4         1 checked   cookie  online     
#5         1 unchecked cookie  local store
#6         1 checked   cookie  chain store

需求与现有代码问题

我需要生成带百分比的频率表,其中百分比的分母是每种产品的购买人数(而非总受访者或购买任意产品的人数)。目前的实现代码需要手动为每个产品定义购买人数变量,再用case_when匹配计算百分比,产品类型增多时代码会非常冗余:

n_macaron<- mockdf %>% filter(product == "macaron" & value == "checked") %>% distinct(record_id) %>% nrow()
n_cookie<- mockdf %>% filter(product == "cookie" & value == "checked") %>% distinct(record_id) %>% nrow()
n_scone<- mockdf %>% filter(product == "scone" & value == "checked") %>% distinct(record_id) %>% nrow()
n_candy<- mockdf %>% filter(product == "candy" & value == "checked") %>% distinct(record_id) %>% nrow()

mockdf %>% filter(value == "checked") %>%  group_by(product, method) %>% count() %>% 
  mutate(perc = case_when(product == "macaron"~ round((n/n_macaron)*100,0),
                          product == "cookie"~ round((n/n_cookie)*100,0),
                          product == "scone"~ round((n/n_scone)*100,0),
                          product == "candy"~ round((n/n_candy)*100,0)))

简化方案

利用dplyr的分组和聚合功能,无需手动定义单个产品的购买人数变量,代码可自动适配任意数量的产品类型:

方法一:先计算产品总购买人数再合并

# 第一步:计算每个产品的购买人数(去重后的受访者数量)
product_total <- mockdf %>%
  filter(value == "checked") %>%
  group_by(product) %>%
  summarise(total_purchasers = n_distinct(record_id), .groups = "drop")

# 第二步:生成频率表并计算百分比
freq_table <- mockdf %>%
  filter(value == "checked") %>%
  group_by(product, method) %>%
  count(name = "n") %>%
  left_join(product_total, by = "product") %>%
  mutate(perc = round((n / total_purchasers) * 100, 0)) %>%
  select(-total_purchasers)

# 查看结果
freq_table

方法二:嵌套分组一步完成

freq_table <- mockdf %>%
  filter(value == "checked") %>%
  group_by(product) %>%
  # 计算当前产品的总购买人数
  mutate(total_purchasers = n_distinct(record_id)) %>%
  # 嵌套分组:在产品分组基础上再按渠道分组
  group_by(product, method, .add = TRUE) %>%
  summarise(
    n = n(),
    perc = round((n / first(total_purchasers)) * 100, 0),
    .groups = "drop"
  )

# 查看结果
freq_table

两种方法都会输出和原代码一致的结果,且当新增产品类型时,无需修改代码,自动适配计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 23:10:41