基于一列匹配文件

时间:2015-08-10 16:44:26

标签: python match matching

我的数据格式为“

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不比匹配5000好。我怎么能这样做?

2 个答案:

答案 0 :(得分:1)

希望这会给你一个良好的开端。我刚刚调用了文件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")

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

答案 1 :(得分:1)

在这里,我认为以一种相当有效的方式做你想要的东西,所以希望能够很好地扩大规模。您没有说出您正在使用的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