函数不能嵌入到另一个函数中
Function does not work embedded in another function
在我的数据集中,ID 具有不止一个不同的名称。为了检测它们,我构建了这个函数:
ddply(my_dataframe, ~ID_col, summarise, number_of_names = length(unique(names_col)))
效果很好,所以我得到了一个 table,第一列是 ID,第二列是不同名称的数量。
因为我需要对几个 ID/name-pairs 执行此操作,所以我决定将 ddply 函数放在一个函数中。我是这样做的:
function_name = function (source, id, name) {
ddply(source, ~id, summarise, number_of_names = length(unique(name)))
不幸的是,当我使用它时会抛出一个错误:
function_name(my_dataframe, ID_col, names_col)
# Error in unique.default(x) : unique() applies only to vectors
如您所见,它与之前的代码完全相同,但嵌入到具有三个变量的函数中。我非常想修复它,真的很期待解决方案。
仅供参考:
在我的原始代码中,我没有使用 "source" 或 "name" 而是德语单词,因此对于现有的其他功能应该没有问题。我也已经尝试将变量放在引号中。
感谢您的帮助!
这是 DF 的样子:
my_dataframe <- data.frame(
ID_col = c(letters[2:9], letters[3:4]),
names_col = paste0("name-", letters[1:10])
)
ID 有 303 个,名字有 963 个。
我们可以用 dplyr
中的 quosure
来做到这一点。 enquo
获取输入变量,转换为quosure
,在group_by
、summarise
中,我们取消引用(UQ
)求值的quosure
library(dplyr)
f1 <- function(source, id, name) {
id <- enquo(id)
name <- enquo(name)
source %>%
group_by(UQ(id)) %>%
summarise(number_of_names = n_distinct(UQ(name)))
}
f1(my_dataframe, ID_col, names_col)
# A tibble: 3 x 2
# ID_col number_of_names
# <chr> <int>
#1 FU181 2
#2 FU901 1
#3 FU992 1
注意:该解决方案基于 dplyr
,它是 plyr
的更高级版本。该解决方案采用不带引号的输入参数,也可以对其进行修改以采用带引号的参数。该解决方案可以用管道扩展(%>%
)并且非常灵活
注意 2:我们没有发现 tidyverse
变得更乱,但实际上与以前的 lazyeval
解决方案相比,它更干净、更一致
数据
my_dataframe <- structure(list(ID_col = c("FU901", "FU992", "FU181", "FU181"),
names_col = c("take a breath", "use a tissue", "get up",
"getting up")), .Names = c("ID_col", "names_col"), class = "data.frame", row.names = c("1",
"2", "3", "4"))
R 一直具有使用双方括号按变量名的值选择列的功能。使用 tapply
你可以这样做:
function_name = function (source, id, name) {
data.frame(
N=tapply(
source[[name]],
my_dataframe[[id]],
function(x){
length(unique(x))
}
)
)
}
然后:
> function_name(my_dataframe,"ID_col","names_col")
N
FU181 2
FU901 1
FU992 1
注意名称在返回的数据框的行名称中。
1) eval/substitute 将正文包裹在 eval.parent(substitute(...)) 中,使参数被替换。 ddply(...)
下面一行与问题中的相同。
library(plyr)
function_name = function (source, id, name) eval.parent(substitute(
ddply(source, ~id, summarise, number_of_names = length(unique(name)))
))
function_name(my_dataframe, ID_col, names_col)
2) substitute 这也行,不依赖 eval
:
function_name = function (source, id, name) {
id <- substitute(id)
name <- deparse(substitute(name))
ddply(source, id, function(x) summarise(x, number_of_names = length(unique(x[[name]]))))
}
function_name(my_dataframe, ID_col, names_col)
2a) pass strings 如果你愿意传递字符串,它可以缩短为这个,这与 (2) 相同,只是我们省略了前两行body,我们在调用它的时候传递字符串:
function_name = function (source, id, name) {
ddply(source, id, function(x) summarise(x, number_of_names = length(unique(x[[name]]))))
}
function_name(my_dataframe, "ID_col", "names_col")
3) defmacro 另一种方法是在 gtools 中使用 defmacro
创建一个宏。 ddply(...)
调用与问题中的调用相同。
library(gtools)
macro_name <- defmacro(source, id, name, expr =
ddply(source, ~id, summarise, number_of_names = length(unique(name)))
)
macro_name(my_dataframe, ID_col,names_col)
在我的数据集中,ID 具有不止一个不同的名称。为了检测它们,我构建了这个函数:
ddply(my_dataframe, ~ID_col, summarise, number_of_names = length(unique(names_col)))
效果很好,所以我得到了一个 table,第一列是 ID,第二列是不同名称的数量。
因为我需要对几个 ID/name-pairs 执行此操作,所以我决定将 ddply 函数放在一个函数中。我是这样做的:
function_name = function (source, id, name) {
ddply(source, ~id, summarise, number_of_names = length(unique(name)))
不幸的是,当我使用它时会抛出一个错误:
function_name(my_dataframe, ID_col, names_col)
# Error in unique.default(x) : unique() applies only to vectors
如您所见,它与之前的代码完全相同,但嵌入到具有三个变量的函数中。我非常想修复它,真的很期待解决方案。
仅供参考: 在我的原始代码中,我没有使用 "source" 或 "name" 而是德语单词,因此对于现有的其他功能应该没有问题。我也已经尝试将变量放在引号中。
感谢您的帮助!
这是 DF 的样子:
my_dataframe <- data.frame(
ID_col = c(letters[2:9], letters[3:4]),
names_col = paste0("name-", letters[1:10])
)
ID 有 303 个,名字有 963 个。
我们可以用 dplyr
中的 quosure
来做到这一点。 enquo
获取输入变量,转换为quosure
,在group_by
、summarise
中,我们取消引用(UQ
)求值的quosure
library(dplyr)
f1 <- function(source, id, name) {
id <- enquo(id)
name <- enquo(name)
source %>%
group_by(UQ(id)) %>%
summarise(number_of_names = n_distinct(UQ(name)))
}
f1(my_dataframe, ID_col, names_col)
# A tibble: 3 x 2
# ID_col number_of_names
# <chr> <int>
#1 FU181 2
#2 FU901 1
#3 FU992 1
注意:该解决方案基于 dplyr
,它是 plyr
的更高级版本。该解决方案采用不带引号的输入参数,也可以对其进行修改以采用带引号的参数。该解决方案可以用管道扩展(%>%
)并且非常灵活
注意 2:我们没有发现 tidyverse
变得更乱,但实际上与以前的 lazyeval
数据
my_dataframe <- structure(list(ID_col = c("FU901", "FU992", "FU181", "FU181"),
names_col = c("take a breath", "use a tissue", "get up",
"getting up")), .Names = c("ID_col", "names_col"), class = "data.frame", row.names = c("1",
"2", "3", "4"))
R 一直具有使用双方括号按变量名的值选择列的功能。使用 tapply
你可以这样做:
function_name = function (source, id, name) {
data.frame(
N=tapply(
source[[name]],
my_dataframe[[id]],
function(x){
length(unique(x))
}
)
)
}
然后:
> function_name(my_dataframe,"ID_col","names_col")
N
FU181 2
FU901 1
FU992 1
注意名称在返回的数据框的行名称中。
1) eval/substitute 将正文包裹在 eval.parent(substitute(...)) 中,使参数被替换。 ddply(...)
下面一行与问题中的相同。
library(plyr)
function_name = function (source, id, name) eval.parent(substitute(
ddply(source, ~id, summarise, number_of_names = length(unique(name)))
))
function_name(my_dataframe, ID_col, names_col)
2) substitute 这也行,不依赖 eval
:
function_name = function (source, id, name) {
id <- substitute(id)
name <- deparse(substitute(name))
ddply(source, id, function(x) summarise(x, number_of_names = length(unique(x[[name]]))))
}
function_name(my_dataframe, ID_col, names_col)
2a) pass strings 如果你愿意传递字符串,它可以缩短为这个,这与 (2) 相同,只是我们省略了前两行body,我们在调用它的时候传递字符串:
function_name = function (source, id, name) {
ddply(source, id, function(x) summarise(x, number_of_names = length(unique(x[[name]]))))
}
function_name(my_dataframe, "ID_col", "names_col")
3) defmacro 另一种方法是在 gtools 中使用 defmacro
创建一个宏。 ddply(...)
调用与问题中的调用相同。
library(gtools)
macro_name <- defmacro(source, id, name, expr =
ddply(source, ~id, summarise, number_of_names = length(unique(name)))
)
macro_name(my_dataframe, ID_col,names_col)