简体   繁体   English

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

[英]Create a single output matrix using apply function

Dear programming gods, 亲爱的编程神,

I would like to perform a series of Chi-square tests in R (one test for each column of my species Presence/Absence data.frame) using a function that can yield a single matrix (or data.frame, ideally) which lists as output the species (column name), Chi-square test statistic, df, and p.value. 我想在R中执行一系列卡方检验(对我物种的存在/缺失data.frame的每一列进行一次检验),使用可以产生单个矩阵(理想情况下为data.frame)的函数,该函数列出为输出种类(列名),卡方检验统计量,df和p.value。

My species data snippet (actual dimensions = 50x131): 我的物种数据摘要(实际尺寸= 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")

The following apply function code performs a chi-sq test on each species (column) by first creating a contingency table with the number of occurrences of a given species on climbed vs. unclimbed rocks (Env$Climbed). 以下应用功能代码通过首先创建一个应变表,对每个物种(列)执行chi-sq测试,该列具有给定物种在攀岩和非攀岩(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)
  )
  }) 

This yields a separate data.frame for each species (column). 这将为每个物种(列)产生一个单独的data.frame。 I would like to yield one data.frame, which includes also the column name of each species. 我想产生一个data.frame,其中还包括每个种类的列名称。 Something like this: 像这样:

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

Should this be done with ddply or adply? 应该用ddply还是adply完成? Or just a loop? 还是只是循环? (I tried, but failed). (我尝试过,但是失败了)。 I reviewed a posting on a similar topic ([ Chi Square Analysis using for loop in R ), but could not make it work for my purposes. 我查看了有关类似主题的文章([ 在R中使用for循环的卡方分析 ),但无法使其达到我的目的。

Thank you for your time and expertise! 感谢您的时间和专业知识! TC TC

If you save the result of your apply as 如果您将apply结果另存为

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

Then you can finish the transformation with 然后,您可以完成转换

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

Here we just append the name of the species to each data.frame and combine all the rows with rbind . 在这里,我们仅将种类的名称附加到每个data.frame并将所有行与rbind合并。

You can also try 您也可以尝试

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

}) })

Don't use apply on data.frames . 不要在data.frames上使用apply It internally coerces to a matrix, which can have unintended consequences for some data structures (ie factors). 它在内部强制转换为矩阵,这会对某些数据结构(即因素)产生意想不到的后果。 It is also not efficient (memorywise). 它也是无效的(从内存角度来看)。

If you want to apply a function by column, use lapply (as a data.frame is a list) 如果lapply列应用函数,请使用lapply (因为data.frame是列表)

You can use plyr::ldply do automagically return a data.frame not a list. 您可以使用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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM