如何向量化自定义函数以在R中配合mutate()和case_when()使用?
解决自定义函数处理向量报错并生成新列的问题
你的报错源于原函数中的if (!is.na(num))无法处理向量输入:当num是向量时,is.na(num)返回同长度的逻辑向量,而if仅支持长度为1的条件判断,因此触发错误。以下是三种可行的解决方案:
方法1:用Vectorize包装原函数
通过Vectorize将原函数转换为支持向量输入的版本,每个元素单独处理后提取第4个结果:
library(tidyverse) # 保留原函数不变 QA2Char_dec <- function(num) { if (!is.na(num)) { char <- paste(sapply(strsplit(paste(rev(intToBits(num))),""),`[[`,2),collapse="") char <- substr(char, 17, 32) qa.arr <- c(substr(char, 1, 1), substr(char, 2, 3), substr(char, 4, 4), substr(char, 5, 8), substr(char, 9, 11), substr(char, 12, 13), substr(char, 14, 16)) } else { qa.arr <- rep(NA_character_, 7) } return(qa.arr) } # 生成向量化版本的函数 QA2Char_dec_vec <- Vectorize(QA2Char_dec) # 处理数据框 QA.values <- c(1, 1291, NA, 1288, 1000, NA) df <- data.frame(QA.values) df <- df %>% mutate(QA.check = sapply(QA2Char_dec_vec(QA.values), `[`, 4))
方法2:重写为纯向量化函数
直接针对向量逻辑重写函数,避免逐元素循环,效率更高:
QA2Char_dec_vec2 <- function(nums) { # 处理非NA值的二进制转换 binary_str <- sapply(nums[!is.na(nums)], function(num) { char <- paste(sapply(strsplit(paste(rev(intToBits(num))),""),`[[`,2),collapse="") substr(char, 17, 32) }) # 提取目标子串并处理NA qa_aod <- ifelse( is.na(nums), NA_character_, substr(binary_str[match(nums, nums[!is.na(nums)])], 5, 8) ) return(qa_aod) } # 应用到数据框 df <- df %>% mutate(QA.check = QA2Char_dec_vec2(QA.values))
方法3:用purrr::map_chr逐元素处理
利用tidyverse的map系列函数,逐个处理每个值并提取目标元素:
df <- df %>% mutate(QA.check = map_chr(QA.values, function(x) { if (is.na(x)) NA_character_ else QA2Char_dec(x)[4] }))
最终结果
三种方法均能得到你期望的输出:
QA.values QA.check 1 1 0000 2 1291 0101 3 NA <NA> 4 1288 0101 5 1000 0011 6 NA <NA>
内容的提问来源于stack exchange,提问作者Seyong Chang
相关产品推荐
相关产品推荐

