优秀的编程知识分享平台

网站首页 > 技术文章 正文

「统计」从p-value到q-value的计算(附代码)

nanyue 2024-07-23 13:52:09 技术文章 24 ℃

看到群里有老师在问“如何从p-value计算获得q-value”。今天简单进行下讨论,并附送一份可在命令行下独立运行的代码。

首先,关于“P值”我们之前也进行过讨论(计算个“P值”,咱也不太懂,咱也不敢信)。大家或许还对下面的这张PPT还有印象:对于来自相同分布的两组样本,如果很多次采集数据并进行假设检验,“本不应显著的”两组样本也会出现P值很小的“显著结果”(“P-hacking”

上图中,我们对来自相同正态分布n(5,5)的x和y进行仿真,每次模拟三个重复,并进行t检验;假设我们有这么一个“劳模”进行了1000次(x轴)独立实验,并各自计算出p值(y轴);其中,红线为p=0.05的阈值线。从图上看出,1000次实验中,有很多次已经出现p<0.05的情况了。实际上,这种情况下“P-value”服从[0,1]区间的“均匀分布”;在随机情况下,1000次实验出现也能出现大约50次“P<0.05的情况”。

所以,在进行了很多次假设检验的时候,为了控制FDR(错误发现率),就要使用统计学方法进行“多检验矫正”(multiple-testing correction),并计算得到q-value。

关于p-value、q-value和FDR的关系,大家可以参考本文链接的网页上的解释(英文的哦~~)。本文不重复讨论。

但简单地,我们对q-value和p-value的特点进行以下总结:

  1. P-value和Q-value都是分布在[0,1]范围内的实数。

  2. 从P-value列表计算得到Q-value列表的统计模型有很多(参考R语言中p.adjust函数)。

  3. P-value 列表计算得到Q-value后,各个元素的大小排序不发生改变(不考虑相等的情况)。

  4. 相对于P-value列表中的对应元素的p值,其q值只会变大(或不变),不会变小(但不会超过1)。

  5. P值经放大到对应的Q值的过程中,和列表中的元素的个数也有关系:即,不同的总体元素个数下,同一个P值经放大往往会得到不同的Q值。

  6. 如果同时进行的假设检验次数很多时,只使用“P值”进行讨论的稿件,会被审稿人质疑作者的统计学基础。

以下是小编附送的一份R语言的代码,另存为可执行的文件后,可通过一行shell命令将P值转换为Q值。供各位同行参考。

在linux命令行下,将下的代码另存为 Pv2Qv.R文件,并添加可执行权限。

#!/usr/bin/env Rscript# by 麦陇 @ 小麦研究联盟

suppressPackageStartupMessages(library("optparse"))option_list <- list( make_option(c("-i", "--infile"), dest = "infile", default = "", help="[opt] input file, use STDIN if omitted"), make_option(c("-p", "--pv"), dest = "pv_col", default = 1, help="The column number for p value [default: %default]"), make_option(c("-o", "--outfile"), dest = "outfile", default = "", help = "[opt] output file, use STDOUT if omitted"))#parser <- OptionParser(usage = "%prog [options] file", option_list=option_list, description = "Description: \ Calculate the q-values from a list of p-values.\ New columns will be added to in right most column of output.xls.\Example: \ Pv2Qv.R -i input.xls -o output.xls \ ")#arguments <- parse_args(parser)opt <- arguments$options# infileinfile <- arguments$infileif(infile == "") { infile = file("stdin")}# outfileoutfile = arguments$outfileif( outfile == "") { outfile = stdout}# Read the input fileT = read.table( infile, header=FALSE, sep = "\t", check.names = FALSE)PV = T[,arguments$pv_col]QV = format(p.adjust(PV, method = "fdr"), digits = 4, scientific = TRUE)write.table( cbind(T, QV), file = outfile, quote = FALSE, sep = "\t", row.names = FALSE, col.names = FALSE)

之后,就可以参考如下命令行从P值直接生成Q值。

说明:输入文件需要是包含所有元素的、同时计算了P值的列表;可以有多列,在命令行中指定P值所在的列号即可(如第三列:“-p 3”)。

./Pv2Qv.R -i input_file -p 3 -o output_file # 假设输入文件中第三列是P值# 生成文件output_file会在input_file的基础上增加一列对应的q值。

Tags:

最近发表
标签列表