dplyr .data 代词 vs "quosure" 方法
dplyr .data pronoun vs "quosure" approach
在dplyr v0.7.0中,引入了.data
代词,允许我们用字符串引用变量。我只是好奇这种方法是否优于 "quosure" 方法。例如,这是一种使用 .data
代词的方法:
varname <- "gear"
data_pronoun_method_df <- dplyr::mutate(mtcars, new_col = .data[[varname]] + 2)
这与使用 quosure
方法的示例进行了比较:
quo_varname <- rlang::quo(gear)
quo_method_df <- dplyr::mutate(mtcars, new_col = !! quo_varname + 2)
两种方法产生相同的输出:
data_pronoun_method_df
# mpg cyl disp hp drat wt qsec vs am gear carb new_col
# 1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 6
# 2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 6
# 3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 6
# 4 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 5
# 5 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 5
# 6 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 5
# 7 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4 5
# 8 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2 6
# [ reached getOption("max.print") -- omitted 24 rows ]
all.equal(data_pronoun_method_df, quo_method_df)
# [1] TRUE
有什么真正的区别吗?这两种方法的优点和缺点是什么?
.data
代词对于解决 NSE 很有用,但它或多或少与 tidy eval 正交。它的主要目的是确保在数据框中查找变量。如果它不存在,你会得到一个错误。这与可以获取本地对象的裸名形成对比,如果它们被定义的话:
other <- 1e10
transmute(mtcars, 2 * other) # Succeeds erroneously
transmute(mtcars, 2 * .data[["other"]] # Fails
使用 .data
代词比仅明确引用数据框更可靠,因为数据可能已分组:
group_by(mtcars, cyl) %>%
transmute(2L * .data[["am"]])
在该示例中,.data[["am"]]
表示由 cyl
的级别定义的 am
列的切片。
编辑:为了完整起见,您可以使用quosures 和quasiquotation 完成同样的事情。如果您使用空 env 作为环境创建符号的 quosure,则只有数据框包含这样的列时符号查找才会成功:
other <- 1e10
quo <- new_quosure(quote(other), empty_env())
transmute(mtcars, 2L * !!quo) # Fails
在dplyr v0.7.0中,引入了.data
代词,允许我们用字符串引用变量。我只是好奇这种方法是否优于 "quosure" 方法。例如,这是一种使用 .data
代词的方法:
varname <- "gear"
data_pronoun_method_df <- dplyr::mutate(mtcars, new_col = .data[[varname]] + 2)
这与使用 quosure
方法的示例进行了比较:
quo_varname <- rlang::quo(gear)
quo_method_df <- dplyr::mutate(mtcars, new_col = !! quo_varname + 2)
两种方法产生相同的输出:
data_pronoun_method_df
# mpg cyl disp hp drat wt qsec vs am gear carb new_col
# 1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 6
# 2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 6
# 3 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 6
# 4 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 5
# 5 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 5
# 6 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1 5
# 7 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4 5
# 8 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2 6
# [ reached getOption("max.print") -- omitted 24 rows ]
all.equal(data_pronoun_method_df, quo_method_df)
# [1] TRUE
有什么真正的区别吗?这两种方法的优点和缺点是什么?
.data
代词对于解决 NSE 很有用,但它或多或少与 tidy eval 正交。它的主要目的是确保在数据框中查找变量。如果它不存在,你会得到一个错误。这与可以获取本地对象的裸名形成对比,如果它们被定义的话:
other <- 1e10
transmute(mtcars, 2 * other) # Succeeds erroneously
transmute(mtcars, 2 * .data[["other"]] # Fails
使用 .data
代词比仅明确引用数据框更可靠,因为数据可能已分组:
group_by(mtcars, cyl) %>%
transmute(2L * .data[["am"]])
在该示例中,.data[["am"]]
表示由 cyl
的级别定义的 am
列的切片。
编辑:为了完整起见,您可以使用quosures 和quasiquotation 完成同样的事情。如果您使用空 env 作为环境创建符号的 quosure,则只有数据框包含这样的列时符号查找才会成功:
other <- 1e10
quo <- new_quosure(quote(other), empty_env())
transmute(mtcars, 2L * !!quo) # Fails