【问题标题】:How to do wilcox.test correctly for multiple columns with NA in R?如何为 R 中具有 NA 的多列正确执行 wilcox.test?
【发布时间】:2020-04-06 20:30:55
【问题描述】:

我正在尝试针对目标列对多列执行wilcox.test,其中每一列都有NA 值,我需要为每一列独立删除它。要做wilcox.test,首先我需要对每一列进行采样,然后在当前列中删除NA,然后过滤掉目标列的值,但是我没有成功检索到当前列中NA的索引,因为我使用了which(is.na(df$x1), arr.ind=TRUE),但它不会帮助我如何在目标列中保留相应的值。因为NA在每一列中的位置不同,所以目标列的对应值也发生了变化。我不知道如何在 R 中进行这种操作。谁能指出我如何做到这一点?有什么想法吗?

可重现的例子

这是我的任务的最小可重复数据:

> dput(mydf)
structure(list(v1 = c(3.69055560203349, 3.01675043088942, 3.4195128033004, 
NA, 3.5798210897553, 4.00279762977148, 3.39364072476593, 3.74902908274812, 
3.75245019598874, NA), v2 = c(8.29251175276882, 6.03085239544148, 
6.61202305724909, 6.32182430455213, 7.01468228541546, 7.91002666664165, 
8.43386943449607, 8.5247956890294, 8.052886597559, 7.22851794548592
), v3 = c(2.67156354473232, 2.36125329858185, 2.17487388876694, 
NA, 2.17995780295262, 2.0439205043448, 1.71779360521063, 2.02967258021284, 
2.04390173884486, NA), v4 = c(2.9771612602651, 2.8554942149399, 
2.86921526382523, NA, 3.5642547915086, 3.02900788965761, 2.86324542975628, 
2.8451951395453, 2.17256320516553, NA), label = c(0L, 1L, 0L, 
1L, 0L, 1L, 0L, 0L, 1L, 0L)), class = "data.frame", row.names = c(NA, 
10L))

我的尝试:

我想对每一列进行采样然后找出目标列的对应值,然后执行wilcox.test。这是我尝试过的:

label = mydf$label
lapply(1:5, function(i){
    res= lapply(colnames(mydf), function(x){
        col_rmna = na.omit(mydf[x])
        sample_size = floor(0.33*nrow(col_rmna))
        split_index <- sample(seq_len(nrow(col_rmna)), size = sample_size, replace = FALSE)
        feat_samped = col_rmna[split_index, ]
        label = subset(label, feat_samped[!which(is.na(feat_samped), arr.ind=TRUE),])
        wtst = wilcox.test(feat_samped ~label)$p.value
    })
    ## put the output of each itertion into list 
})

但我不知道如何获取对应的标签值,并为每个带有相应标签值的采样列执行wilcox.test。我的最终目标是在生成不同采样列值的多次迭代后计算每列的平均 p 值。

谁能指出我如何做到这一点?如何通过查看另一列中的NA 值来查找和保留目标列的值,其中NA 行中出现的值被简单地丢弃?任何的想法?

目标

在这里,我想运行多次迭代,对每一列进行采样并执行wilcox.test,最终输出将是数据帧,其中应包含每列的平均 p 值。如何完成这项工作?在 R 中执行此类任务的任何更简单的方法?谢谢

【问题讨论】:

  • 您的示例缺少tst,因此无法重现,您的总体目标是什么?平均 p 值没有意义
  • @rawr 抱歉,这是一个错字,现在已修复,并且可以正常工作。有什么进一步的想法吗?谢谢
  • 我会使用replicate 而不是嵌套的lapplys,看起来你让这太复杂了——这是你想要的吗? lapply(1:4, function(i) replicate(5, {mydf[, i] &lt;- sample(mydf[, i]); mydf &lt;- na.omit(mydf); mydf &lt;- mydf[sample(nrow(mydf)), ]; wilcox.test(mydf[, i] ~ factor(mydf$label, 0:1))$p.value}))
  • @rawr 我并不复杂,但我需要非常小心地对待NA 的每一列,其中NA for each column may be different from one to another. I need to do sampling for each column then do wilcox.test 的比例。我尝试了类似的方法,但我的分析不正确。还有什么想法吗?

