在数据框中的多列上使用 shapiro.test

Posted

技术标签:

【中文标题】在数据框中的多列上使用 shapiro.test【英文标题】:Using shapiro.test on multiple columns in a data frame 【发布时间】:2014-02-09 23:12:00 【问题描述】:

我有一个数据框(我们称之为 df),包含 n=100 列(C1C2、...、C100)和 50 行(R1R2、 ...,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"

如果你想要这个对象的statisticp.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.callrbindlapply 一起使用以获得更简单和紧凑的解决方案:

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的主要内容,如果未能解决你的问题,请参考以下文章

根据熊猫中多列中的值从数据框中选择行

根据熊猫中多列中的值从数据框中选择行

根据熊猫中多列中的值从数据框中选择行

根据熊猫中多列中的值从数据框中选择行

如何使用 groupby 和聚合将 pyspark 数据框中的行与多列连接起来

使用R中数据框中的多列创建列联表