下面,我包含了一个非常符合人体工程学的解决方案,它(几乎)无缝地模仿了dplyr 工作流程的熟悉感觉。我还花了一些时间来诊断和解决概念上的缺陷。
一个常见的混淆来源是 R 传递值而不是引用。除了程序化dplyr 的细微差别之外,这一事实也是造成代码中两个概念性错误的原因。
为方便起见,我在此将您的sp_merrel_df_raw 转载为data.frame:
structure(list(product_name = c("Merrell Riverbed 3", "Sapatilhas Montanha Merrell", "Merrell Moab Adventure", "Merrell Moab 2 Vent"),
price_new = c("59,99 €", "149,99 €", "99,99 €", "79,99 €"),
price_old = c("69,99 €", NA, NA, "99,99 €"),
date = c(210720, 210720, 210720, 210720)),
row.names = c(NA, -4L),
class = "data.frame")
您不能“就地”修改
偶然地,我clarified 前段时间确实有这种困惑。假设你有一个简单的numeric 变量a 和一个简单的函数doubler():
x <- 2
doubler <- function(num) {
num <- 2 * num
}
现在除了(不可见地)返回4 之外,只需运行doubler(x) 即可执行absolutely nothing。所发生的只是参数num 被传递值 2,然后num 被4 覆盖在函数的范围内。但是,原始变量 x 保持不变:
doubler(x)
x
# [1] 2
为了修改x,我们必须用函数的结果覆盖它(<-):
x <- doubler(x)
x
# [1] 4
类似地,当您运行 currency_to_numeric() 函数时
currency_to_numeric(raw = sp_merrel_df_raw, clean = sp_merrel_df_clean2, var = price_new)
它将接受sp_merrel_df_clean2 的值,并将该值 分配给它的clean 参数。之后发生的一切
clean <- raw %>% # ...
只影响clean在函数的范围内。说到底,sp_merrel_df_clean2 永远不会受到影响。
相反,需要这样的东西,用新值覆盖 sp_merrel_df_clean2 :
currency_to_numeric <- function(raw, ...) {
# ...
}
sp_merrel_df_clean2 <- currency_to_numeric(raw = sp_merrel_df_raw, ...)
去上下文变量
如dplyr documentation 中所述
环境变量是存在于环境中的“编程”变量
而
数据变量是存在于数据框中的“统计”变量。
现在数据变量在某些函数的上下文中被“屏蔽”了,尤其是在dplyr 中。当我们在sp_merrel_df_raw 上执行(比如说)mutate() 时,这种屏蔽让我们将sp_merrel_df_raw$price_new 列简单地称为price_new:
sp_merrel_df_raw %>%
mutate(
price_new = sub(" €", "", price_new)
# ...
)
但是,当您运行 currency_to_numeric() 函数时
currency_to_numeric(raw = sp_merrel_df_raw, clean = sp_merrel_df_clean2, var = price_new)
var不会变成sp_merrel_df_raw$price_new变量本身。
相反,R 在周围环境(此处为 .GlobalEnv)中寻找一些名为 price_new 的 env-variable,并尝试将其 值 分配给 @ 987654366@参数。自然,由于.GlobalEnv 中不存在这样的price_new 变量,因此没有这样的值,所以R 在尝试在mutate() 中使用该值时立即抛出错误:
Error: Problem with `mutate()` column `var`.
i `var = sub(" \200", "", var)`.
x object 'price_new' not found
此错误与您在任何其他不存在的变量上调用函数时所得到的错误相当:
doubler(num = nonexistent_variable)
# Error in doubler(num = nonexistent_variable) :
# object 'nonexistent_variable' not found
然而,即使price_new 作为一个典型的env-variable实际上在.GlobalEnv 中浮动,你仍然会得到一个错误。这是因为将price_new 的值 传递给var 与“粘贴”“名称”price_new 不同
mutate(
price_new = sub(" €", "", price_new),
price_new = sub(",", ".", price_new),
price_new = as.numeric(price_new))
“名称”var 曾经在哪里。
mutate(
var = sub(" €", "", var),
var = sub(",", ".", var),
var = as.numeric(var))
解决方案
这是对currency_to_numeric () 的精巧改造,非常接近dplyr 的典型功能:
currency_to_numeric <- function(raw, ...) {
raw %>%
mutate(
across(c(...), ~ sub(" €", "", .x)),
across(c(...), ~ sub(",", ".", .x)),
across(c(...), ~ as.numeric(.x))
)
}
与几乎所有 R 函数一样,您仍必须将结果分配给sp_merrel_df_clean2,但此解决方案将帮助您非常干净地完成此操作
sp_merrel_df_clean2 <- sp_merrel_df_raw %>%
currency_to_numeric(price_new)
sp_merrel_df_clean2 的结果如下:
product_name price_new price_old date
1 Merrell Riverbed 3 59.99 69,99 € 210720
2 Sapatilhas Montanha Merrell 149.99 <NA> 210720
3 Merrell Moab Adventure 99.99 <NA> 210720
4 Merrell Moab 2 Vent 79.99 99,99 € 210720
事实上,您可以同时定位任意数量的数据变量(如price_new 和price_old)
sp_merrel_df_clean2 <- sp_merrel_df_raw %>%
currency_to_numeric(price_new, price_old)
一举隐藏所有货币列!
product_name price_new price_old date
1 Merrell Riverbed 3 59.99 69.99 210720
2 Sapatilhas Montanha Merrell 149.99 NA 210720
3 Merrell Moab Adventure 99.99 NA 210720
4 Merrell Moab 2 Vent 79.99 99.99 210720