标签: r dplyr data-manipulation


【解决方案1】:

我不评估这种方法的有效性,只评估它的程序实施。

我们可以使用which()来转换观察值不是NA的逻辑向量,而不是直接对数据进行采样,而是对索引进行采样。这样,索引也将匹配标签的位置。我还处理了只对两个标签中的一个进行采样的情况,因为这只会产生一个因素,wilcox.test 会失败。

sample.fraction <- 0.8
trials <- 10
result <- lapply(mydf[,1:4],function(x){
  pvals <- vector();
  for(i in seq(1,trials)){
    number.non.na.obs <- length(x[!is.na(x)]);
    n.sample <- floor(sample.fraction*number.non.na.obs);
    logical.not.na <- !is.na(x);
    target.indices <- which(logical.not.na);
    sample <- sample(target.indices,n.sample);
    n.labels.sampled <- length(table(mydf$label[sample]));
    if(n.labels.sampled < 2){pvals[i] <- NA}
     else{pvals[i] <- wilcox.test(x[sample]~mydf$label[sample])$p.value}
  }
return(pvals);  
})
result
#$v1
# [1] 0.3333333 1.0000000 0.7000000 0.7000000 0.1333333 1.0000000 1.0000000 1.0000000 1.0000000 0.3333333
#$v2
# [1] 0.1142857 0.4285714 0.3428571 0.4285714 0.1142857 0.1142857 0.1428571 0.2500000 0.1428571 0.3428571
#$v3
# [1] 0.5333333 1.0000000 0.5333333 0.5333333 0.6666667 0.5333333 0.5333333 1.0000000 1.0000000 0.8000000
#$v4
# [1] 1.0000000 0.2666667 0.6666667 0.8000000 0.8000000 1.0000000 0.2666667 0.3333333 0.4000000 1.0000000

如果你想要平均值,你可以使用sapply

sapply(result, mean)
#       v1        v2        v3        v4 
#0.5533333 0.3321429 0.7166667 0.6933333 

数据

mydf <- structure(list(v1 = c(3.69055560203349, 3.01675043088942, 3.4195128033004, 
NA, 3.5798210897553, 4.00279762977148, 3.39364072476593, 3.74902908274812, 
3.75245019598874, NA), v2 = c(8.29251175276882, 6.03085239544148, 
6.61202305724909, 6.32182430455213, 7.01468228541546, 7.91002666664165, 
8.43386943449607, 8.5247956890294, 8.052886597559, 7.22851794548592
), v3 = c(2.67156354473232, 2.36125329858185, 2.17487388876694, 
NA, 2.17995780295262, 2.0439205043448, 1.71779360521063, 2.02967258021284, 
2.04390173884486, NA), v4 = c(2.9771612602651, 2.8554942149399, 
2.86921526382523, NA, 3.5642547915086, 3.02900788965761, 2.86324542975628, 
2.8451951395453, 2.17256320516553, NA), label = c(0L, 1L, 0L, 
1L, 0L, 1L, 0L, 0L, 1L, 0L)), class = "data.frame", row.names = c(NA, 
10L))

【讨论】:

  • 是否有可能使您的代码易于理解?如何在开始使用sapply 的同时对代码进行矢量化?谢谢
  • 谢谢,我需要先验证并理解您的输出。在接受您的回答之前,我会尽快回复您。
  • 我不明白这个的用途:if(length(table(mydf$label[sample])) == 1){NA},你能告诉我它是做什么用的吗?我们可以改用ifelse 吗?
  • 我想理解或简化这一行:n.sample &lt;- floor(sample.fraction*length(x[!is.na(x)])),我们可以用更易读的方式吗?谢谢
  • 作为for循环是不是更容易理解?
猜你喜欢
  • 1970-01-01
  • 2021-11-26
  • 1970-01-01
  • 2021-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-04
相关资源
最近更新 更多