在Python中从等长字符串计算相似性/差异矩阵

时间:2017-04-20 06:20:38

标签: string python-3.x numpy matrix string-comparison

我在Python中有一对等长字符串,以及一个可接受的字母表。并非字符串中的所有字母都来自接受的字母表。 E.g。

str1 = 'ACGT-N?A'
str2 = 'AAGAA??T'
alphabet = 'ACGT'

我想得到的是numpy矩阵,它描述了字符串之间的相似点和不同点。即矩阵的列是str1中接受的字母表中的字母,行是str2中接受的字母表中的字母。条目是str1str2包含相关字母的次数的总和。我只关心两个字符串在给定位置接受字母的情况。

因此,对于上面的示例,我的输出将是(cols为str1,行为str2,名称按字母顺序从左上角开始):

# cols & rows both refer to 'A', 'C', 'G', 'T' starting top left
# cols are str1, rows are str2

array([[ 1,  1,  0,  1],
       [ 0,  0,  0,  0],
       [ 0,  0,  1,  0],
       [ 1,  0,  0,  0]])

我可以通过遍历所有可能的解决方案来强制执行此操作,但我想知道是否有人提示(或链接)更一般的解决方案。例如。有没有办法更接近我可以定义N个唯一字符的字母表,并给出两个等长输入字符串的N-by-N矩阵?

蛮力方法:

def matrix(s1,s2):
    m= np.zeros((4,4))
    for i in range(len(s1)):
        if s1[i]==s2[i]:
            if s1[i]=="A":
                m[0,0]=m[0,0]+1
            elif s1[i]=="C":
                m[1,1]=m[1,1]+1
            elif s1[i]=="G":
                m[2,2]=m[2,2]+1
            elif s1[i]=="T":
                m[3,3]=m[3,3]+1
        elif s1[i]=="A":
            if s2[i]=="C":
                m[1,0]=m[1,0]+1
            elif s2[i]=="G":
                m[2,0]=m[2,0]+1
            elif s2[i]=="T":
                m[3,0]=m[3,0]+1
        elif s1[i]=="C":
            if s2[i]=="A":
                m[0,1]=m[0,1]+1
            elif s2[i]=="G":
                m[2,1]=m[2,1]+1
            elif s2[i]=="T":
                m[3,1]=m[3,1]+1
        elif s1[i]=="G":
            if s2[i]=="A":
                m[0,2]=m[0,2]+1
            elif s2[i]=="C":
                m[1,2]=m[1,2]+1
            elif s2[i]=="T":
                m[3,2]=m[3,2]+1
        elif s1[i]=="T":
            if s2[i]=="C":
                m[1,3]=m[1,3]+1
            elif s2[i]=="G":
                m[2,3]=m[2,3]+1
            elif s2[i]=="A":
                m[0,3]=m[0,3]+1           
    return m

2 个答案:

答案 0 :(得分:2)

使用布尔矩阵的点积(保持秩序正确的最简单方法):

def simMtx(a, x, y):
    a = np.array(list(a))
    x = np.array(list(x))
    y = np.array(list(y))
    ax = (x[:, None] == a[None, :]).astype(int)
    ay = (y[:, None] == a[None, :]).astype(int)
    return np.dot(ay.T, ax)

simMtx(alphabet, str1, str2)
Out[183]: 
array([[1, 1, 0, 1],
       [0, 0, 0, 0],
       [0, 0, 1, 0],
       [1, 0, 0, 0]])

答案 1 :(得分:1)

此任务可以使用set,一些理解和pandas.DataFrame简洁地完成:

<强>代码:

from collections import Counter
import pandas as pd

def dot_product(allowed, s1, s2):
    in_s1 = {c: set([y.start() for y in [
        x for x in re.finditer(c, s1)]]) for c in allowed}
    in_s2 = {c: set([y.start() for y in [
        x for x in re.finditer(c, s2)]]) for c in allowed}
    return pd.DataFrame(
        [[len(in_s1[c1] & in_s2[c2]) for c1 in allowed] for c2 in allowed],
        columns=list(allowed),
        index=list(allowed),
    )

测试代码:

str1 = 'ACGT-N?A'
str2 = 'AAGAA??T'
alphabet = 'ACGT'

print(dot_product_sum(alphabet, str1, str2))

<强>结果:

   A  C  G  T
A  1  1  0  1
C  0  0  0  0
G  0  0  1  0
T  1  0  0  0