为什么子集不介意丢失数据帧的子集参数?

Vin*_*ent 3 r subset dataframe

通常我想知道神秘错误来自哪里,但现在我的问题是神秘的错误来自何处.

numbers <- c(1, 2, 3)
frame <- as.data.frame(numbers)
Run Code Online (Sandbox Code Playgroud)

如果我输入

subset(numbers, )
Run Code Online (Sandbox Code Playgroud)

(所以我想拿一些子集但忘记指定子集函数的subset-argument)然后R提醒我(应该这样):

subset.default(numbers,)出错:
缺少参数"subset",没有默认值

但是当我打字的时候

subset(frame,)
Run Code Online (Sandbox Code Playgroud)

(所以用一个data.frame而不是向量的东西),它不会给出错误,而只是返回(完整)数据帧.

这里发生了什么?为什么我得不到我应得的错误信息?

lmo*_*lmo 9

tl; dr:该subset函数根据所输入的对象类型调用不同的函数(具有不同的方法).在上面的示例中,subset(numbers, )使用subset.defaultsubset(frame, )使用subset.data.frame.


R内置了几个面向对象的系统.最简单和最常见的是S3.这种OO编程风格实现了Wickham所谓的"泛型函数OO".在这种OO样式下,称为泛型函数的对象查看对象的类,然后将适当的方法应用于对象.如果不存在直接方法,则始终存在可用的默认方法.

为了更好地了解S3如何工作以及其他OO系统的工作原理,您可以查看Advanced R站点的相关部分.找到对象的正确方法的过程称为方法分派.您可以在帮助文件中阅读有关此内容的更多信息?UseMethod.

如详细信息部分所述?subset,subset函数"是一个通用函数".这意味着subset在第一个参数中检查对象的类,然后使用方法分派将适当的方法应用于对象.

泛型函数的方法被编码为

<generic function name>.<class name>

并且可以使用methods(<generic function name>).因为subset,我们得到

methods(subset)
[1] subset.data.frame subset.default    subset.matrix    
see '?methods' for accessing help and source code
Run Code Online (Sandbox Code Playgroud)

表示如果对象具有data.frame类,则subset调用subset.data.frame方法(函数).它的定义如下:

subset.data.frame
function (x, subset, select, drop = FALSE, ...) 
{
    r <- if (missing(subset)) 
        rep_len(TRUE, nrow(x))
    else {
        e <- substitute(subset)
        r <- eval(e, x, parent.frame())
        if (!is.logical(r)) 
            stop("'subset' must be logical")
        r & !is.na(r)
    }
    vars <- if (missing(select)) 
        TRUE
    else {
        nl <- as.list(seq_along(x))
        names(nl) <- names(x)
        eval(substitute(select), nl, parent.frame())
    }
    x[r, vars, drop = drop]
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果缺少子集参数,则为第一行

    r <- if (missing(subset)) 
        rep_len(TRUE, nrow(x))
Run Code Online (Sandbox Code Playgroud)

生成一个与data.frame和最后一行长度相同的TRUES向量

    x[r, vars, drop = drop]
Run Code Online (Sandbox Code Playgroud)

将此向量提供给row参数,这意味着如果您不包含子参数,则该subset函数将返回data.frame的所有行.

正如我们从methods调用的输出中看到的subset那样,没有原子向量的方法.这意味着,作为您的错误

subset.default(数字)出错

当你应用于subset向量时,R调用subset.default定义为的方法

subset.default
function (x, subset, ...) 
{
    if (!is.logical(subset)) 
        stop("'subset' must be logical")
    x[subset & !is.na(subset)]
}
Run Code Online (Sandbox Code Playgroud)

当缺少子集参数时,该subset.default函数抛出错误stop.