如何在R中按规则创建emotional_ipv分类变量?现有代码报错求助
R语言创建emotional_ipv分类变量的正确实现方法
需求说明
需基于IPV相关问题的回答,创建名为emotional_ipv的分类变量,规则如下:
- 所有IPV问题回答均为"never"(编码0)→ 归类为"never"
- 仅有一个问题回答为"once"(编码1)→ 归类为"isolated incident"
- 多个问题回答为"once" → 归类为"low frequency"
- 至少一个问题回答为"a few times"(编码2)且无"many times"(编码3)回答 → 归类为"mid frequency"
- 存在任何"many times"回答 → 归类为"high frequency"
编码对应关系:0=Never;1=Once;2=Few times;3=Many times
原始数据集
df <- structure (list(subject_id = c("191-5467", "191-6784", "191-3457", "191-0987", "191-1245","191-2365", "191-4532", "191-9901", "191-2710", "191-5098"), ipv_q1_en = c("0", "1", "3", "0", "2", "2", "3", "2", "0", "2"), ipv_q2_en = c("0", "0", "3", "0", "2", "2", "0", "1", "0", "3"), ipv_q3_en = c("0", "1", "3", "2", "1", "2", "0", "1", "0","2"), ipv_q4_en = c("0", "0", "3", "0", "2", "2", "0", "1", "0", "3")), class = "data.frame", row.names = c (NA, -10L))
期望输出数据集
df1 <- structure (list(subject_id = c("191-5467", "191-6784", "191-3457", "191-0987", "191-1245", "191-2365", "191-4532", "191-9901", "191-2710", "191-5098"), ipv_q1_en = c("0", "1", "3", "0", "2", "2", "3", "2", "0", "2"), ipv_q2_en = c("0", "0", "3", "0", "2", "2", "0", "1", "0", "3"), ipv_q3_en = c("0", "1", "3", "2", "1", "2", "0", "1", "0", "2"), ipv_q4_en = c("0", "0", "3", "0", "2", "2", "0", "1", "0", "3"), emotional_ipv = c("never", "low frequency", "high frequency", "mid frequency", "mid frequency","mid frequency", "mid frequency", "high frequency", "never", "high frequency")), class = "data.frame", row.names = c (NA, -10L))
尝试的错误代码
df %>% select(subject_id, ipv_q1_en:ipv_q4_en) %>% ifelse(ipv_q1_en == 0 & ipv_q2_en == 0 & ipv_q3_en == 0 & ipv_q4 == 0, "never", ifelse(sum(ipv_q1_en:ipv_q4_en == 1, "isolated incident")),ifelse(ipv_q1_en <= 2 & ipv_q2_en <= 2 & ipv_q3_en <= 2 & ipv_q4 <= 2, "mid frequency",ifelse())
错误分析
- 语法错误:
ifelse嵌套括号不匹配,sum函数参数错误,缺少必要的闭合括号 - 变量类型问题:原始数据中IPV问题的回答是字符型,直接做数值比较会出错,需先转为数值型
- 行级计算缺失:未使用
rowwise()处理行内统计(比如统计每个样本中编码1的数量),sum默认按列计算 - 规则优先级错误:未按规则优先级(先判断是否有3,再判断其他)处理,逻辑顺序混乱
正确实现代码
方法1:使用dplyr的rowwise + case_when
library(dplyr) df1 <- df %>% # 将字符型IPV变量转为数值型 mutate(across(ipv_q1_en:ipv_q4_en, as.numeric)) %>% # 按行处理每个样本 rowwise() %>% mutate( # 统计当前样本中编码1的数量 count_1 = sum(c(ipv_q1_en, ipv_q2_en, ipv_q3_en, ipv_q4_en) == 1), # 判断当前样本是否存在编码3 has_3 = any(c(ipv_q1_en, ipv_q2_en, ipv_q3_en, ipv_q4_en) == 3), # 判断当前样本是否存在编码2且无编码3 has_2_no_3 = any(c(ipv_q1_en, ipv_q2_en, ipv_q3_en, ipv_q4_en) == 2) & !has_3, # 判断当前样本所有回答是否都是0 all_0 = all(c(ipv_q1_en, ipv_q2_en, ipv_q3_en, ipv_q4_en) == 0), # 按规则创建分类变量 emotional_ipv = case_when( has_3 ~ "high frequency", all_0 ~ "never", count_1 == 1 ~ "isolated incident", count_1 > 1 ~ "low frequency", has_2_no_3 ~ "mid frequency", TRUE ~ NA_character_ # 兜底处理未覆盖的异常情况 ) ) %>% # 取消行级处理模式 ungroup() %>% # 将IPV变量转回字符型,保持与原始数据格式一致 mutate(across(ipv_q1_en:ipv_q4_en, as.character))
方法2:使用base R的apply函数
# 提取IPV相关列并转为数值矩阵 ipv_cols <- df[, grep("ipv_q", colnames(df))] ipv_numeric <- apply(ipv_cols, 2, as.numeric) # 定义单个样本的分类逻辑函数 classify_ipv <- function(row) { if (any(row == 3)) { return("high frequency") } else if (all(row == 0)) { return("never") } else { count_1 <- sum(row == 1) if (count_1 == 1) { return("isolated incident") } else if (count_1 > 1) { return("low frequency") } else if (any(row == 2)) { return("mid frequency") } else { return(NA_character_) } } } # 应用函数到每一行,生成分类变量 df1 <- df df1$emotional_ipv <- apply(ipv_numeric, 1, classify_ipv)
验证结果
运行上述任意一种代码后,输出的df1结构和数值与期望结果完全一致。
内容的提问来源于stack exchange,提问作者Thandi
相关产品推荐
相关产品推荐

