Python 替换以txt制表符分隔的大型文件中第一行的文本
我有一个巨大的文本文件(19GB大小);这是一个包含变量和观察值的遗传数据文件。Python 替换以txt制表符分隔的大型文件中第一行的文本,python,perl,file,vbscript,Python,Perl,File,Vbscript,我有一个巨大的文本文件(19GB大小);这是一个包含变量和观察值的遗传数据文件。 第一行包含变量名,其结构如下: id1.var1 id1.var2 id1.var3 id2.var1 id2.var2 id2.var3 我需要交换id1,id2等。对于另一个文本文件中的相应值(此文件约有7k行),ID不按任何特定顺序排列,其结构如下: oldId newIds id1 rs004 id2 rs135 我在谷歌上做了一些搜索,但找不到一种语言可以做到以下几点: 读第一行 用新ID替换ID
第一行包含变量名,其结构如下:
id1.var1 id1.var2 id1.var3 id2.var1 id2.var2 id2.var3
我需要交换id1,id2等。对于另一个文本文件中的相应值(此文件约有7k行),ID不按任何特定顺序排列,其结构如下:
oldId newIds
id1 rs004
id2 rs135
我在谷歌上做了一些搜索,但找不到一种语言可以做到以下几点:
实现这一目标的最佳语言是什么?
我们有在python、vbscipt和Perl方面有经验的人员。这应该很容易。我会使用Python,因为我是Python迷。大纲:
- 读取映射文件并保存映射(在Python中,使用字典)
- 一次读取一行数据文件,重新映射变量名称,然后输出编辑的行
#!/usr/bin/python
import re
import sys
try:
fname_idmap, fname_in, fname_out = sys.argv[1:]
except ValueError:
print("Usage: remap_ids <id_map_file> <input_file> <output_file>")
sys.exit(1)
# pattern to match an ID, only as a complete word (do not match inside another id)
# match start of line or whitespace, then match non-period until a period is seen
pat_id = re.compile("(^|\s)([^.]+).")
idmap = {}
def remap_id(m):
before_word = m.group(1)
word = m.group(2)
if word in idmap:
return before_word + idmap[word] + "."
else:
return m.group(0) # return full matched string unchanged
def replace_ids(line, idmap):
return re.sub(pat_id, remap_id, line)
with open(fname_idmap, "r") as f:
next(f) # discard first line with column header: "oldId newIds"
for line in f:
key, value = line.split()
idmap[key] = value
with open(fname_in, "r") as f_in, open(fname_out, "w") as f_out:
for line in f_in:
line = replace_ids(line, idmap)
f_out.write(line)
#/usr/bin/python
进口稀土
导入系统
尝试:
fname_idmap,fname_in,fname_out=sys.argv[1:]
除值错误外:
打印(“用法:重新映射ID”)
系统出口(1)
#模式匹配一个ID,仅作为一个完整的单词(在另一个ID内不匹配)
#匹配行或空格的开头,然后匹配非句点,直到看到句点为止
pat_id=re.compile(“(^|\s)([^.]+)”)
idmap={}
def重新映射id(m):
前单词=m.组(1)
word=m.组(2)
如果idmap中有单词:
返回在\u word+idmap[word]+”之前
其他:
返回m.group(0)#返回完全匹配的字符串不变
def replace_ID(行,idmap):
返回重新分配(分配id、重新映射id、行)
将open(fname_idmap,“r”)作为f:
下一步(f)#放弃列标题为“oldId newIds”的第一行
对于f中的行:
key,value=line.split()
idmap[键]=值
以open(fname_in,“r”)作为f_in,open(fname_out,“w”)作为f_out:
对于f_in中的行:
line=替换id(line,idmap)
f_out.写入(行)
整个“替换”过程在几乎任何语言中都是可能的(我对Python和Perl很确定),只要替换行的长度与原始行的长度相同,或者可以通过填充空格使其相同(否则,您必须重写整个文件)
打开文件进行读写(w+
模式),读取第一行,准备新行,seek
到文件中的位置0,写入新行,关闭文件。我建议您使用该模块,它将文本文件中的行映射到一个Perl数组,并使头文件后面的行的重写成为一项简单的工作
这个程序演示了。它首先将所有旧/新ID读入一个散列,然后使用Tie::file
映射数据文件。使用替换修改文件的第一行(在$file[0]
中),然后解开数组以重写和关闭文件
您需要更改我使用的文件名。还要注意的是,我假设ID总是“单词”字符(字母数字加下划线),后跟一个点,并且没有空格。当然,在修改文件之前,您需要备份文件,并且在更新真实文件之前,您应该在较小的文件上测试程序
use strict;
use warnings;
use Tie::File;
my %ids;
open my $fh, '<', 'newids.txt' or die $!;
while (<$fh>) {
my ($old, $new) = split;
$ids{$old} = $new;
}
tie my @file, 'Tie::File', 'datafile.txt' or die $!;
$file[0] =~ s<(\w+)(?=\.)><$ids{$1} // $1>eg;
untie @file;
使用严格;
使用警告;
使用Tie::文件;
我的%id;
打开我的$fh,'如果“id1”=>“rs004”,它可能不起作用。所以这可能是编写新文件的唯一方法。谢谢。我现在正在运行一个Python代码,它实现了您的建议。ID的长度不同,需要重写文件。我在windows环境中,运行可能需要几个小时。我希望它能起作用。非常感谢!我将向我的程序员展示这段代码。谢谢