如何在R中基于多条件将一列值替换为另一列对应行的值
问题描述
现有如下表格数据:
Family Genus Species Genus_new col2 Pedinellales Pedinella uncultured_eukaryote uncultured eukaryote Noctilucales Noctiluca Noctiluca_scintillans Noctiluca scintillans Mediophyceae Chaetoceros Chaetoceros_socialis Chaetoceros socialis Noctilucales Noctiluca Noctiluca_scintillans Noctiluca scintillans Eustigmatales uncultured uncultured_eukaryote uncultured eukaryote Mediophyceae Chaetoceros Chaetoceros_sp. Chaetoceros sp. Gonyaulacales Heterodinium uncultured_eukaryote uncultured eukaryote Cryptomonadales Cryptochloris phytoplankton_environmental phytoplankton environmental Prymnesiophyceae Phaeocystis Haptophyta_environmental Haptophyta environmental Sarcinochrysidales Pelagodinium Pelagophyceae_sp. Pelagophyceae sp. Mediophyceae Skeletonema uncultured_marine uncultured marine Gymnodiniphycidae Gyrodinium uncultured_Gyrodinium uncultured Gyrodinium Cryptomonadales Cryptochloris uncultured_Cryptophyta uncultured Cryptophyta Pedinellales Pedinellales uncultured_eukaryote uncultured eukaryote Prasinophytae Prasinophytae Pycnococcus_sp. Pycnococcus sp.
需求是:当Genus_new列的字符串满足以下任一条件时,将其替换为同一行Genus列的值:
- 以
unc或phyto开头 - 以
phyceae结尾
单独的for循环可以正常运行:
for (i in 1:nrow(data)) { (data$Genus_new[i][startsWith(data$Genus_new[i], "unc")]<-data$Genus[i]) } for (i in 1:nrow(data)) { (data$Genus_new[i][endsWith(data$Genus_new[i], "phyceae")]<-data$Genus[i]) } for (i in 1:nrow(data)) { (data$Genus_new[i][startsWith(data$Genus_new[i], "phytoplank")]<-data$Genus[i]) }
但整合逻辑时遇到问题:
第一次尝试(行不匹配错误)
#first try data$Genus_new[startsWith(data$Genus_new, "unc") | startsWith(data$Genus_new[i], "Unc") | endsWith(data$Genus_new[i], "phyta") | endsWith(data$Genus_new[i], "phyceae") | startsWith(data$Genus_new[i], "phytoplank") | endsWith(data$Genus_new[i], "phyte") ] <- data$Genus
结果出现行不匹配,比如第2行Genus_new的值变为第5行Genus的值。
第二次尝试(逻辑判断错误)
#second try: for (i in 1:nrow(data)) { if(data$Genus_new[i][startsWith(data$Genus_new[i], "unc")]) { data$Genus_new[i]<-data$Genus[i]} else if(data$Genus_new[i][endsWith(data$Genus_new[i], "phyta")]){ data$Genus_new[i]<-data$Genus[i]} else if(data$Genus_new[i][endsWith(data$Genus_new[i], "phyceae")]) { data$Genus_new[i]<-data$Genus[i]} }
报错:
Error in if (data$Genus_new[i][startsWith(data$Genus_new[i], "unc")]) { : argument is not interpretable as logical
问题分析与解决
错误原因解析
第一次尝试的问题:
- 混用了向量化操作和循环变量
i,startsWith(data$Genus_new[i], ...)是单个元素判断,而startsWith(data$Genus_new, "unc")是整列判断,导致生成的逻辑索引与data$Genus长度不匹配,赋值时出现行错位。 startsWith默认区分大小写,单独写"Unc"判断没必要,可用ignore.case = TRUE统一处理大小写。
- 混用了向量化操作和循环变量
第二次尝试的问题:
data$Genus_new[i][startsWith(data$Genus_new[i], "unc")]写法错误:startsWith返回逻辑值时,该代码取的是data$Genus_new[i]的字符子集,而非逻辑值,if语句无法识别,因此报错。应直接用startsWith(data$Genus_new[i], "unc")作为判断条件。
正确实现方法
方法1:整合向量化操作(推荐,符合R语言风格)
直接生成整列的逻辑索引,批量赋值避免循环:
# 生成所有满足条件的逻辑向量 condition <- startsWith(data$Genus_new, "unc", ignore.case = TRUE) | startsWith(data$Genus_new, "phytoplank") | endsWith(data$Genus_new, "phyceae") | endsWith(data$Genus_new, "phyta") | endsWith(data$Genus_new, "phyte") # 对满足条件的行赋值 data$Genus_new[condition] <- data$Genus[condition]
方法2:整合for循环
修正第二次尝试的判断逻辑,直接用逻辑值作为判断条件:
for (i in 1:nrow(data)) { current_genus_new <- data$Genus_new[i] # 整合所有判断条件 if (startsWith(current_genus_new, "unc") || startsWith(current_genus_new, "phytoplank") || endsWith(current_genus_new, "phyceae") || endsWith(current_genus_new, "phyta") || endsWith(current_genus_new, "phyte")) { data$Genus_new[i] <- data$Genus[i] } }
方法3:正则表达式简化判断(更灵活)
用grepl结合正则表达式一次性覆盖所有条件:
# 正则表达式:匹配以unc/phytoplank开头,或以phyceae/phyta/phyte结尾的字符串 condition <- grepl("^(unc|phytoplank)", data$Genus_new, ignore.case = TRUE) | grepl("(phyceae|phyta|phyte)$", data$Genus_new) data$Genus_new[condition] <- data$Genus[condition]
内容的提问来源于stack exchange,提问作者Franchi
相关产品推荐
相关产品推荐

