查看原文
其他

视频小教程_R语言中的批量操作

果子 果子学生信 2023-06-15

(本次操作有配套的视频教程,在果子学生信公众号回复“果子爱批量”自行获取,和代码一起以project的形式分享)
目前而言,我学R语言,受益最大的是批量操作。
比如,我们可以实现批量计算2万个基因的生存分析。这里有个例子:
8秒完成2万个基因的生存分析,人人都可以!
如果更猛一点,用双基因来分开样本,可以实现双基因的生存分析。
但是数量级有点大,理论上是2万乘以2万,大概是4亿。
写成批量的呈现后,就有了4亿个生存分析的结果。

我们还可以用批量思维实现别人paper中的图表。
这个帖子就是个例子
跟Nature一起学习TCGA,GTEx和CCLE数据库的使用

只要能批量操作,速度不是很重要,所以,大家都应该掌握的是for循环
人人都该掌握for循环

当我们梳理掌握for循环之后,学有余力的可以尝试用上apply家族的成员。
其中对我而言,最常用的是lapply。

1.lapply

他接受一个列表和一个函数,然后批量地把列表中的每一个元素都call function。
他会得出和列表一样长度的结果,并把结果储存在列表中。
举个例子:
批量地对1,2,3,4取log2

lapply(as.list(1:4), log2)

这个结果就是个list,长度和输入的1,2,3,4一样,四个元素,每一个元素都求了log2

上面的例子也可以简写成这个, 因为向量就是特殊的列表
可以看看这个帖子中的动画
数据结构就是晾衣杆上的小盒子

lapply(1:4, log2)

lapply的厉害之处在于,他作用的function可以自己写,那么这样一来就千变万化了。
对1,2,3,4批量操作,每个元素平方后加上2

lapply(1:4function(x){
  x^2 +2
})

注意,lapply作用于list,返回的还是等长的list

在我以往的帖子中,伴随lapply出现的还有个do.call。也是个批量操作。

2.do.call

他也是接受一个列表,传给函数当参数。
和lapply不一样的地方有三个:
第一,do.call 整个过程中函数只调用一次,所以返回的是一个结果。
这跟lapply很不一样,lapply作用n次,返回n次结果,这个n就是list的长度。
简单理解,对应1到100这100个数,lapply可以让他们每个数都加上2,得到100个结果
而do.call实现的是,把1到100这些数相加求和,得到1个结果

第二,函数的要求不同。
do.call中的函数,需要能够接受多个参数。
比如,求和sum(),输入多少个数都可以算,不限定数量
cbind(), rbind(),c()都有这个特点。
如果我们打开这些函数的文档,他们的第一个参数写的是三个点...,代表传入的参数不限个数

sum(..., na.rm = FALSE)
c(...)
cbind(..., deparse.level = 1)
rbind(..., deparse.level = 1)

第三,使用的形式不一样。
lapply是list在前,函数在后

lapply(1:4, log2)

do.call是函数在前,列表在后
我们举例说明
首先用lapply生成一个列表

dd <- lapply(1:4, log2)

看到没有,list在前,函数在后
现在用do.call把结果合并起来,使用的函数是c()
函数c在前,列表dd在后

do.call(c,dd)

返回的结果就一个

[10.000000 1.000000 1.584963 2.000000

3.lapply 和do.call 连用

连用的例子有很多,但是大部分情况下,我的目的是有一个,

改变数据结构,尤其是把批量后的list转换为数据框

举个例子,生成一个列表

dd <- lapply(LETTERS[1:6], function(i){
  paste0(i,1:10)
})

现在我想要把这个列表变成一个数据框,我就有两种选择。
第一,把每个元素当成行,那么最后生成的数据框是这样的

do.call(rbind,dd)

第二,把列表的每个元素当成列,那么生成的数据框是这个样子的。

do.call(cbind,dd)

你看两种不一样的函数,刚好让一个数据转置了,基于这个原理,我还重新写过转置t()这个函数。
这是数据格式转换三大件中的一个
R语言中性价比最高的函数以及最贵的函数

而我在是实战中往往是把lapply批量得到的结果转换为适合阅读的数据框。

但是我们知道,do.call 中的函数,需要能够接受多个参数。有些函数是不可以的,比如merge,他就只能接受两个参数。
还有intersect求交集也是

union(x, y)
intersect(x, y)
setdiff(x, y)
setequal(x, y)

那怎么办呢?

4.Reduce

只要我们不是第一个进入这个领域的,那么我们的问题大概率是有答案的。
Reduce函数就是一个解决方案。
我在这个帖子里面给出了使用场景和使用方法
Reduce函数实现多个数据框批量合并

5.推荐阅读

如果想看看lapply的用法和其他三个跟do.call类似的函数,可以看看这个
神奇的lapply
如果想要燃烧自己的小电脑,这里还有并行化的方案,目前我直选这一个,极其简单高效
lapply并行化处理
这里还有一个lapply批量求相关性的例子
又是神器!基于单基因批量相关性分析的GSEA
如果是多个列表对应多个参数,批量操作可以选择mapply,我曾经用这个把11小时的任务缩减到11s
迷人的mapply
最终,批量的分组操作,这里还有一个大合集,apply家族中其他成员也出现啦!
R语言中的批量分组操作

这样限制我们的只剩下自己写函数的能力。这个技能会让我们上天入地,无所不能。
可以先从这些实战的例子中找找灵感,我们会出一个系统的函数教程。后会有期。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存