关于 Python 函数以及如何用不同索引替换多个字符的建议

Advice regarding a Python function and how to replace multiple characters with different indexs

提问人:JuanMacD 提问时间:11/7/2023 最后编辑:JuanMacD 更新时间:11/7/2023 访问量:73

问:

我最近回到了 Python,我需要一些帮助来解决这个问题:

我有等长的DNA序列,其中一些里面有N(错误)。我需要一个脚本,将一个序列中的 N 替换为其他序列中的可用核苷酸。因此,只有当所有用作输入的序列在一个位置上都有一个 N,输出才会有一个 N。 此外,如果一个序列具有 N,但其他两个序列具有 A 和 T,则应该有两个输出:一个带有一个选项,另一个带有另一个选项。

但这并不意味着我需要所有可能的组合(那会更容易)。脚本应该“坚持”一个序列中的一组选项,而不是将所有可能性都作为输出。

以下是一些输入和预期输出作为示例:

  1. [“ATC”, “CGN”, “NNN”] 应返回 [ATC, CGC]

  2. [“ACG”, “TGT”, “CAG”] 应返回 [“ACG”, “TGT”, “CAG”]

  3. [“ATN”, “GCN”, “GGN”] 应返回 [“ATN”, “GCN”, “GGN”]

到目前为止,上面的所有示例都适用于我的代码。

但是我在使这些示例工作时遇到了一些问题:

  1. [“ACN”, “TGT”, “NNG”] 应返回 ['ACT', 'TGG', 'ACG', 'TGT']

  2. [“NTA”, “GNC”, “CGN”] 应返回 [“GTA”, “CTA”, “GGC”, “GTC”, “CGA”]

  3. [“NNA”, “CNN”, “NGN”] 应返回 ['NNA', 'CNN', 'NGN']

  4. [“ACN”, “TNT”, “NNG”] 应返回 [ACT', 'ACG', 'TCT', 'ACG']。TCG 不应该是一个有效的选项,因为“混合”了来自两个不同序列的信息:“ACT”和“TNT”

最后 3 个序列是我的输入中最常见的。 这是我到目前为止的代码,它非常简单:


import numpy as np


def procesar_secuencias(secuencias):
    output = []
    secuencias_con_n = [s for s in secuencias if 'N' in s] # check if there are N's

    if len(secuencias_con_n) == 0: # If there are no N's, simply return the sequences as is 
        return secuencias


    a = [] # positions and nt 
    b = []

    for i in range(len(secuencias)): # for all sequences

        for j,k in  enumerate(secuencias[i]): # j is position, k is nt

          if k != 'N': # if it not an N, save the information
            a.append(k)
            b.append(j)

    for s in secuencias: # for all sequences, ie [ATC, CGN, NNN]
        if 'N' in s: # only if s has N's inside
            posiciones_n = [i for i, c in enumerate(s) if c == 'N']  # save the position of the N

            if len(posiciones_n) == len(s): # if there are only N's, go to the next sequence

              break

            else:
              new_seqs = []
              for h in b: # for every "valid" option
                for u in posiciones_n: # for all positions that store an N
                    if h == u: # when there is an available option to change an N for a "valid" nt

                        new_seq = s.replace(s[h], a[u]) # replace said position for a new nt

                        new_seqs.append(new_seq)

            output.extend(new_seqs)

        else:
            # If there are no N's, append directly to the output. 
            output.append(s)


    return np.unique(output)

我相信主要问题在于两个 for 循环中的逻辑,以及我如何使用 replace。

此示例的当前输出如下: 。如果我没记错的话,它是将“N”的每个实例替换为可用列表“b”的第一个实例。这就是为什么有两个 A 和两个 C',而不是一个带有“AC”的序列和另一个带有“TG”的序列。["ACN", "TGT", "NNG"]['AAG' 'ACT' 'CCG' 'TGT']

我真的不确定如何解决它,任何帮助都是值得赞赏的!如果需要更多信息,请告诉我。

提前致谢,

python 字符串 替换 生物信息学

评论

0赞 Andrej Kesely 11/7/2023
应该输出什么?["ACN", "TNT", "NNG"]
0赞 JuanMacD 11/7/2023
它应该是:['ACT','ACG','TCT','ACG']。TCG 不应该是一个有效的选项,因为“混合”了来自两个不同序列的信息:“ACT”和“TNT”。我将编辑问题并添加此示例!
0赞 Andrej Kesely 11/7/2023
为什么要退货?您正在混合来自多个序列的字母?["NNA", "CNN", "NGN"]["CGA"]

答:

0赞 Andrej Kesely 11/7/2023 #1

你可以试试(注意:根据你的陈述,不应该从不同的序列中混合,所以不应该返回?["NNA", "CNN", "NGN"]['NNA', 'CNN', 'NGN']

test_cases = [
    ["ATC", "CGN", "NNN"],
    ["ACG", "TGT", "CAG"],
    ["ATN", "GCN", "GGN"],
    ["ACN", "TGT", "NNG"],
    ["NTA", "GNC", "CGN"],
    ["NNA", "CNN", "NGN"],
    ["ACN", "TNT", "NNG"],
]


def process(lst):
    lst_indices_N = [{i for i, ch in enumerate(v) if ch == "N"} for v in lst]
    lst_indices_non_N = [{i for i, ch in enumerate(v) if ch != "N"} for v in lst]

    out = []

    for i, v in enumerate(lst_indices_N):
        if not v:
            out.append(lst[i])
            continue
        elif v and len(v) == len(lst[i]):
            continue

        should_merge = True

        for j, u in enumerate(lst_indices_non_N):
            if v.issubset(u):
                s = list(lst[i])
                for k in v:
                    s[k] = lst[j][k]
                out.append("".join(s))
                should_merge = False

        if should_merge:
            out.append(lst[i])

    return out


for t in test_cases:
    print("test case :", t)
    print("processed :", process(t))
    print()

指纹:

test case : ['ATC', 'CGN', 'NNN']
processed : ['ATC', 'CGC']

test case : ['ACG', 'TGT', 'CAG']
processed : ['ACG', 'TGT', 'CAG']

test case : ['ATN', 'GCN', 'GGN']
processed : ['ATN', 'GCN', 'GGN']

test case : ['ACN', 'TGT', 'NNG']
processed : ['ACT', 'ACG', 'TGT', 'ACG', 'TGG']

test case : ['NTA', 'GNC', 'CGN']
processed : ['GTA', 'CTA', 'GTC', 'GGC', 'CGA', 'CGC']

test case : ['NNA', 'CNN', 'NGN']
processed : ['NNA', 'CNN', 'NGN']

test case : ['ACN', 'TNT', 'NNG']
processed : ['ACT', 'ACG', 'TCT', 'ACG']

评论

1赞 JuanMacD 11/7/2023
是的!你对最后一个是对的,对不起,我没有意识到这一点。答案似乎是对的,非常感谢!