求优化双文件公共ID提取方案:Bash提速/Python补全行输出
提取两个.bim文件中公共ID对应的整行
现有两种实现的问题:
- Bash版通过循环grep提取,但速度极慢(大文件需1-2天)
- Python版速度快,但仅输出公共ID,无法输出对应整行
.bim文件格式示例:
1 1:891021 0 891021 G A 1 1:903426 0 903426 T C 1 1:949654 0 949654 A G
一、Bash提速方案:Awk脚本
用Awk只需遍历两个文件各一次,避免循环grep的重复IO操作,速度大幅提升:
awk 'NR==FNR {snp[$2]=$0; next} $2 in snp {print $0}' file1.bim file2.bim > file1_2_shared.txt
说明:
NR==FNR:处理第一个文件(file1.bim)时,将第2列的ID作为键,整行内容作为值存入关联数组snpnext:跳过后续逻辑,继续处理第一个文件的下一行- 处理第二个文件(file2.bim)时,检查当前行第2列的ID是否在
snp数组中,存在则输出整行
如果需要同时输出两个文件中对应公共ID的行,可修改为:
awk 'NR==FNR {snp[$2]=$0; next} $2 in snp {print snp[$2] ORS $0}' file1.bim file2.bim > file1_2_shared_both.txt
二、Python代码修改:输出公共ID对应的整行
修改原Python脚本,保存ID到整行的映射,找到公共ID后输出对应行:
#!/usr/bin/env python3 import sys def print_common_snp_lines(inputbim1, inputbim2, outputtxt): # 读取第一个文件,建立ID到整行的映射 snp_map1 = {} with open(inputbim1, "r") as bim1: for line in bim1: parts = line.strip().split() if len(parts) >= 2: snp_map1[parts[1]] = line.strip() # 读取第二个文件,建立ID到整行的映射 snp_map2 = {} with open(inputbim2, "r") as bim2: for line in bim2: parts = line.strip().split() if len(parts) >= 2: snp_map2[parts[1]] = line.strip() # 找出公共ID,输出对应行 common_ids = set(snp_map1.keys()).intersection(snp_map2.keys()) with open(outputtxt, "w") as output: # 输出file2中的对应行(和原Bash逻辑一致) for snp_id in common_ids: output.write(snp_map2[snp_id] + "\n") # 如果需要同时输出file1和file2的行,替换为: # for snp_id in common_ids: # output.write(f"{snp_map1[snp_id]}\n{snp_map2[snp_id]}\n") if __name__ == "__main__": if len(sys.argv) != 4: print("Usage: python script.py file1.bim file2.bim output.txt") sys.exit(1) print_common_snp_lines(sys.argv[1], sys.argv[2], sys.argv[3])
修改点说明:
- 用字典
snp_map1和snp_map2分别存储两个文件中ID到整行的映射,而非仅存储ID列表 - 使用
with语句自动管理文件句柄,更安全简洁 - 增加参数检查,避免输入错误
- 可选择输出单个文件或两个文件的对应行
内容的提问来源于stack exchange,提问作者Gf.Ena
相关产品推荐
相关产品推荐

