基于一列匹配文件

Matching files based on one column

我有表格中的数据

rsID          MAF
rs1980123     0.321
rs870123      0.142
rs314234      0.113
rs723904      0.022
rs1293048     0.098
rs1234123     0.314
rs239401      0.287
rs0928341     0.414
rs9038241     0.021
rs3801423     0.0712
rs8041239     0.312

此文件大约有 2,000 行长。我在表格中有另一个数据文件。这个文件大约有 700 万行:

rsID          iHS          Fst          MAF
rs701234      1.98         0.11         0.098
rs908341      1.32         0.31         0.189
rs101098      0.315        0.08         0.111
rs100981      0.093        0.123        0.023
rs7345123     0.481        0.20         0.479
rs090321      1.187        0.234        0.109
rs512341      1.89         0.092        0.324

我想根据它们的 MAF 是否在彼此的 +/- 0.05 范围内将 rsID 设为第一列。 rsID 列来自第一个数据,然后匹配列来自第二个数据。这些匹配基于 +/- MAF 0.05。输出看起来像:

rsID         match
rs1980123    rs512341
rs870123     rs101098
rs314234     rs090321
rs723904     rs100981
rs1293048    rs701234

我实际上希望输出看起来像(有 5,000 列):

rsID     match1     match2     match3
...      ...        ...        ...
...      ...        ...        ...
...      ...        ...        ...

我希望它尽可能随机,这样 match1 不会比 match 5000 好。我该怎么做?

希望这能给您一个好的开始。我刚刚将文件命名为 file1file2。很有创意,我知道。

import random

f1_dict = {}
f2_dict = {}
match_dict = {}
match_threshold = .05
matches_to_return = 2
skip_unmatched = True

isfirstline = True
for line in open("file1"):
    if isfirstline:
            isfirstline = False
            continue
    f1_dict[line.split()[0]] = line.split()[1]

isfirstline = True
for line in open("file2"):
    if isfirstline:
            isfirstline = False
            continue
    f2_dict[line.split()[0]] = line.split()[3]


for i in f1_dict:
    compare_rsID = i
    compare_val = f1_dict[i]
    temp_list = []
    for j in f2_dict:
        if abs(float(f2_dict[j]) - float(compare_val)) <= match_threshold:
            temp_list.append(j)
    match_dict[i] = temp_list

fo = open("output.txt", "wb")
for k in match_dict:
    if skip_unmatched and len(match_dict[k]) == 0:
        continue
    else:
        random.shuffle(match_dict[k])
        fo.write(k),
        for l in match_dict[k][:matches_to_return]:
            fo.write(" ")
            fo.write(l),
        fo.write("\n")

我确信这可以提高效率。它循环遍历第二个字典的次数与第一个字典中的索引数一样多。此外,我已将 return 的匹配数设置为 2,以便使用问题中的微小数据集进行测试。你可以赚到 5,000 或任何你喜欢的。列表中的元素不是随机的,但我也没有强加任何超出列表自然构建的顺序。 (编辑:不再正确......它现在打乱列表。)我还改变了匹配阈值,以防你想稍微探索其他值。

这是我认为以相当有效的方式完成您想要的事情的东西,因此希望能很好地扩大规模。您没有说明您使用的是哪个版本的 Python,因此它是为与版本 2.x 一起使用而编写的。用于创建输出文件的字段分隔符是一个变量,因此可以轻松更改。

匹配项的数量不限于 5,000 - 它会找到所有匹配项 - 但如果确实有必要,可以添加强制限制。

from collections import defaultdict

TOLERANCE = 0.05
DELIM = '\t'

ref_dict = {}
with open('second_file.txt', 'rt') as inf:
    next(inf)  # skip header row
    for line in inf:
        fields = line.split()
        ref_dict[fields[0]] = float(fields[3])  # rsID to MAF

matches = defaultdict(list)
with open('first_file.txt', 'rt') as inf:
    next(inf)  # skip header row
    for line in inf:
        fields = line.split()
        rsID, MAF = fields[0], float(fields[1])
        for ref_id, ref_value in ref_dict.iteritems():
            if abs(MAF-ref_value) <= TOLERANCE:
                matches[rsID].append(ref_id)

# determine maximum number of matches for output file header row
longest = max(map(len, (v for v in matches.itervalues())))

with open("output.txt", "wt") as outf:
    outf.write('rsId' + DELIM + DELIM.join('match%d' % i
                                        for i in xrange(1, longest+1)) + '\n')
    fmt_str = '{}' + DELIM + '{}\n'
    for k,v in matches.iteritems():
        outf.write(fmt_str.format(k, (DELIM.join(v))))

output.txt 的内容根据您问题中显示的样本数据生成(» 代表制表符):

rsId»   match1» match2» match3» match4
rs870123»   rs908341»   rs090321»   rs701234»   rs101098
rs9038241»  rs100981
rs1234123»  rs512341
rs1293048»  rs090321»   rs701234»   rs101098
rs723904»   rs100981
rs1980123»  rs512341
rs3801423»  rs090321»   rs701234»   rs101098»   rs100981
rs8041239»  rs512341
rs239401»   rs512341
rs314234»   rs090321»   rs701234»   rs101098