为什么我偏爱system函数

什么是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中的axelcommand,配合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脚本就会让人完全抓不到头脑.

所以如果要求非常高的代码可读性和可维护性,尽量还是应该去避免类似操作,当然了,我个人还是很喜欢的,就酱.

posted @ 2019-05-22 15:14  PeRl`  阅读(936)  评论(1编辑  收藏  举报