一题多解:AWK、R、Python大比拼,如何用不同的编程语言轻松合并行列名相同的多个文件

文摘   2024-09-02 15:52   陕西  

关注我们并在后台回复 “进群”,即可加入农心生信工作室学习交流群,群内不定时分享源代码及示例文件,并在线交流答疑。我们在等你!

由于微信改版,乱序推送,很多朋友反映收不到公众号推文。快跟着图片步骤,将公众号设为星标,不错过每一条精彩内容!


本公众号已开通留言功能,欢迎大家直接在文末留言交流!


写在前面

当我们在处理任何组学的fasta序列数据时,对不同样本运行相同的软件后可能会生成相同的输出文件,这些根据样本名命名的输出文件有一个特点:具有相同的行名和列名但数值不同。如果样本量很大且我们可能只需要不同样本的某一列信息,这时就需要对这些文件的特定列进行提取并在列名上添加样本名target,最终将不同样本输出文档的特定列合并到一个新表中。

例如,有四个样本的输出文档sample1.txt, sample2.txt, sample3.txt, sample4.txt

以及一个储存样本名id的list文件sampleid.txt

我们发现,这四个文件的第一列,也就是名为name的列都相同,那么,如何根据相同的name列合并四个文件呢?

这里有多种方式实现这个需求。

单行AWK

一行命令实现:

awk -F '\t' '{print $1}' sample1.txt > first_column.txt && while read -r i; do sed “s/number/${i}_number/g” ${i}.txt > ${i}.txt2 && awk -F '\t' '{print $2}' ${i}.txt2 > ${i}_column2.txt; done < sampleid.txt && paste first_column.txt $(awk '{print $0"_column2.txt"}' sampleid.txt) > merge_column.txt

生成的文件merge_column.txt

最后,删除生成的中间文件

while read -r i; do rm ${i}.txt2 ${i}_column2.txt; done < sampleid.txt

这里提供给大家的是结合了awk和循环实现合并行列名相同的多样本输出文档。

该命令分为三部分:
第一部分,提取任意一个表的第一列
第二部分,处理每一个文件,为特定列加样本target后提取特定列
第三部分,合并行名(即第一列)和各列

第二部分的功能还可以替换成使用xargs,或者使用多样本并行软件parallel软件教程 | 一文学会多任务并行神器parallel

awk -F '\t' '{print $1}' sample1.txt > first_column.txt && cat sampleid.txt | xargs -I {} sh -c 'sed "s/number/{}_number/g" {}.txt | awk -F "\t" "{print \$2}" > {}_column2.txt' && paste first_column.txt $(awk '{print $0"_column2.txt"}' sampleid.txt) > merge_column.txt
awk -F '\t' '{print $1}' sample1.txt > first_column.txt && cat sampleid.txt | parallel 'sed "s/number/{}/g" {}.txt | awk -F "\t" "{print \$2}" > {}_column2.txt' && paste first_column.txt $(awk '{print $0"_column2.txt"}' sampleid.txt) > merge_column.txt

base-R

# 读取样本ID  
sample_ids <- readLines("sampleid.txt")

# 初始化一个空列表来存储数据框  
data_list <-list()

# 遍历每个样本文件  
for(sample_id in sample_ids){
# 构造文件名  
  file_name <- paste0(sample_id,".txt")
# 从文件中读取数据  
  data <- read.table(file_name, header =TRUE)

# 提取'name'列和第一列数据  
  data_subset <- data[,c("name", setdiff(names(data),"name")[1])]
# 重命名提取的数据列,以样本ID加上"_target"作为列名  
  colnames(data_subset)[2]<- paste0(sample_id,"_target")

# 添加到列表中  
  data_list[[sample_id]]<- data_subset  
}

# 通过'name'列合并所有数据框  
result <-Reduce(function(x, y) merge(x, y,by="name",all=TRUE), data_list)

# 将结果写入新文件  
write.table(result,"merge_column.txt", sep ="\t",quote=FALSE, row.names =FALSE)

tidy-R

这里与base-R的区别就在于使用了tidyverse包,对数据的处理都采用了tidyverse内的函数:

library(tidyverse)

# 读取样本ID  
sample_ids <- readLines("sampleid.txt")

# 初始化一个空列表来存储数据框  
data_list <-list()

# 遍历每个样本文件  
for(sample_id in sample_ids){
# 构造文件名  
  file_name <- paste0(sample_id,".txt")
# 从文件中读取TSV格式的数据  
  data <- read_tsv(file_name)

# 提取'name'列和以除'name'外的第一列数据列名开头的列,  
# 然后将提取的数据列重命名为“样本ID_target”  
  data_subset <- data %>%
select(name, target = starts_with(setdiff(names(data),"name")[1]))%>%
    rename(!!paste0(sample_id,"_target"):= target)

# 添加到列表中  
  data_list[[sample_id]]<- data_subset  
}

# 通过'name'列将所有数据框进行全外连接合并  
result <- reduce(data_list, full_join,by="name")

# 将结果写入新的TSV文件  
write_tsv(result,"merge_column.txt")

python

在使用python实现需求时,我们调用了pandas库,来帮助我们更好地处理数据:

import pandas as pd  

# 读取样本ID  
withopen('sampleid.txt')as f:
    sample_ids = f.read().splitlines()

# 初始化一个空的数据框  
result =None

# 遍历每个样本文件  
for sample_id in sample_ids:
    file_name =f"{sample_id}.txt"
# 从文件中读取以制表符分隔的数据  
    data = pd.read_csv(file_name, sep="\t")

# 提取'name'列和第一列数据  
    target_column = data.columns[1]
    data_subset = data[['name', target_column]].copy()
# 重命名提取的数据列,将第一列数据命名为“样本ID_target”  
    data_subset.columns =['name',f"{sample_id}_target"]

# 与结果数据框合并  
if result isNone:
        result = data_subset  
else:
# 通过'name'列以外连接的方式合并数据框  
        result = pd.merge(result, data_subset, on='name', how='outer')

# 将结果写入新的文件,使用制表符作为分隔符,不包含索引  
result.to_csv("merge_column.txt", sep="\t", index=False)

关于这个需求实现,大家还有什么另辟蹊径的解决方式,欢迎留言讨论分享!

写在最后

当然,这其实只是一个很简单的需求,但我们在这篇推文中却使用了多种方法来实现它,只是想说明,不管用什么方法,只要殊途同归,完成我们的需求,都是好方法。这好比大家在学习生物信息学的过程中,有时会纠结到底该优先学习什么编程语言;但在我们看来,这并不是一个需要太过纠结的问题,不论python、R甚至是perl,学起来、用起来才是关键,试图去掌握一门语言,而不仅仅是了解几门语言


END

编辑 | Narcissus

供稿 | littleslug

审核 | 农心生信工作室


农心生信工作室
用生信力量服务中国农业!!!