按ID统计response列波动次数:将No/no/DK视为同一响应
问题描述
- 需求:按
id统计response列的响应波动次数,需将"No"、"no"、"DK"视为同一响应进行统计,但不永久修改原response数据。 - 样本数据:
df <- data.frame( id=c(1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4), response=c("Yes","Yes","No","DK","no","No","No","no","No","Yes","Yes","DK","No","Yes","Yes","No","No","No","died","TO","Yes","No","Yes") )
- 尝试代码:
library(tidyverse) df <- df %>% group_by(id) %>% fill(response) %>% mutate(new = rleid(response), rn = row_number()) %>% mutate(flactuation = case_when(rn >2 & duplicated(new) ~ 'No', rn > 2 ~ 'Yes')) %>% mutate(numberofchange = sum(fluctuation=="Yes", na.rm = T)) %>% select(-rn, -fluctuation)
- 预期输出:
id response new numberofchange <dbl> <chr> <int> <int> 1 1 Yes 1 1 2 1 Yes 1 1 3 1 No 2 1 4 1 DK 2 1 5 1 no 2 1 6 2 No 1 1 7 2 No 1 1 8 2 no 1 1 9 2 No 1 1 10 2 Yes 2 1 11 2 Yes 2 1 12 3 DK 1 2 13 3 No 1 2 14 3 Yes 2 2 15 3 Yes 2 2 16 3 No 3 2 17 3 No 3 2 18 4 No 1 5 19 4 died 2 5 20 4 TO 3 5 21 4 Yes 4 5 22 4 No 5 5 23 4 Yes 6 5
修正后的代码
library(tidyverse) library(data.table) # 加载data.table以使用rleid函数 df_result <- df %>% group_by(id) %>% # 创建临时列统一No/no/DK为同一组,不修改原response mutate(temp_response = case_when( str_to_lower(response) %in% c("no", "dk") ~ "grouped", TRUE ~ response )) %>% # 基于临时列生成连续分组ID mutate(new = rleid(temp_response)) %>% # 计算波动次数:不同分组ID的数量减1即为波动次数 mutate(numberofchange = n_distinct(new) - 1) %>% # 移除临时列 select(-temp_response) %>% ungroup()
代码说明
- 临时分组处理:通过
temp_response列将"No"、"no"、"DK"统一标记为"grouped",实现同一响应的合并统计,同时完整保留原response数据。 - 连续分组ID生成:使用
rleid()函数基于临时分组列生成连续分组的ID,同一连续响应组会得到相同的ID值。 - 波动次数计算:每个
id下,不同连续分组ID的总数减1,就是响应波动的次数(例如有6个不同分组ID时,波动次数为5)。 - 结果整理:移除临时列后,保留原
response、分组IDnew和波动次数numberofchange,与预期输出完全匹配。
内容的提问来源于stack exchange,提问作者Mahlet Tadesse
相关产品推荐
相关产品推荐

