Python-从数据集中删除高度相似的字符串

时间:2015-08-03 06:53:27

标签: python bioinformatics

我的基因组数据集包含基本消息,如下所示:

  

位置samp1 samp2 samp2 samp3 samp4 samp5 samp6 ...
  posA T T T T T T ... ...   posB G A A G G A A ...
  posC G G G G G G ...
  ......

此文件有100000多行,每行包含200个200个样本的基数 现在我想删除每个样本中具有高相似基数的位置,下面的图片是100%相同,我将删除其中一个
similar positions

我们将类似的比率定义为(相似的基数)/(序列长度):

  

posH C C C C C C C
  posI A C C C A C C C

posH和posI的相似度为6/8 = 75% 根据需要,类似比率高于99%被视为高度相似,并删除其中一个类似的位置。

我如何有效地在python中完成这项工作? 谢谢。

2 个答案:

答案 0 :(得分:5)

6/8posH之间posI的相似性,看起来您想要归一化hamming distance的倒数(即1-d)。

您可以使用以下方法计算两个序列之间的反归一化汉明距离:

def inverse_hamming_distance(a,b):
    z = list(zip(a, b))
    return sum(e[0]==e[1] for e in z) / len(z)

它给出了:

>>> inverse_hamming_distance('CCCCCCCC', 'ACCCACCC')
0.75

但是,您可以通过早期检测两行类似来节省一些CPU周期。给定最小相似度阈值t,如果您观察到int(0.5+(1-t)*len(z))个不同的项目,则不需要直到最后,并且您已经可以告诉项目不相似。

def similar(a,b,t=0.99):
    l = min(len(a), len(b))
    t = int(0.5 + l*(1 - t))
    n = 0
    for a1, b1 in zip(a, b):
        if a1 != b1:
            n += 1
        if n > t:
            return False
    return True

试验:

>>> similar('CCCCCCCC', 'ACCCACCC', 0.75)
True
>>> similar('CCCCCCCC', 'ACCCACCC', 0.9)
False

答案 1 :(得分:2)

首先要加快速度,首先将所有数据存储为整数或二进制列表,然后再进行比较。要么会大大减少比较操作所需的内存。一个可以说是一个很好的选择。执行此操作时,我还会将每个字典值拆分为一个列表,每个项目都是特定样本:basedict = { 'posA' : [samp1, samp2,...] , ... }

from enum import Enum
Base = Enum('Base', 'A C T G')

@mescalinum的答案很好地描述了如何使用函数来计算两条线是否相似:

def similar(a,b,t=0.99):
l = min(len(a), len(b))
t = int(0.5 + l*(1 - t))
n = 0
for a1, b1 in zip(a, b):
    if a1 != b1:
        n += 1
    if n > t:
        return False
return True

剩下的就是创建一个适用于您的数据集的循环。 similarpositions列出了每个被认为“相似”的职位的关键字。

similarpositions = []
for key in basedict:
    samplecomps = (len(basedict[key]) * (len(basedict[key]) - 1)) / 2 # number of comparisons between samples needed
    dissimilar = 0
    for item1 in basedict[key]:
        for item2 in basedict[key]:
            if similar(item1, item2, 0.99) == False:
                dissimilar += 1
                if samplecomps / dissimilar > 0.01: // break once we know too many dissimilar results, to save unneeded comparisions
                    break
        if samplecomps / dissimilar > 0.01:
            break
    if samplecomps / dissimilar <= 0.01:
        similarpositions.append(key)