蛋白质组学组学数据分析

2019-11-12 蛋白质组学数据中缺失值处理

2019-11-12  本文已影响0人  iColors

转发自http://crickcollege.com/news/170.html

有趣的小故事

美国作家Shel Silverstein有一篇经典的图画寓言---《缺失的一角》。

image

故事的主人公缺了一角,于是它开始拼命地寻找自己缺失的那一角。在执着的寻找中,它尝尽世间百味,感悟颇多。当然,小编举这个例子并没有打算跟你从诗词歌赋聊到人生哲理,小编想说的是,作为科研的搬砖工,在分析数据时,往往你的数据缺的不是一个角,而是一堆角,这个时候,要不要做故事中那位“小圆”呢?

数据缺失的情况
当你辛辛苦苦取完样,累死累活地做完实验,然后满心期待地上质谱采集数据,等待着那一抹“曙光”照耀你的心扉,一切看似快圆满了。。。可是,当你搜完数据,打开结果文件的时候,面对的却经常是下面这样的结果:

image

亦或是这样的:

image

是不是小宇宙都快要崩溃了?!这时候你若是跑去问你的师兄师姐,这种情况该咋办?答:“删掉或者填充吧!”没错,老司机就是老司机,一句道破“天机”!给你的师兄师姐赞一个先。
其实你的数据遇到这个情况绝不是你运气不好,这几乎是一个不可避免的情况。早有前辈就此做了总结(doi: 10.1093/bib/bbn004; doi: 10.1002/pmic.200800576, doi: 10.1021/acs.jproteome.5b00981),一般情况下,特别是在“label free”定量的策略下,你的数据(不管是肽段还是蛋白质的定量信息)里面会有10%到50% 的缺失值,至少有一个重复里面有缺失值的比例有可能会高达70%以上。这意思就是说,当你做的重复越多,每一个重复都有定量信息的概率就会越小。就算你用了标记定量,情况虽有改善,但依然摆脱不了这种情况!

image

数据缺失的原因

上面已经提到,蛋白质组学数据(其它组学数据情况估计也差不多)中有缺失值的情况几乎是不可避免的,那么造成这一现状的原因具体是啥呢?我们也按照缺失值产生的机制来简单的分析下:

1. 完全随机缺失(MCAR,Missing Completely At Random),指的是数据的缺失不依赖于自身或者其他变量,完全是随机的。比如你在街头请路人填问卷采集数据,路人很可能由于某种原因(肚子疼,或者他妈喊他回家吃饭等等)中途撤走,那么你的数据就不完整了。再比如你的质谱在采集数据过程中,不小心受到某种程度的扰动(鬼知道仪器经历了什么…),导致你的数据受到影响,最后在搜库匹配时,无法给出对应的定量信息。这种情况指不清道不明,完全随机,所以它对你整个数据的影响没有任何的偏好性,呈现均一分布。

2. 随机缺失(MAR,Missing At Random),指的是数据的缺失不是完全随机的,该类数据的缺失依赖于其他观测变量。比如时间梯度越长的采集越可能有缺失值的出现。这个时候,若是我们将时间变量进行控制,那么数据的缺失也就变成了完全随机的了。所以也有人认为MCAR和MAR二者没啥区别,或者认为MCAR是MAR的一个特例(doi:10.1186/1471-2105-13-S16-S5)。

3. 非随机缺失(MNAR,Missing Not At Random),指的是数据的缺失依赖于观测变量自身。比如在质谱检测的过程中,某些肽段的含量在仪器的检测限以下,这些肽段的定量信息就很有可能丢失,但是你又不能说这些肽段真的不存在,所以这种情况是比较纠结的,这就是所谓的左删失数据(left-censored data)。

image

强调点:
聊到这,肯定会有小伙伴有疑问了,我怎么才能知道数据缺失值产生的原因呢?小编很遗憾地告诉你,其实是没有什么标准的判断方法的!一般我们默认缺失值属于MCAR或MAR机制类的,MNAR机制类的缺失值需要你找到足够的理由支持才行。

也许有些小伙伴又有疑问了,那为啥看到不少文献(比如doi: 10.1021/acs.jproteome.5b00981, doi:10.1186/1471-2105-13-S16-S5)和书籍(比如《Statistical Analysis with Mssing Data》、《R语言实战》)里,对每一类机制分析得头头是道,貌似他们就能很准确地判断数据缺失值的原因呢?对于这个问题,你若细细地翻看这些资料,你会发现这些作者会有一个共性---“站在上帝的视角看问题”!什么意思呢?就是这些作者全都是“老司机”,他们给出的数据要不就是选择那些缺失值产生的机制比较明确的,或者很容易受大家认可的,比如动物睡眠数据(R语言中sleep数据);要不就是他们自己根据某种规则产出的,比如下图,作者按照缺失值产生的规则模拟出相应的缺失值(规则比较简单:他们随机产生个阈值,数据里面小于这个阈值的被认为是MNAR机制类的缺失值;MCAR机制类的缺失值就是随机点到哪个数据,那么这个数据就被标记成缺失值)。

image

所以,一般说来,在某一个领域经验多些(比如一位做实验的或者管理和维护仪器设备的老手,他对这些器材状态的把控度肯定比一般人要高很多),对自己的数据产生的背景及过程了解的也就多些(这些时候你就可以按照上面的定义对应着找出你的数据缺失值属于哪一种),你对自己数据中的缺失值认识就会更有把握,也能比较快的去选择恰当的方法解决这个问题。所以遇到这类问题去跟你的师兄师姐或者导师讨论一下,也许你会对你的数据有进一步的认识。

解决办法及代码实现

