R语言中mutate结合pick生成的列含$符号问题求助
问题:结合pick与列匹配函数调用自定义函数时生成嵌套data.frame列的问题
我用自定义函数calc_tas计算新列时,发现当结合pick、starts_with和ends_with函数传入参数时,生成的tas列是嵌套的data.frame,列名带$且附加了输入列名,导致后续无法正常引用;但直接传入无引号的列名时结果正常。请问函数写法是否有误?
输入数据示例
> data structure(list(tmpc39000 = c(-55, -56, -56, -57, -56, -56), tmpc45000 = c(-64, -65, -64, -63, -64, -64), tmpc53000 = c(-64, -64, -63, -63, -64, -63)), row.names = c(NA, -6L), class = c("tbl_df", "tbl", "data.frame" ))
自定义函数
knots_to_ms <- 0.51444 gamma <- 1.4 r_star <- 287.053 degc_to_degk <- 273.15 calc_tas <- function(mach, temp, units = "knots") { if (units == "knots") { speed_mult <- 1 / knots_to_ms } else { speed_mult <- 1 } speed_sound <- sqrt(gamma * r_star * (temp + degc_to_degk)) tas <- speed_mult * mach * speed_sound tas }
函数调用
mach <- 2.04 alt <- "53000" spdata <- data %>% mutate( tas = calc_tas(mach, pick(starts_with("tmpc") & ends_with(alt))) )
实际输出
> spdata structure(list(tmpc39000 = c(-55, -56, -56, -57, -56, -56), tmpc45000 = c(-64, -65, -64, -63, -64, -64), tmpc53000 = c(-64, -64, -63, -63, -64, -63), tas = structure(list(tmpc53000 = c(1149.6502039295, 1149.6502039295, 1152.39531338665, 1152.39531338665, 1149.6502039295, 1152.39531338665 )), row.names = c(NA, -6L), class = "data.frame")), row.names = c(NA, -6L), class = c("tbl_df", "tbl", "data.frame"))
期望输出
> spdata structure(list(tmpc39000 = c(-55, -56, -56, -57, -56, -56), tmpc45000 = c(-64, -65, -64, -63, -64, -64), tmpc53000 = c(-64, -64, -63, -63, -64, -63), tas = c(1174.12516099369, 1171.43097396222, 1171.43097396222, 1168.73057623976, 1171.43097396222, 1171.43097396222)), row.names = c(NA, -6L), class = c("tbl_df", "tbl", "data.frame"))
原因分析
函数写法本身没有错误,问题出在**pick函数的返回值类型**:pick返回的是一个由匹配列组成的数据框(data.frame/tbl),而calc_tas函数的temp参数期望接收的是一个数值向量。当把数据框传入函数后,内部的数学运算会保留数据框的结构,最终输出也会是数据框,导致mutate生成嵌套列。
解决方案
可以通过以下几种方式解决:
方案1:用pull提取向量(调用时处理)
pull会从数据框中提取指定列的向量,替代pick的组合使用:
spdata <- data %>% mutate( tas = calc_tas(mach, pull(pick(starts_with("tmpc") & ends_with(alt)))) )
方案2:在函数内强制转换为向量(修改函数增强健壮性)
在calc_tas函数开头添加一行代码,将输入的temp转为向量,兼容向量和数据框两种输入:
calc_tas <- function(mach, temp, units = "knots") { temp <- as.vector(temp) # 新增:将输入转为向量 if (units == "knots") { speed_mult <- 1 / knots_to_ms } else { speed_mult <- 1 } speed_sound <- sqrt(gamma * r_star * (temp + degc_to_degk)) tas <- speed_mult * mach * speed_sound tas }
方案3:直接提取pick结果的第一列(适合确定仅匹配一列的场景)
如果能确定starts_with和ends_with只会匹配到一列,可以用[[1]]提取数据框的第一列向量:
spdata <- data %>% mutate( tas = calc_tas(mach, pick(starts_with("tmpc") & ends_with(alt))[[1]]) )
内容的提问来源于stack exchange,提问作者qwertytam
相关产品推荐
相关产品推荐

