如何在R中重载函数参数?

如何在R中重载函数参数?,r,R,简化代码,其中有两个参数年龄和性别;不过,我只想按性别或年龄来挑选案例;我在想,你怎么能在不重复相同代码的情况下重载getIDsage和getIDsgender;假设您有50个参数等;我尝试了getIDsage,但我认为这不是一个好主意 getIDs <- function(age, gender) { # https://stackoverflow.com/a/40330110/54964 ageIDs <- c(1,2,3) genderIDs # du

简化代码,其中有两个参数年龄和性别;不过,我只想按性别或年龄来挑选案例;我在想,你怎么能在不重复相同代码的情况下重载getIDsage和getIDsgender;假设您有50个参数等;我尝试了getIDsage,但我认为这不是一个好主意

getIDs <- function(age, gender) {
    # https://stackoverflow.com/a/40330110/54964

    ageIDs <- c(1,2,3)
    genderIDs # dummy code here to indicate that do not use genderIDs if gender ""

    intersect(ageIDs, genderIDs)
}
数据2

DF <- structure(list(ID = 100:104, Age = c(69L, 75L, 84L, NA, 66L), Gender = 
c("male", "female", "female", "male", "female")), .Names = c("ID", "Age", 
"Gender"), row.names = c(NA, -5L), class = "data.frame") 
操作系统:Debian8.5
R:3.1.1

您可以为参数指定默认值并在下游捕获它们

例如,如果将age=NULL,则可以使用

if (is.null(age)) {
    # do something
}
其他参数也是如此。另一个好的选择是使用NA,由is.NA函数捕获

编辑 在讨论之后,五十个参数在任何情况下都是需要处理的。根据您的需要,您有多种选择

如果所有参数都是相同的数据类型,则可以使用命名向量,例如

x <- c(arg1 = "1", arg2 = "this")
在R中使用列表是非常自然的,您可以使用sappy或lappy等工具对其进行操作。你可以找到所有的数值

> x[sapply(x, is.numeric)]
$par1
[1] 1
或者仅仅基于名字

> x[grepl(paste("par", 1:2, sep = "", collapse = "|"), names(x))]
$par1
[1] 1

$par2
[1] "2"
使用dplyr,您可以编写一个通用函数,在这个函数中,您可以将任何条件作为字符串传递给函数,它将返回值。这很容易扩展到多个参数,只要dplyr可以评估您的条件字符串,那么输出是使用您提供的数据帧生成的:

以这种方式定义函数是magrittr链的一个特点

如果要将一系列查询作为参数传递:

getIDs <- function(...){
    DF %>% filter_(...) %>% .$ID
} 

getIDs("Gender == 'male'", "Age > 30")
# [1] 100

按照罗曼的想法,我可能会使用一个列表:

library(data.table)
setDT(DF)

getIDs <- function(L) DF[L, on=names(L), ID]
资料


我从不使用它,但missing似乎也在某种程度上使用它,比如f=functiona,b如果缺少b a,b其他b;f1,2;f1。。?哦,没关系,重读OP的问题,我现在完全糊涂了。@Frank,你能把你的评论扩展成一个答案,这样我能更好地理解它吗?我把罗曼的答案暗示到身体里,它有50个参数的严重限制。很难维护。@Roman,你能将你的提案与yeedle的提案进行比较吗?yeedle的提案非常灵活,我非常喜欢。如果年龄是一个数字,性别是一个字符串,则可以区分getIDsage和getIDsgender。不过,R中的数据类型太多了,如果您有50种数据类型,希望函数在不传递参数名称的情况下匹配,那就麻烦了。我理解您的意思是要求getIDs45和getIDsmale应该工作。。。对吗?对于50个参数,一个命名向量可能是一个更好的解决方案。如果你找到任何可能的解决方案,请参阅我问题的编辑。它使用了一个完全不同的范例。在一天结束时,使用50个参数,您必须对条件进行大量手动枚举。我发现使用显式条件和清晰的转换步骤链更容易。其他人则喜欢base R的简洁性。与其每次调用函数时都读取数据,不如将其分配给环境。同样,在这种情况下,您可以使用一个链来编写整个函数:getIDs%filter\u DF,.%>%$身份证件environmentgetIDs$DF是正确的@Frank。在OP中,我只是遵循了Masi的示例。显然,每次读取它都是低效的。绝对:getIDs%filter\uUx…%%>%按%>%.$ID}排列\u。我把它添加到我的答案中,看看我的答案。如果忽略by参数,输出将不会按任何顺序排序。如果指定它,它将按升序排序。如果希望按降序排列,则可以通过=descAge@Masi我不明白你在问什么。@Masi抱歉,我还是不明白。@Masi好的。是的,这很有道理。此答案中的方法仅适用于平等性测试。如果您需要一系列的查询,那么yeedle的最适合。我编辑它是为了演示。
> x[grepl(paste("par", 1:2, sep = "", collapse = "|"), names(x))]
$par1
[1] 1

$par2
[1] "2"
library(dplyr)
getIDs <- function(conditon)
{
  data <- read.csv("/home/masi/data.csv", header = T)
  df <- data %>% filter_(conditon) %>% .$ID
}

getIDs("Gender == 'male'")
# [1] 100 103

getIDs("Age > 30")
# [1] 100 101 102 104

getIDs("Gender == 'male' & Age > 30")
# [1] 100
getIDs <- . %>% filter_(DF, .) %>% .$ID
getIDs <- function(...){
    DF %>% filter_(...) %>% .$ID
} 

getIDs("Gender == 'male'", "Age > 30")
# [1] 100
getIDs <- function(..., by = NULL){
    DF %>% filter_(...) %>% { if (!is.null(by))  arrange_(., by) else . } %>% .$ID
} 

getIDs("Gender == 'female'", "Age > 10", by = "Age")
# [1] 104 101 102

# descending order:
getIDs("Gender == 'female'", "Age > 10", by = "desc(Age)")
# [1] 102 101 104
library(data.table)
setDT(DF)

getIDs <- function(L) DF[L, on=names(L), ID]
> getIDs(list(Gender = "male"))
[1] 100 103
> getIDs(list(Gender = "male", Age = NA))
[1] 103
DF = structure(list(ID = 100:104, Age = c(69L, 75L, 84L, NA, 66L), 
Gender = c("male", "female", "female", "male", "female")), .Names = c("ID", 
"Age", "Gender"), row.names = c(NA, -5L), class = "data.frame")