由于在后续分析中(比如相关性分析,PCA分析,Mfuzz分析等),需要的都是完整的数据框或者矩阵,所以你的数据里面若是含有缺失值将会影响后续的分析。而且,当你的数据中缺失的比例比较大时(比如大于30%),这时候还是劝你考虑一下,不要一上来就把这些数据删掉。我们处理缺失值最重要的目的就是希望“返璞归真”---去掉缺失值这层外饰,还其最接近真实值的本质!
通过好多前辈的不懈努力,现有的各类处理缺失值的方法加起来不下15种,当然在本文当中,小编不会对每一种方法都一一介绍,这里只分享给大伙儿几个较常用的方法。
【PS:如果你完全不关心缺失值问题,或者坚定地相信删除缺失值也不会影响分析结果,那你大可以简单粗暴地删掉了事。】
Tips:如何识别缺失值:在R语言中,缺失值被标记为NA,判断一个值是不是缺失值用is.na函数,如下表:

image

其中NaN是说这个值不是一个数,代表的是不可能的值,判断用is.nan函数;infinite表示无穷值,Inf表示正无穷,-Inf表示负无穷,判断使用is.infinite函数。要注意区分,不要混淆了。

1. K近邻法(KNN):该方法主要是通过预先设定的K个邻居(其它肽段或者蛋白质的表达量),根据这些邻居的信息推算出缺失值的大小。一般的数据处理流程是先计算目标对象(含有缺失值的肽段或者蛋白质)与其他对象之间的距离(一般默认计算的是欧氏距离),计算完成后,选择K个(K值是我们预先设定的)距离最近的对象,然后将对应位置的数值进行平均或者加权,其得到的数值用来表征该缺失值的大小。R代码实现:

image

这里面我们用impute包的imput.knn函数,其中data就是要导入的数据,一般是矩阵的形式;k就是我们预先设定的近邻数,默认为10,根据经验一般取值是10到20之间;rowmax和colmax是控制的导入数据中行或者列含有缺失值的比例,比如rowmax=0.5是指当某行的数据缺失值占的比例超过了50%,那么这些缺失值就会用整个样本的均值去填充,而不是我们上面提到的根据K个邻居来填充了;colmax=0.8是指任何一列的数据中当缺失值的比例超过了80%,那么计算就会停止并会报出错误。

2. 有序K近邻法(Sequential KNN):该方法是对上述KNN法的改进,它在缺失值占比稍微大些的数据中表现依然良好。实现流程是先根据数据中每个对象缺失值的比例进行排序(这里也就体现出“Sequential”的思想),从比例最小的那个对象开始计算,根据预先设定的K个近邻(注意这里是指没有缺失值的,KNN法里面并没有强调这一点)的值进行加权或者平均计算填充。此外当该对象填充完毕后,也会加入后续其他对象缺失值填充的计算当中。R代码实现:

image

这里我们用SeqKnn包的SeqKNN函数,其中data就是我们要导入的数据,一般是矩阵的形式;k就是我们预先设定的近邻数,根据经验一般取值是10到20之间。

3. 多重插补法(MI):该方法主要包括3块内容:a,将包含缺失值的原始数据集生成几个完整的数据集(一般生成3-10个),注意这一步就已经完成了缺失值的填充,并且一般我们会把所有填充值的平均值作为最终的填充结果;b,使用标准的方法流程去分析这几个完整的数据集,比如可使用线性回归模型,广义线性模型等,注意这一步并不是对填充结果好坏的评判,而是对填充以后的数据集进行统计方法的分析; c,整合模型分析的结果,输出最终的结果。这个流程可以用下图来比较形象的说明:

image

当然,在这个图中已经标上每一步常用的函数了,在这里我们使用的就是R语言中的mice包。代码实现如下:

image image

其中是以sleep数据(VIM包中动物睡眠数据)为例展开的,mice()就是进行插补的函数,它里面m参数是指生成完整数据集的个数,defaultMethod参数是指选择填充缺失值的方法,seed参数是为了保证结果的重复性;with()就是我们进行标准方法流程对填充好的完整数据集进行分析,这里面我们选择的是线性模型来分析做梦(Dream)变量与另外两个变量(Span,寿命;Gest,妊娠期)之间的线性关系;pool()函数整合最终的结果。

再提一句,如果我们关注的只是缺失值的填充,上面的代码只需要运行到mice()函数,计算出结果就可以了,后面的两步分析做梦与其它两个变量的线性关系这些,就不必运行了。
介绍完这3中常用的方法后,可能你还有疑问:我该使用哪种方法呢?小编不敢断言哪一种方法就一定优越,还是要具体问题具体分析,不过这已经有前辈对这几种方法进行了比较,在这里展示出来供你参考,如下图:

image

其中横轴表示数据中缺失值的占比,纵轴表示均方根误差,用来表征填充值的准确性,值越小表示效果越好。在他们的评估结果中, MI方法的整体表现会稍好一些。

小结

数据出现缺失,虽然这种情况十分讨厌,但你几乎是百分之百会遇到的,躲也躲不掉!处理这种情况时要牢记我们最初的愿望--“返璞归真”。虽然数据缺失得不少,但是它们不是缺的一点逻辑都没有。处理缺失值的方法很多,本文我们只提到了3种比较常用的方法,对于其他的方法,以后有机会咱们再继续聊。也欢迎大家关注小编开发的网站---“悟空”(http://www.omicsolution.org/wu-kong/main/,建议用电脑打开查看学习),该网站收录上述的方法,后期也会逐渐加入其他的方法,方便大家使用学习。

上一篇下一篇

猜你喜欢

热点阅读