您如何在 R 中编写自定义假设检验?

机器算法验证 r 假设检验
2022-04-02 23:49:10

有许多有趣的假设检验R,其中检验的输出以用户友好的格式显示。例如,这里是使用包中函数的Welch 的 T 检验的输出。t.teststats

#Run a T-test on some example data
X <- c(30, 32, 40, 28, 29, 35, 30, 34, 31, 39);
Y <- c(19, 20, 44, 45, 8, 29, 26, 59, 35, 50);
TEST <- stats::t.test(X,Y);

#Print the TEST object
TEST;

        Welch Two Sample t-test

data:  X and Y
t = -0.13444, df = 10.204, p-value = 0.8957
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -12.27046  10.87046
sample estimates:
mean of x mean of y 
     32.8      33.5

如您所见,此测试的输出采用用户友好的格式,提供与测试输出相关的所有必需信息。R当您调用对象时,它以不同于标准输出的格式提供此输出。


问题:假设您遇到了一种不在任何现有R包中的假设检验,并且您希望将此检验编程为一个函数,以便您可以轻松地在新数据上运行它,并获得一个很好的用户友好输出,例如上面那个。你如何编程?

2个回答

这是您通常需要做的事情

假设检验函数在R创建和输出类的列表对象h.test此类对象在其文档中列出了一组特定的所需组件,并且print.htest在全局环境中的设置下还具有特殊的打印方法。该打印方法从列表中提取信息,但以您在问题输出中看到的用户友好方式打印它。该列表应包含下面列出的组件,包括用names属性命名几个对象。(您是链接文档中显示的其他一些可选组件。)


测试文字说明

  • method:给出假设检验名称的字符串。这将作为打印输出的第一句话出现。

  • data.name:给出数据描述的字符串,通常包括对测试中使用的数据向量名称的引用。对于这一部分,使用substitutedeparse函数将用户输入到函数的名称提取为适当的名称很有用(示例如下所示)。


假设的规范

  • null.value:一个数值变量,给出零假设下的参数值(带有names属性)。

  • alternative: 设置为或的字符串greater用于指定备择假设相对于空值的方向。lesstwo-sided


检验统计量和 p 值

  • estimate:参数的估计值(带有names属性)。该值将是测试函数的数据输入的函数。

  • statistic:测试统计量的值(带有names属性)。这个值要么是测试函数的数据输入的直接函数,要么是参数估计的函数。

  • p.value:测试的 p 值(应该是零到一之间的数字)。该值将是检验统计量的函数。


置信区间(可选)

  • conf.int: 一个置信区间,由一个包含两个元素的向量表示,其中第一个是下限,第二个是上限(带有一个conf.level给出置信水平的属性)。如果您正在使用此组件,最好要求函数将显着性水平作为输入,以指定所需的置信水平。

为了创建自定义假设检验函数,您需要创建一个函数,该函数生成一个列表,其中包含上面显示的所需组件,为您的特定测试定制。对于测试的实质性部分(即估计值、测试统计量、p 值和置信区间),您需要为特定测试使用适当的公式。请注意,您可以将这些元素按任何顺序放在列表中,只要所有必需的元素都在那里。

如果您愿意,还可以将其他组件添加到列表中。最好添加函数的初始部分来检查函数的输入,以确保它们的格式正确,并在输入以某种方式存在缺陷时停止函数并给出错误消息。创建列表后,将对象的类设置为h.test并在函数末尾输出对象。


这是特定测试的实现示例

在一个相关问题中,我给出了一个来自Tarone (1979)的假设检验代码示例。下面是该代码的略微修改版本,作为示例,说明如何为自定义假设检验编写函数。

请注意,代码首先检查输入,然后使用该特定测试的适当名称和公式来构建测试的每个必需组件。计算完这些组件后,我们创建一个名为 的列表对象TEST,由这些元素组成,并将其类设置为h.test我们在函数的末尾输出这个对象。(还值得观察 的代码data.name,它提取用户输入的变量名。)

