使用apply函数创建单个输出矩阵

时间:2014-06-12 00:18:18

标签: r dataframe plyr apply chi-squared

亲爱的编程神,

我想在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完成?或者只是一个循环? (我试过,但失败了)。我查看了关于类似主题的帖子([Chi Square Analysis using for loop in R),但无法使其适用于我的目的。

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

3 个答案:

答案 0 :(得分: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合并。

答案 1 :(得分: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

UPD:

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))

})

答案 2 :(得分:1)

不要在apply上使用data.frames。它内部强制转换为矩阵,这可能会对某些数据结构(即因素)产生意想不到的后果。它也没有效率(记忆性)。

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

您可以使用plyr::ldply自动返回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