2

亲爱的编程之神,

我想使用可以产生单个矩阵(或 data.frame,理想情况下)的函数在 R 中执行一系列卡方检验(对我的物种存在/不存在 data.frame 的每一列进行一个测试),该矩阵列出为输出种类(列名)、卡方检验统计量、df 和 p.value。

我的物种数据片段(实际尺寸 = 50x131):

   Species<-structure(list(Acesac = c(0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 1L, 1L
), Allpet = c(0L, 0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L), Ambser = c(0L, 
0L, 0L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L), Anoatt = c(0L, 0L, 0L, 1L, 0L, 
1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 
0L, 1L, 1L, 1L), Aritri = c(0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 0L, 
0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L
)), .Names = c("Acesac", "Allpet", "Ambser", "Anoatt", "Aritri"
), row.names = c("BS1", "BS10", "BS2", "BS3", "BS4", "BS5", "BS6", 
"BS7", "BS8", "BS9", "LC1", "LC10", "LC2", "LC3", "LC4", "LC5", 
"LC6", "LC7", "LC8", "LC9", "TR1", "TR10", "TR2", "TR3", "TR4"
), class = "data.frame")

My environmental data snippet:
Env<-structure(list(Rock = structure(1:25, .Label = c("BS1", "BS10", 
"BS2", "BS3", "BS4", "BS5", "BS6", "BS7", "BS8", "BS9", "LC1", 
"LC10", "LC2", "LC3", "LC4", "LC5", "LC6", "LC7", "LC8", "LC9", 
"TR1", "TR10", "TR2", "TR3", "TR4", "TR5", "TR6", "TR7", "TR8", 
"TR9", "WD1", "WD10", "WD2", "WD3", "WD4", "WD5", "WD6", "WD7", 
"WD8", "WD9", "WW1", "WW10", "WW2", "WW3", "WW4", "WW5", "WW6", 
"WW7", "WW8", "WW9"), class = "factor"), Climbed = structure(c(1L, 
2L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 1L, 2L, 2L, 1L, 2L, 1L, 2L, 
1L, 2L, 1L, 1L, 2L, 2L, 1L, 2L), .Label = c("climbed", "unclimbed"
), class = "factor")), .Names = c("Rock", "Climbed"), row.names = c(NA, 
25L), class = "data.frame")

以下应用函数代码通过首先创建一个列联表,其中包含给定物种在攀爬岩石与未攀爬岩石 (Env$Climbed) 上的出现次数,对每个物种(列)执行卡方检验。

apply(Species, 2, function(x) {
  Table<-table(Env$Climbed, x)
  Test<-chisq.test(Table, corr = TRUE)
  out <- data.frame("Chi.Square" = round(Test$statistic,3)
                  , "df" = Test$parameter
                  , "p.value" = round(Test$p.value, 3)
  )
  }) 

这会为每个物种(列)生成一个单独的 data.frame。我想生成一个 data.frame,其中还包括每个物种的列名。像这样的东西:

mydf<-data.frame("spp"= colnames(Species[1:25,]), "Chi.sq"=c(1:25), "df"=
  c(1:25),"p.value"= c(1:25))

这应该用 ddply 还是 adply 来完成?还是只是一个循环?(我尝试过,但失败了)。我查看了一篇关于类似主题的帖子([在 R 中使用 for 循环进行卡方分析),但无法使其适用于我的目的。

感谢您的时间和专业知识!TC

4

3 回答 3

1

如果您将结果保存apply

kk <- apply(Species, 2, function(x) {...})

然后你可以完成转换

do.call(rbind, Map(function(x,y) cbind(x, species=y), kk, names(kk)))

在这里,我们只是将物种的名称附加到每个 data.frame 并将所有行与rbind.

于 2014-06-12T00:32:30.890 回答
1

你也可以试试

kk <- apply(Species,2,....) 
library(plyr)
ldply(kk,.id='spp') 
 spp Chi.Square df p.value
1 Acesac      0.000  1   1.000
2 Allpet      0.000  1   1.000
3 Ambser      0.000  1   1.000
4 Anoatt      0.338  1   0.561
5 Aritri      0.085  1   0.770

更新:

library(plyr)
library(reshape2)
ddply(setNames(melt(Species), c("spp", "value")), .(spp), function(x) {
Test <- chisq.test(table(Env$Climbed, x$value), corr = TRUE)
data.frame(Chi.Square = round(Test$statistic, 3), df = Test$parameter, p.value = round(Test$p.value, 
    3))

})

于 2014-06-12T02:09:19.540 回答
1

不要applydata.frames. 它在内部强制转换为矩阵,这可能会对某些数据结构(即因子)产生意想不到的后果。它也不是有效的(内存方面)。

如果要按列应用函数,请使用lapply(因为 data.frame 是列表)

您可以使用plyr::ldplydo 自动返回一个data.frame非列表。

# rewrite the function so `Env$Climbed` is not hard coded....
my_fun <- function(x,y) {
  Table<-table(y, x)
  Test<-chisq.test(Table, corr = TRUE)
  out <- data.frame("Chi.Square" = round(Test$statistic,3)
                    , "df" = Test$parameter
                    , "p.value" = round(Test$p.value, 3)
  )

}
library(plyr)
results <- ldply(Species,my_fun, y = Env$Climbed)
results
# .id Chi.Square df p.value
# 1 Acesac      0.000  1   1.000
# 2 Allpet      0.000  1   1.000
# 3 Ambser      0.000  1   1.000
# 4 Anoatt      0.338  1   0.561
# 5 Aritri      0.085  1   0.770
于 2014-06-12T03:44:25.553 回答