为什么我偏爱system函数
为什么我偏爱system函数
PeRl
2019/5/22
什么是system函数
在R语言中有一个特殊的函数: system
, 它可以实现R与linux终端bash命令(DOS也可以,但是我使用的很少)之间的互动.
更出名一些的是RCPP
包,它可以实现R与底层C++的互动.
那么,为什么我们会需要这种不同程序语言之间的互动呢?
让专业的人干专业的事!
为什么需要Bash?
Bash有着得天独厚的优势,那就是众多功能各异的command,比如最常用的 ls
, cd
, paste
, cat
等等.
command建立的初衷就是为了节省程序员重复劳动的时间和精力,对同一个任务(比如多文件的拼接)实现最精简的可重复性命令.
linux又天生对文件操作得心应手,相反R对文件系统的操作就显得稚嫩而粗糙;就像Perl天生对字符串敏感,而R进行字符串操作就无比笨拙.
为了更好的理解这点,请看下面的两个例子:实现对文件夹下所有文件按列拼接
Bash:
cd /home/wang/Downloads/test/file_paste
paste a.txt b.txt c.txt d.txt > ../paste_file.txt
R:
setwd("/home/wang/Downloads/test/file_paste")
file_list <- list.files()
for(file in file_list){
data = read.table(file, header = F, stringsAsFactors = F)
if(file == file_list[1]){
result = data
} else {
result = cbind(result, data)
}
}
高下立见, R对文件内容的操作需要先读取再进一步操作.
为什么需要R?
R在对文件内容,特别是数据处理上几乎是最顶尖的工具.
简单的command想要实现相对复杂一些的数据处理也很困难
请看下面的两个例子:计算拼接文件中每行的均值
Bash:
cd /home/wang/Downloads/test
awk -F "\t" '{print ($1+$2+$3+$4)/4}' paste_file.txt
R:
setwd("/home/wang/Downloads/test")
data <- read.table("paste_file.txt", header = F, stringsAsFactors = F)
mean_value <- rowMeans(data)
Bash和R的有机整合
Bash精于文件处理, R精于内容处理, 那么两者的有机结合应当算是强强联合.
利用system
重复一下上述的操作:
Bash+R:
setwd("/home/wang/Downloads/test/file_paste")
file_list <- list.files()
paste_str <- paste(c("paste", file_list, "> ../paste_file.txt"), collapse = " ")
system(paste_str)
data <- read.table("../paste_file.txt", header = F, stringsAsFactors = F)
mean_value <- rowMeans(data)
可以发现,Bash的一个简单command可以完成R可能需要好几个函数配合才能实现的效果;同样,R的一个基本函数也可以完成Bash所达不到的效果.
如何进行两者的有机结合是非常有意思的事情,举一个简单的例子:
文件批量下载
如果要处理一些原始数据,通常就绕不过数据批量下载的问题,那么利用Bash中的axel
command,配合R进行数据下载.
比如我们需要下载以下数据:
那么根据提供的SRR ID,我们可以很方便的获得对应样本的下载URL地址:
cell_list <- unlist(read.csv("SraRunInfo.csv", header = T, as.is = T)[,1])
header <- "ftp://ftp.ncbi.nlm.nih.gov/sra/sra-instant/reads/ByRun/sra/SRR/"
url <- matrix(apply(
matrix(cell_list, ncol = 1),
1,
function(x){
folder = paste(unlist(strsplit(x, ""))[1:6], collapse = "")
url = paste(header, folder, "/", x, "/", x, ".sra", sep = "")
return(url)
}
), ncol = 1)
接下来只需要利用system
函数调用axel
command:
apply(
url,
1,
function(x){
download_str = paste("axel -n 40", x)
system(download_str)
}
)
当然了,直接用迅雷批量下载也是可以的.
灵活 = 代码可维护性差
通常越灵活的程序语言就意味着糟糕的代码可维护性,那么程序语言之间的互动在这方面就体现的淋漓精致.
假如对Bash一窍不通,那么加入了command调用的R脚本就会让人完全抓不到头脑.
所以如果要求非常高的代码可读性和可维护性,尽量还是应该去避免类似操作,当然了,我个人还是很喜欢的,就酱.