如何在R中重载功能参数?

时间:2016-10-31 18:39:29

标签: r

两个参数agegender的简化代码;但是,我想仅通过genderage选择案例;我在想如何重载到getIDs(age)getIDs(gender),而不会一次又一次地相乘相同的代码;假设您有50个参数等;我试过getIDs(age, ""),但我不是个好主意

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)
}

主要数据

ID,Age,Gender
100,69,male
101,75,female
102,84,female
103,,male
104,66,female

数据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") 

同样适用于年龄:如果age=="",请不要包含subset ageIDs。

所有男性的某些参数都很棒,因此您无需明确"male", "male", ...

基于罗马answer

的算法

我认为这个策略对50个参数非常具有挑战性,因此仍然需要更好的方法

getIDs <- function(age, gender) {
# https://stackoverflow.com/a/40330110/54964
# So if you called this as getIDs(c(20, 30), "male")
# You'd get the ids of all males with age >= 20 and <= 30
# 
# NULL = ALL
# getIDs(age = c(1,2), gender = NULL)
# getIDs(age = NULL, gender = "male")
        data <- read.csv("/home/masi/data.csv",header = TRUE,sep = ",")

        if (is.null(gender)) {
                genderIDs <- data$ID
        } else {
                gender <- data$Gender == gender
                genderIDs <- data[which(gender), ]$ID
        }

        if (is.null(age)) {
                age <- c(0,130)
        }
        if (length(age) == 1) {
                ages <- data$Age == age
        } else {
                ages <- (data$Age >= age[1] & data$Age <= age[2])
        }
        ageIDs <- data[which(ages), ]$ID

        intersect(ageIDs, genderIDs)
}
操作系统:Debian 8.5
R:3.1.1

3 个答案:

答案 0 :(得分:5)

您可以为参数指定默认值并将其捕获到下游。

例如,如果您创建age = NULL,则可以使用

捕获它
if (is.null(age)) {
    # do something
}

其他参数也是如此。另一个不错的选择是使用由NA函数捕获的is.na

修改

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

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

x <- c(arg1 = "1", arg2 = "this")

如果您有不同的数据类型,并且您不希望它们被强制转换为一种类型(数字将被强制转换为字符,如果一个参数是字符,请尝试c(1, "2")),您可以使用列表。< / p>

x <- list(par1 = 1,
          par2 = "2",
          par3 = factor(3),
          par4 = TRUE)

在R中使用列表非常自然,您可以使用例如sapplylapply。您可以找到所有数值

> x[sapply(x, is.numeric)]
$par1
[1] 1

或仅仅基于名称

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

$par2
[1] "2"

答案 1 :(得分:4)

遵循罗马的想法,我可能会使用一个列表:

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")

答案 2 :(得分:3)

使用dplyr,您可以编写一个通用函数,您可以将您喜欢的任何条件作为字符串传递给函数,它将返回值。这可以轻松扩展到多个参数,只要您的条件字符串可以由dplyr评估(输出是使用您提供的数据框生成的in this question

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

如果你不需要在函数中读入data,那么函数可以写成

getIDs <- . %>% filter_(DF, .) %>% .$ID

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

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

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

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

如果您希望按其中一个参数对结果进行排序,请在dplyr pipline中添加arrange

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