我需要编写一个将dataframe列作为参数的函数,并且如果缺少任何这些,将向数据框添加新变量,例如从
开始 foo bar
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
8 8 8
9 9 9
10 10 10
为:
foo bar arg3
1 1 1 NA
2 2 2 NA
3 3 3 NA
4 4 4 NA
5 5 5 NA
6 6 6 NA
7 7 7 NA
8 8 8 NA
9 9 9 NA
10 10 10 NA
。到目前为止,我有这个例子:
df <- data.frame(foo = 1:10, bar = 1:10)
CheckData <- function(data, arg1 = NULL, arg2 = NULL, arg3 = NULL) {
list_args <- list(arg1, arg2, arg3)
# lapply(list_args, function(x) if(is.null(x)) data[[x]] <<- NA)
# lapply(list_args, function(x) if(is.null(x)) data$x <<- NA)
return(data)
}
CheckData(df, arg1 = 'foo', arg2 = 'bar')
所以,我传递了一个带有2列数据帧的函数,foo&amp; bar,允许arg3为NULL
,默认值。在注释掉的2行中,我们有2个选项 -
arg3
中的list_args
为NULL
,应创建一个新变量data[[arg3]]
&amp;填充NA
s。但是,这不起作用,我想知道是否有一些非标准的评估可能会对此有所帮助,因此它不会将其视为NULL
对象而是名称/字符串。df$x
的变量,而不是df$arg3
。 我可以逐个明确地这样做,例如
CheckData <- function(data, arg1 = NULL, arg2 = NULL, arg3 = NULL) {
if(is.null(arg1)) data$arg1 <- NA
if(is.null(arg2)) data$arg2 <- NA
if(is.null(arg3)) data$arg3 <- NA
return(data)
}
CheckData(df, arg1 = 'foo', arg2 = 'bar')
但这样做不够优雅,需要事先了解所有可能的变量,这对我的需求来说是不现实的。
对于高级R程序员来说,这似乎应该是一个相当直接的问题,但是我被阻止了,尽管经过了几个小时的搜索和反复试验,却无法找到解决方案。非常感谢您的帮助
答案 0 :(得分:1)
以下是您想要的:
CheckArgs = function (df, ...) {
args = list(...)
for (arg in names(args)) {
if (! arg %in% names(df))
df[[arg]] = args[[arg]]
}
df
}
或者,以下内容相同,但没有循环:
CheckArgs = function (df, ...) {
args = list(...)
missing = ! names(args) %in% names(df)
df[names(args)[missing]] = args[missing]
df
}
用法:
df = CheckArgs(df, a = NA, b = NA, c = NA)
如果您只想用NA
s填充向量,那么更好的解决方案是使用一个允许您只指定所需名称的函数:
df = CheckArgs(df, c('a', 'b', 'c'))
...或者沿着这些方向的东西。这当然可以很容易地以同样的方式完成:
CheckArgs = function (df, required_names) {
missing = ! required_names %in% names(df)
df[required_names[missing]] = NA
df
}
答案 1 :(得分:0)
我设法找到了一个解决方案,使用plyr
包中的一些固有功能,并使用assign
代替赋值运算符(<-
),这使我可以拥有映射到变量的参数,如下所示:
library(magrittr)
dat <- data.frame(foo = 1:10, bar = letters[1:10])
CheckData <- function(data, arg1 = NULL, arg2 = NULL, arg3 = NULL, arg4 = NULL) {
# create dataframe of missing/unmatched arguments
list_args <-
list(arg1, arg2, arg3, arg4) %>%
setNames(c('arg1', 'arg2', 'arg3', 'arg4')) %>%
plyr::ldply(function(x) if(is.null(x)) NA)
# create new variables based on these missing arguments; map the arguments to these variables
for(i in list_args[[1]]) {data[[i]] <- NA; assign(i, i)}
return(data)
}
tmp <- CheckData(dat, arg1 = 'foo', arg2 = 'bar')
给出了以下数据帧,这正是我想要的:
foo bar arg3 arg4
1 1 a NA NA
2 2 b NA NA
3 3 c NA NA
4 4 d NA NA
5 5 e NA NA
6 6 f NA NA
7 7 g NA NA
8 8 h NA NA
9 9 i NA NA
10 10 j NA NA