Tarone.test <- function(N, M) {
    
    #Check validity of inputs
    if(!(all(N == as.integer(N)))) { stop("Error: Number of trials should be integers"); }
    if(min(N) < 1) { stop("Error: Number of trials should be positive"); }
    if(!(all(M == as.integer(M)))) { stop("Error: Count values should be integers"); }
    if(min(M) < 0) { stop("Error: Count values cannot be negative"); }
    if(any(M > N)) { stop("Error: Observed count value exceeds number of trials"); }
    
    #Set description of test and data
    method      <- "Tarone's Z test";
    data.name   <- paste0(deparse(substitute(M)), " successes from ", 
                          deparse(substitute(N)), " trials");
    
    #Set null and alternative hypotheses
    null.value  <- 0;
    attr(null.value, "names") <- "dispersion parameter";
    alternative <- "greater";
    
    #Calculate test statistics
    estimate    <- sum(M)/sum(N);
    attr(estimate, "names") <- "proportion parameter";
    S           <- ifelse(estimate == 1, sum(N),
                          sum((M - N*estimate)^2/(estimate*(1 - estimate))));
    statistic   <- (S - sum(N))/sqrt(2*sum(N*(N-1))); 
    attr(statistic, "names") <- "z";
    
    #Calculate p-value
    p.value     <- 2*pnorm(-abs(statistic), 0, 1);
    attr(p.value, "names") <- NULL;
    
    #Create htest object
    TEST        <- list(method = method, data.name = data.name,
                        null.value = null.value, alternative = alternative,
                        estimate = estimate, statistic = statistic, p.value = p.value);
    class(TEST) <- "htest";
    TEST; }

下面我们创建一些计数数据来实现这个测试,看看输出是什么样子的。如您所见,输出与您在其他假设检验中获得的用户友好输出相同R,其中检验的组件已从列表中拉出并以非常简单的方式呈现。输出显示测试的名称并描述数据,然后给出测试的统计量和 p 值。它还描述了备择假设并给出了参数的样本估计。

#Generate example data
TRIALS <- c(30, 32, 40, 28, 29, 35, 30, 34, 31, 39);
COUNTS <- c( 9, 10, 22, 15,  8, 19, 16, 19, 15, 10);

#Apply Tarone's test to the example data
TEST <- Tarone.test(TRIALS, COUNTS);
TEST;

        Tarone's Z test

data:  COUNTS successes from TRIALS trials
z = 2.5988, p-value = 0.009355
alternative hypothesis: true dispersion parameter is greater than 0
sample estimates:
proportion parameter 
           0.4359756 

stats 包中的假设检验函数使用经典的 S3 面向对象编程。您编写了一个函数来创建一个对象,该对象是一个具有一组标准组件的列表,并且 R 具有该类对象的"htest"内置方法。print用户级函数传统上被称为类似yourname.test但可以有任何名称。它可以有任何适当的参数。

  • 键入 ?t.test 以查看"htest"对象的定义。
  • 请参阅stats:::t.test.default查看创建"htest"对象的函数示例。
  • 看看stats:::print.htest如何创建用户友好的输出。

这是一个执行非常简单的卡方检验的玩具示例:

demo.test <- function(s2, df=1)
{
  pval <- pchisq(s2, df, lower.tail=FALSE)
  out <- list(
    statistic=s2,
    parameter=NULL,
    p.value=pval,
    null.value=NULL,
    alternative="greater",
    method="demo",
    data.name="s2")
  class(out) <- "htest"
  out
}

然后

> TEST <- demo.test(30, df=10)
> TEST

        demo

data:  s2
= 30, p-value = 0.0008566
alternative hypothesis: greater

如果您想变得更高级,您可以使您的函数 S3 通用(如 stats 包函数)以处理不同类型的输入(例如,公式而不是数据向量)。但是像上面示例这样的普通函数可能会满足您的需求。