提取运算符 `$`() returns 函数内的零长度向量
Extraction operator `$`() returns zero-length vectors within function
我在函数内部使用提取运算符 `$() 时遇到问题。如果我在循环外遵循相同的逻辑,则问题不存在,因此我假设可能存在我不知道的范围问题。
一般设置:
## Make some fake data for your reproducible needs.
set.seed(2345)
my_df <- data.frame(cat_1 = sample(c("a", "b"), 100, replace = TRUE),
cat_2 = sample(c("c", "d"), 100, replace = TRUE),
continuous = rnorm(100),
stringsAsFactors = FALSE)
head(my_df)
我正在尝试动态重现这个过程:
index <- which(`$`(my_df, "cat_1") == "a")
my_df$continuous[index]
但是一旦我将这个逻辑编程到一个函数中,它就失败了:
## Function should take a string for the following:
## cat_var - string with the categorical variable name as it appears in df
## level - a level of cat_var appearing in df
## df - data frame to operate on. Function assumes it has a column
## "continuous".
extract_sample <- function(cat_var, level, df = my_df) {
index <- which(`$`(df, cat_var) == level)
df$continuous[index]
}
## Does not work.
extract_sample(cat_var = "cat_1", level = "a")
这是返回 numeric(0)
。对我所缺少的有什么想法吗?也欢迎使用其他方法。
问题不在于功能,而在于 $
处理输入的方式。
cat_var = "cat_1"
length(`$`(my_df,"cat_1"))
#> [1] 100
length(`$`(my_df,cat_var))
#> [1] 0
您可以改用 [[
来达到您想要的结果。
cat_var = "cat_1"
length(`[[`(my_df,"cat_1"))
#> [1] 100
length(`[[`(my_df,cat_var))
#> [1] 100
更新
有人指出,以这种方式使用 [[
很丑陋。它是。当你想写类似 lapply(stuff,'[[',1)
的东西时它很有用
在这里,你可能应该写成my_df[[cat_var]]
。
此外,this question/answer 更详细地说明了为什么 $
无法按您希望的方式工作。
问题在于您对该列进行索引的方式。这只是对你的稍作调整:
extract_sample <- function(cat_var, level, df = my_df) {
index <- df[, cat_var] == level
df$continuous[index]
}
动态使用:
> extract_sample(cat_var = "cat_2", level = "d")
[1] -0.42769207 -0.75650031 0.64077840 -1.02986889 1.34800344 0.70258431 1.25193247
[8] -0.62892048 0.48822673 0.10432070 1.11986063 -0.88222370 0.39158408 1.39553002
[15] -0.51464283 -1.05265106 0.58391650 0.10555913 0.16277385 -0.55387829 -1.07822831
[22] -1.23894422 -2.32291394 0.11118881 0.34410388 0.07097271 1.00036812 -2.01981056
[29] 0.63417799 -0.53008375 1.16633422 -0.57130500 0.61614135 1.06768285 0.74182293
[36] 0.56538633 0.16784205 -0.14757303 -0.70928924 -1.91557732 0.61471302 -2.80741967
[43] 0.40552376 -1.88020372 -0.38821089 -0.42043745 1.87370600 -0.46198139 0.10788358
[50] -1.83945868 -0.11052531 -0.38743950 0.68110902 -1.48026285
问题是 $
是非标准的,在某种意义上,当您不引用参数输入时,它仍然会尝试解析它并使用您键入的内容,即使那是意味着引用另一个变量。
或者更简单地说,正如@42 在 linked question 的第一条评论中所说:
The "$" function does not evaluate its arguments, whereas "[[" does`.
这里有一个更简单的数据集作为示例。
my_df <- data.frame(a=c(1,2))
v <- "a"
比较平时的用法;前两个给出相同的结果,如果你不引用它,它会解析它。所以第三个(现在)显然不能正常工作。
my_df$"a"
## [1] 1 2
my_df$a
## [1] 1 2
my_df$v
## NULL
这正是发生在你身上的事情:
`$`(my_df, "a")
## [1] 1 2
`$`(my_df, v)
## NULL
相反,我们需要在使用 do.call
.
发送到 $
之前评估 v
do.call(`$`, list(my_df, v))
## [1] 1 2
或者,更恰当地说,使用首先评估参数的 [[
版本。
`[[`(my_df, v)
## [1] 1 2
我在函数内部使用提取运算符 `$() 时遇到问题。如果我在循环外遵循相同的逻辑,则问题不存在,因此我假设可能存在我不知道的范围问题。
一般设置:
## Make some fake data for your reproducible needs.
set.seed(2345)
my_df <- data.frame(cat_1 = sample(c("a", "b"), 100, replace = TRUE),
cat_2 = sample(c("c", "d"), 100, replace = TRUE),
continuous = rnorm(100),
stringsAsFactors = FALSE)
head(my_df)
我正在尝试动态重现这个过程:
index <- which(`$`(my_df, "cat_1") == "a")
my_df$continuous[index]
但是一旦我将这个逻辑编程到一个函数中,它就失败了:
## Function should take a string for the following:
## cat_var - string with the categorical variable name as it appears in df
## level - a level of cat_var appearing in df
## df - data frame to operate on. Function assumes it has a column
## "continuous".
extract_sample <- function(cat_var, level, df = my_df) {
index <- which(`$`(df, cat_var) == level)
df$continuous[index]
}
## Does not work.
extract_sample(cat_var = "cat_1", level = "a")
这是返回 numeric(0)
。对我所缺少的有什么想法吗?也欢迎使用其他方法。
问题不在于功能,而在于 $
处理输入的方式。
cat_var = "cat_1"
length(`$`(my_df,"cat_1"))
#> [1] 100
length(`$`(my_df,cat_var))
#> [1] 0
您可以改用 [[
来达到您想要的结果。
cat_var = "cat_1"
length(`[[`(my_df,"cat_1"))
#> [1] 100
length(`[[`(my_df,cat_var))
#> [1] 100
更新
有人指出,以这种方式使用 [[
很丑陋。它是。当你想写类似 lapply(stuff,'[[',1)
在这里,你可能应该写成my_df[[cat_var]]
。
此外,this question/answer 更详细地说明了为什么 $
无法按您希望的方式工作。
问题在于您对该列进行索引的方式。这只是对你的稍作调整:
extract_sample <- function(cat_var, level, df = my_df) {
index <- df[, cat_var] == level
df$continuous[index]
}
动态使用:
> extract_sample(cat_var = "cat_2", level = "d")
[1] -0.42769207 -0.75650031 0.64077840 -1.02986889 1.34800344 0.70258431 1.25193247
[8] -0.62892048 0.48822673 0.10432070 1.11986063 -0.88222370 0.39158408 1.39553002
[15] -0.51464283 -1.05265106 0.58391650 0.10555913 0.16277385 -0.55387829 -1.07822831
[22] -1.23894422 -2.32291394 0.11118881 0.34410388 0.07097271 1.00036812 -2.01981056
[29] 0.63417799 -0.53008375 1.16633422 -0.57130500 0.61614135 1.06768285 0.74182293
[36] 0.56538633 0.16784205 -0.14757303 -0.70928924 -1.91557732 0.61471302 -2.80741967
[43] 0.40552376 -1.88020372 -0.38821089 -0.42043745 1.87370600 -0.46198139 0.10788358
[50] -1.83945868 -0.11052531 -0.38743950 0.68110902 -1.48026285
问题是 $
是非标准的,在某种意义上,当您不引用参数输入时,它仍然会尝试解析它并使用您键入的内容,即使那是意味着引用另一个变量。
或者更简单地说,正如@42 在 linked question 的第一条评论中所说:
The "$" function does not evaluate its arguments, whereas "[[" does`.
这里有一个更简单的数据集作为示例。
my_df <- data.frame(a=c(1,2))
v <- "a"
比较平时的用法;前两个给出相同的结果,如果你不引用它,它会解析它。所以第三个(现在)显然不能正常工作。
my_df$"a"
## [1] 1 2
my_df$a
## [1] 1 2
my_df$v
## NULL
这正是发生在你身上的事情:
`$`(my_df, "a")
## [1] 1 2
`$`(my_df, v)
## NULL
相反,我们需要在使用 do.call
.
$
之前评估 v
do.call(`$`, list(my_df, v))
## [1] 1 2
或者,更恰当地说,使用首先评估参数的 [[
版本。
`[[`(my_df, v)
## [1] 1 2