【问题标题】:Create a single output matrix using apply function使用 apply 函数创建单个输出矩阵
【发布时间】:2014-06-12 00:18:18
【问题描述】:

亲爱的编程之神,

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

我的物种数据 sn-p(实际尺寸 = 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

【问题讨论】:

    标签: r dataframe plyr apply chi-squared


    【解决方案1】:

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

    如果要按列应用函数,请使用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
    

    【讨论】:

    • 太棒了!非常感谢大家:D
    • Mnel,您能否提供代码,说明如何将每个卡方检验的 Holm 校正 p 值添加到此输出中?
    • @user3729247 - 这是一个单独的(统计)问题。你应该在stats.stackexchange 上问一个格式正确的问题(如果你在那里找不到类似的问题)
    【解决方案2】:

    如果您将apply 的结果另存为

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

    然后你就可以完成转换了

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

    这里我们只是将物种的名称附加到每个 data.frame 中,并将所有行与rbind 结合起来。

    【讨论】:

    • 似乎是一个好方法。我不喜欢使用两个数据集并希望它们的顺序相同。像intm &lt;- merge(Species,Env,by.x="row.names",by.y="Rock") 这样先合并可能是明智的。
    • 不要鼓励人们在 data.frames 上使用apply!这将在内部强制转换为矩阵,因此效率不高。促进更好的编码实践!
    【解决方案3】:

    你也可以试试

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

    })

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-30
      • 2021-11-30
      • 1970-01-01
      • 2020-02-14
      • 1970-01-01
      • 2017-03-19
      • 2022-01-10
      • 1970-01-01
      相关资源
      最近更新 更多