如何简化 R 中的代码(正态性检验):1 行或 2 行代码中的不同样本量?

How to simplify code in R (normality test): different sample sizes in 1 line or 2 lines of code?

我想在我的编码中进行更清晰的正态性测试并进行模拟(重复测试 1000 次)。

sample <- c(10,30,50,100,500)
shapiro.test(rnorm(sample))

    Shapiro-Wilk normality test

data:  rnorm(sample)
W = 0.90644, p-value = 0.4465

正如您在上面看到的那样,这只给出了一个输出。如何获得 5 个输出?我在这里遗漏了什么..?

使用复制函数为每个样本量提供 1000 个统计数据,而我只对 p 值感兴趣并将它们与显着性水平相关联。在各个正态性测试的编码中,我使用了以下代码(感谢用户 StupidWolf,在我之前在 Whosebug 上发布的问题中)

replicate_sw10 = replicate(1000,shapiro.test(rnorm(10)))
table(replicate_sw10["p.value",]<0.10)/1000
#which gave the following output
> FALSE  TRUE 
> 0.896 0.104

使用 purrr

map(sample, function(x) shapiro.test(rnorm(x)))

这给出了

[[1]]

    Shapiro-Wilk normality test

data:  rnorm(x)
W = 0.92567, p-value = 0.4067


[[2]]

    Shapiro-Wilk normality test

data:  rnorm(x)
W = 0.95621, p-value = 0.247


[[3]]

    Shapiro-Wilk normality test

data:  rnorm(x)
W = 0.96144, p-value = 0.1021


[[4]]

    Shapiro-Wilk normality test

data:  rnorm(x)
W = 0.98654, p-value = 0.4077


[[5]]

    Shapiro-Wilk normality test

data:  rnorm(x)
W = 0.99597, p-value = 0.2324

编辑:所以在您编辑之后,您正在请求一些 table。这与您使用 replicate_sw10 示例的方式不同,因为它是一个矩阵,而 map (或 lapply 就此而言)会生成一个列表。因此,您再次想要使用 apply 或 map 对列表的所有部分进行相同的转换。

replicate_swall  <- map(sample, function(x) shapiro.test(rnorm(x)))

replicate_pvalue_extract <- map(replicate_swall  , function(x) x["p.value",]) %>% unlist(., recursive = F)

table(replicate_pvalue_extract  < 0.10) / length(replicate_pvalue_extract )

这会给你:

FALSE  TRUE 
0.896 0.104 

另一种选择是使用 magrittr 包进行提取。您的代码将看起来像

replicate_pvalue_extract <- map(replicate_swall, magrittr::extract, "p.value") %>% unlist(., recursive = F)

table(replicate_pvalue_extract  < 0.10) / length(replicate_pvalue_extract )

在上面的代码中,我假设您想将 table 除以所有重复项,并且输入是什么并不重要(输入是指 10、30、50、100 或 500) .如果您确实关心输入,可以将它们分开,我将在下面给出代码。另请注意,我使用的是长度而不是硬编码的 /1000。通过这种方式,您的代码更加通用,如果您更改重复编号,您除以 table 的编号也会自动更改。否则,您必须在多个位置进行更改(尤其是当其他人使用您的代码时),这很容易导致错误。

replicate_pvalue_extract <- map(replicate_swall  , function(x) x["p.value",]) 

map(replicate_pvalue_extract  , function(x) table(x < 0.10) / length(x))

或者您可以组合它们:

map(map(replicate_swall, function(x) x["p.value",]), function(x) table(x < 0.10) / length(x))

这就是我给你 magrittr 选项的原因,因为我不喜欢 function(x) 两次。使用 magrittr 它看起来像:

map(map(replicate_swall, magrittr::extract, "p.value"), function(x) table(x < 0.10) / length(x))

这将导致:

[[1]]

FALSE  TRUE 
0.896 0.104 

[[2]]

FALSE  TRUE 
0.889 0.111 

[[3]]

FALSE  TRUE 
0.904 0.096 

[[4]]

FALSE  TRUE 
  0.9   0.1 

[[5]]

FALSE  TRUE 
0.891 0.109 

您可以简单地使用$p.value。下面的代码生成一个矩阵,其中 1,000 行用于重复,5 列用于 smpl 大小。如果您想要一个列表作为结果,只需使用 lapply 而不是 sapply.

smpl <- c(10, 30, 50, 100, 500)

set.seed(42)  ## for sake of reproducibility

res <- sapply(smpl, function(x) replicate(1e3, shapiro.test(rnorm(x))$p.value))
head(res)
#            [,1]      [,2]       [,3]      [,4]      [,5]
# [1,] 0.43524553 0.5624891 0.02116901 0.8972087 0.8010757
# [2,] 0.67500688 0.1417968 0.03722656 0.7614192 0.7559309
# [3,] 0.52777713 0.6728819 0.67880178 0.1455375 0.7734797
# [4,] 0.55618980 0.1736095 0.69879316 0.4950400 0.5181642
# [5,] 0.93774782 0.9077292 0.58930787 0.2687687 0.8435223
# [6,] 0.01444456 0.1214157 0.07042380 0.4479121 0.7982574