在R函数中无需显式引用数据框直接调用列的更佳实现方法
在R函数中直接调用数据框列名的替代方案
我希望在R函数里直接通过列名调用数据框的列(仅写列名即可),而非每次都写df$columnname或df["columnname"]。使用attach()函数可实现此需求,但听说该函数存在性能不佳等问题。目前我实现的代码及调用输出如下:
第一次调用代码与输出
> somefunction <- function(df1,df2) {attach(df1); attach(df2); mean(Sepal.Length) + speed*3} > somefunction(iris, cars) The following objects are masked from iris: Petal.Length, Petal.Width, Sepal.Length, Sepal.Width, Species The following objects are masked from b (pos = 5): Petal.Length, Petal.Width, Sepal.Length, Sepal.Width, Species The following objects are masked from a (pos = 6): Petal.Length, Petal.Width, Sepal.Length, Sepal.Width, Species The following objects are masked from a (pos = 8): Petal.Length, Petal.Width, Sepal.Length, Sepal.Width, Species The following objects are masked from cars: dist, speed The following objects are masked from b (pos = 8): dist, speed [1] 17.84333 17.84333 26.84333 26.84333 29.84333 32.84333 35.84333 35.84333 35.84333 38.84333 38.84333 41.84333 41.84333 41.84333 41.84333 44.84333 [17] 44.84333 44.84333 44.84333 47.84333 47.84333 47.84333 47.84333 50.84333 50.84333 50.84333 53.84333 53.84333 56.84333 56.84333 56.84333 59.84333 [33] 59.84333 59.84333 59.84333 62.84333 62.84333 62.84333 65.84333 65.84333 65.84333 65.84333 65.84333 71.84333 74.84333 77.84333 77.84333 77.84333 [49] 77.84333 80.84333
再次调用的输出
> somefunction(iris, cars) The following objects are masked from df1 (pos = 4): Petal.Length, Petal.Width, Sepal.Length, Sepal.Width, Species The following objects are masked from iris: Petal.Length, Petal.Width, Sepal.Length, Sepal.Width, Species The following objects are masked from b (pos = 7): Petal.Length, Petal.Width, Sepal.Length, Sepal.Width, Species The following objects are masked from a (pos = 8): Petal.Length, Petal.Width, Sepal.Length, Sepal.Width, Species The following objects are masked from a (pos = 10): Petal.Length, Petal.Width, Sepal.Length, Sepal.Width, Species The following objects are masked from df2 (pos = 4): dist, speed The following objects are masked from cars: dist, speed The following objects are masked from b (pos = 10): dist, speed [1] 17.84333 17.84333 26.84333 26.84333 29.84333 32.84333 35.84333 35.84333 35.84333 38.84333 38.84333 41.84333 41.84333 41.84333 41.84333 44.84333 [17] 44.84333 44.84333 44.84333 47.84333 47.84333 47.84333 47.84333 50.84333 50.84333 50.84333 53.84333 53.84333 56.84333 56.84333 56.84333 59.84333 [33] 59.84333 59.84333 59.84333 62.84333 62.84333 62.84333 65.84333 65.84333 65.84333 65.84333 65.84333 71.84333 74.84333 77.84333 77.84333 77.84333 [49] 77.84333 80.84333
可以看到调用时出现大量变量遮蔽警告,且pos值会随调用次数变化,并非理想情况。请问是否有更好的实现方法?
可行替代方案
1. 使用with()函数
with()可以指定数据框作为临时环境,在括号内直接引用列名,不会污染全局环境,也不会出现变量遮蔽问题:
somefunction <- function(df1, df2) { # 从df1中计算Sepal.Length的均值 mean_sepal <- with(df1, mean(Sepal.Length)) # 在df2的环境中计算结果 with(df2, mean_sepal + speed * 3) } somefunction(iris, cars)
2. 使用tidyverse系列工具(dplyr)
现代R常用的tidyverse语法支持直接引用列名,代码可读性高,适合数据处理场景:
library(dplyr) somefunction <- function(df1, df2) { mean_sepal <- df1 %>% pull(Sepal.Length) %>% mean() df2 %>% transmute(result = mean_sepal + speed * 3) %>% pull() } somefunction(iris, cars)
3. 使用data.table
data.table不仅支持直接引用列名,还具备高效的大数据处理能力:
library(data.table) somefunction <- function(df1, df2) { dt1 <- as.data.table(df1) dt2 <- as.data.table(df2) mean_sepal <- dt1[, mean(Sepal.Length)] dt2[, mean_sepal + speed * 3] } somefunction(iris, cars)
4. 自定义临时环境(进阶)
如果需要模拟attach()的全局式引用,可创建临时环境存放数据框列,用完即销毁,避免污染全局环境:
somefunction <- function(df1, df2) { temp_env <- new.env() # 将两个数据框的列导入临时环境 list2env(as.list(df1), envir = temp_env) list2env(as.list(df2), envir = temp_env) # 在临时环境中计算结果 result <- with(temp_env, mean(Sepal.Length) + speed * 3) # 销毁临时环境 rm(temp_env) result } somefunction(iris, cars)
内容的提问来源于stack exchange,提问作者Aku-Ville Lehtimäki
相关产品推荐
相关产品推荐

