使用循环为R语言data.frame创建新字段的报错排查与实现
R语言按规则生成薪资字段:循环代码错误排查与正确实现
问题描述
现有一个包含212行的tibble数据框,结构如下:
tibble [212 × 9] (S3: tbl_df/tbl/data.frame) $ Observation : num [1:212] 1 2 3 4 5 6 7 8 9 10 ... $ Gender : Factor w/ 2 levels "0","1": 2 2 1 1 1 2 2 2 1 1 ... $ Education : Factor w/ 3 levels "Bachelors","Masters",..: 2 2 3 1 2 3 3 1 2 2 ... $ Salary : num [1:212] 64233855 7955556 97531875 89785395 6956943 ... $ Graduation : Date[1:212], format: "2015-09-22" "2020-06-15" "2008-05-07" ... $ License : logi [1:212] TRUE FALSE TRUE FALSE FALSE TRUE ... $ Expenses : num [1:212] 3356768 247988 274816 2447352 4069344 ... $ Satisfaction: Factor w/ 5 levels "1","2","3","4",..: 3 1 4 3 5 2 3 2 4 3 ... $ Stress : Factor w/ 2 levels "No","Yes": 2 2 1 1 2 2 1 2 1 1 ...
需按以下规则创建SalaryNew字段:
- a. 满意度为2或3且压力为'Yes'的女性,薪资增加15%
- b. 满意度为1或2且压力为'No'的男性,薪资增加7.5%
- c. 其余行保持原薪资不变
自行编写的循环代码报错:
Error: unexpected '&' in: " if (df$Gender[j]=='female')
&"
错误代码:
for (j in 1:i[1]) { if (df$Gender[j]=='female') & df$Satisfaction[j] 2 | 3 & df$Stress[j] == 'Yes' df$SalaryNew[j] <- df$Salary[j]*1.15 else if (df$Gender[j]=='male'), & df$Satisfaction[j] 2 | 3 & df$Stress[j] == 'No' df$SalaryNew[j] <- df$Salary[j]*1.075 else df$SalaryNew[j] <- df$Salary[j] }
数据结构示例(可直接运行):
structure(list(Observation = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), Gender = structure(c(2L, 2L, 1L, 1L, 1L, 2L, 2L, 2L, 1L, 1L), levels = c("0", "1"), class = "factor"), Education = structure(c(2L, 2L, 3L, 1L, 2L, 3L, 3L, 1L, 2L, 2L), levels = c("Bachelors", "Masters", "PhD"), class = "factor"), Salary = c(64233855,7955556, 97531875, 89785395, 6956943, 12445419, 54293295, 109647195, 113335215, 8171793), Graduation = structure(c(16700, 18428, 14006, 11782, 15333, 13879, 18873, 19085, 13067, 13529), class = "Date"), License = c(TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE), Expenses = c(3356768, 247988, 274816, 2447352, 4069344, 244264, 3398872, 2901072, 3346736, 2358584), Satisfaction = structure(c(3L, 1L, 4L,3L, 5L, 2L, 3L, 2L, 4L, 3L), levels = c("1", "2", "3", "4","5"), class = "factor"), Stress = structure(c(2L, 2L, 1L,1L, 2L, 2L, 1L, 2L, 1L, 1L), levels = c("No", "Yes"), class = "factor")), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"))
错误排查
原代码存在以下核心问题:
- 因子取值匹配错误:
Gender的水平是"0"和"1",不是"female"/"male",需先明确业务映射关系(以下假设"0"=女性,"1"=男性) - 条件表达式语法混乱:
if的条件未包裹在括号内,&单独换行导致语法断裂- 缺少比较运算符:
df$Satisfaction[j] 2应改为df$Satisfaction[j] == "2" - 逻辑运算优先级未明确:多条件需用括号分组,避免运算顺序错误
- 存在无效符号:
else if中的逗号属于多余字符
- 循环范围无效:
1:i[1]无意义,应使用1:nrow(df)遍历所有行 - 代码块未正确包裹:
if/else if后的多行逻辑未用大括号{}包裹,导致执行逻辑混乱
正确实现方案
方案1:修复后的循环版本
# 初始化新字段 df$SalaryNew <- df$Salary # 遍历所有行 for (j in 1:nrow(df)) { # 规则a:女性,满意度2/3,压力Yes if (df$Gender[j] == "0" & (df$Satisfaction[j] == "2" | df$Satisfaction[j] == "3") & df$Stress[j] == "Yes") { df$SalaryNew[j] <- df$Salary[j] * 1.15 } # 规则b:男性,满意度1/2,压力No else if (df$Gender[j] == "1" & (df$Satisfaction[j] == "1" | df$Satisfaction[j] == "2") & df$Stress[j] == "No") { df$SalaryNew[j] <- df$Salary[j] * 1.075 } # 规则c:其余情况保持原薪资 else { df$SalaryNew[j] <- df$Salary[j] } }
方案2:更高效的向量化实现(推荐)
R中循环效率较低,优先使用向量化操作,提供两种简洁写法:
方式一:base R的ifelse嵌套
df$SalaryNew <- ifelse( # 规则a df$Gender == "0" & (df$Satisfaction %in% c("2", "3")) & df$Stress == "Yes", df$Salary * 1.15, ifelse( # 规则b df$Gender == "1" & (df$Satisfaction %in% c("1", "2")) & df$Stress == "No", df$Salary * 1.075, # 规则c df$Salary ) )
方式二:dplyr的case_when(代码可读性更强)
library(dplyr) df <- df %>% mutate(SalaryNew = case_when( Gender == "0" & Satisfaction %in% c("2", "3") & Stress == "Yes" ~ Salary * 1.15, Gender == "1" & Satisfaction %in% c("1", "2") & Stress == "No" ~ Salary * 1.075, TRUE ~ Salary ))
注意:若Gender的实际业务映射与假设相反(比如"1"代表女性),请自行调整条件中的取值。
内容的提问来源于stack exchange,提问作者EBE
相关产品推荐
相关产品推荐

