R中的函数,用于验证data.frame上特定列的存在

时间:2018-11-05 15:32:59

标签: r validation dataframe

我想验证data.frame是否包含具有特定名称的列。理想情况下,这将是一个实用函数,我可以只传递data.frame和期望的列名,如果data.frame不包含期望的列,则该函数将引发错误。我在下面编写了自己的函数,但是,这似乎已经存在于R生态系统中。

我的问题是:

  1. 这样的功能(或单行)是否已经存在于base R或通用包中?
  2. 如果没有,对我的功能有什么建议(如下)?

我为此编写的函数示例:

validate_df_columns <- function(df, columns) {
    chr_df <- deparse(substitute(df))
    chr_columns <- paste(columns, collapse = ", ")
    if (!('data.frame' %in% class(df))) {
        stop(paste("Argument", df, "must be a data.frame."))
    }
    if (sum(colnames(df) %in% columns) != length(columns)) {
        stop(paste(chr_df, "must contain the columns", chr_columns))
    }
}

validate_df_columns(data.frame(a=1:3, b=4:6), c("a", "b", "c'"))
## Error in validate_df_columns(data.frame(a = 1:3, b = 4:6), c("a", "b",  : 
##   data.frame(a = 1:3, b = 4:6) must contain the columns a, b, c'

2 个答案:

答案 0 :(得分:3)

tibble中的软件包rlangtidyverse具有检查此功能的功能:

library(tibble) # or library(rlang) or library(tidyverse)
has_name(iris, c("Species","potatoe"))
# [1]  TRUE FALSE

从技术上讲,它位于rlang中,其代码仅为:

function (x, name) 
{
    name %in% names2(x)
}

其中rlang::names2base::names的增强版本,当对象没有名称时,它返回空字符串向量,而不是NULL

这是一种重写函数的方法:

validate_df_columns <- function(df, columns){
if (!is.data.frame(df)) {
    stop(paste("Argument", deparse(substitute(df)), "must be a data.frame."))
}
  if(!all(i <- rlang::has_name(df,columns)))
    stop(sprintf(
      "%s doesn't contain: %s",
      deparse(substitute(df)),
      paste(columns[!i], collapse=", ")))
}

validate_df_columns(iris, c("Species","potatoe","banana"))
# Error in validate_df_columns(iris, c("Species", "potatoe", "banana")) : 
# iris doesn't contain: potatoe, banana

在这里使用deparse(substitute(...))对我来说意义不大,因为它不是交互式使用的,所以我认为只说"df"就更清楚了。

答案 1 :(得分:0)

%in%运算符可以处理成对的向量,因此我们已经可以使用单线了。考虑:

df <- data.frame(a=c(1:3), b=c(4:6), c=c(7:9))
names <- c("a", "c", "blah", "doh")
names[names %in% names(df)]

[1] "a" "c"

如果要断言数据框包含所有输入名称,则只需使用:

length(names %in% names(df)) == length(names)     # to check all inputs are present
length(names %in% names(df)) == length(names(df)) # to check that input matches df