在数据框中的多列上使用 shapiro.test
Posted
技术标签:
【中文标题】在数据框中的多列上使用 shapiro.test【英文标题】:Using shapiro.test on multiple columns in a data frame 【发布时间】:2014-02-09 23:12:00 【问题描述】:我有一个数据框(我们称之为 df
),包含 n=100 列(C1
、C2
、...、C100
)和 50 行(R1
、R2
、 ...,R50
)。我测试了数据框中的所有列以确保它们是数字的。我想知道使用shapiro.test()
函数的每一列中的数据是否具有正态分布。
我可以使用代码按列进行操作:
> shapiro.test(df$Cn)
或
> shapiro.test(df[,c(Cn)])
但是,当我尝试同时在多个列上执行此操作时,它不起作用:
> shapiro.test(df[,c(C1:C100)])
返回错误:
[.data.frame
(x, complete.cases(x)) 中的错误:选择了未定义的列
如果有人能提出一种同时进行所有测试并最终将结果存储在新的数据框/矩阵/列表/向量中的方法,我将不胜感激。
【问题讨论】:
【参考方案1】:并不是说我认为这是一种明智的数据分析方法,而是将函数应用于数据框的列的基本问题是可以使用sapply()
或lapply()
之一轻松完成的一般任务(甚至apply()
,但对于数据帧,前面提到的两个函数之一是最好的)。
这是一个示例,使用了一些虚拟数据:
set.seed(42)
df <- data.frame(Gaussian = rnorm(50), Poisson = rpois(50, 2),
Uniform = runif(50))
现在应用shapiro.test()
函数。我们将输出捕获在一个列表中(给定此函数返回的对象),因此我们将使用lapply()
。
lshap <- lapply(df, shapiro.test)
lshap[[1]] ## look at the first column results
R> lshap[[1]]
Shapiro-Wilk normality test
data: X[[1L]]
W = 0.9802, p-value = 0.5611
你需要从这些对象中提取你想要的东西,它们都具有以下结构:
R> str(lshap[[1]])
List of 4
$ statistic: Named num 0.98
..- attr(*, "names")= chr "W"
$ p.value : num 0.561
$ method : chr "Shapiro-Wilk normality test"
$ data.name: chr "X[[1L]]"
- attr(*, "class")= chr "htest"
如果你想要这个对象的statistic
和p.value
组件用于lshap
的所有元素,我们这次将使用sapply()
,以便为我们很好地安排结果:
lres <- sapply(lshap, `[`, c("statistic","p.value"))
R> lres
Gaussian Poisson Uniform
statistic 0.9802 0.9371 0.918
p.value 0.5611 0.01034 0.001998
鉴于您有 500 个,我将转置 lres
:
R> t(lres)
statistic p.value
Gaussian 0.9802 0.5611
Poisson 0.9371 0.01034
Uniform 0.918 0.001998
如果您打算使用本练习中的 p 值做任何事情,我建议您在用 30 卡的热量击中自己的脚之前,开始考虑如何纠正多重比较。
【讨论】:
最后的音符很棒。 谢谢,它工作得很好。至于如何处理它,嗯......我需要在这个矩阵的不同列之间进行多重相关。我会做非参数相关,但我的老板对非参数过敏并坚持使用参数。我看看能不能把数据转换成正态分布…… 无论你做什么,你都需要纠正所有这些测试。如果您进行了 100 次测试并使用通常的 0.05 (alpha=0.95) 显着性水平,那么您接受当 HO 正确时,您将在 100 次中平均拒绝 NULL (H0) 5 次(即您会发现一个显着结果不存在的地方)。在进行多项测试时需要考虑到这一点,因此请查看 Bonferroni 和 Holm 调整、FDR(错误发现率)等。这可以通过p.adjust()
完成。
是的,很好的建议。然而,我们主要将相关性用于探索性目的:找出哪些变量呈现出最大的相关性,然后将分析重新集中在这个特定变量上。尽管如此,我还是执行了 FDR 来调整 p 值,并比较了两组结果。
使用 apply 系列的简单而精彩的示例。【参考方案2】:
要对数据框的行或列应用某些函数,可以使用apply
family:
df <- data.frame(a=rnorm(100), b=rnorm(100))
df.shapiro <- apply(df, 2, shapiro.test)
df.shapiro
$a
Shapiro-Wilk normality test
data: newX[, i]
W = 0.9895, p-value = 0.6276
$b
Shapiro-Wilk normality test
data: newX[, i]
W = 0.9854, p-value = 0.3371
请注意,列名被保留,df.shapiro
是一个命名列表。
现在,如果你想要一个 p 值向量,你所要做的就是从适当的列表中提取它们:
unlist(lapply(df.shapiro, function(x) x$p.value))
a b
0.6275521 0.3370931
【讨论】:
【参考方案3】:将do.call
与rbind
和lapply
一起使用以获得更简单和紧凑的解决方案:
df <- data.frame(a = rnorm(100), b = rnorm(100), c = rnorm(100))
do.call(rbind, lapply(df, function(x) shapiro.test(x)[c("statistic", "p.value")]))
#> statistic p.value
#> a 0.986224 0.3875904
#> b 0.9894938 0.6238027
#> c 0.9652532 0.009694794
【讨论】:
以上是关于在数据框中的多列上使用 shapiro.test的主要内容,如果未能解决你的问题,请参考以下文章