Повторите и сравните все значения внутри ключей в dict. Python

#python-3.x

#python-3.x

Вопрос:

У меня есть словарь, такой как :

 dict = {'group1':["-----AGAAC--C--","-----ATATA-----"],'group2':["------AGGCGGA----","--AAACC----------","--AAACCG---------"]}
  

в этом словаре я хотел бы сравнить все значения друг с другом, выполнив итерацию всех из них.
Идея состоит в том, чтобы сравнивать каждое значение и подсчитывать, когда буква стоит перед символом, отличным от буквенного.

Вот результаты, которые я должен получить (номер буквы, перед которой стоит символ, отличающийся от альфа (характеризуемый pipe в приведенном ниже примере) / длина строки)

группа1:

элемент1 против элемента2

 -----AGAAC--C--
-----*****--|--
-----ATATA-----
1/15 = 0.07
  

группа2:

элемент 1 против элемента 2

 ------AGGCGGA----
--||||*||||||----
--AAACC----------
10/17= 0.59
  

элемент 2 против элемента 3

 --AAACC----------
--*****|---------
--AAACCG---------
1/17= 0.059
  

элемент 1 против элемента 3

 ------AGGCGGA----
--||||**|||||----
--AAACCG---------
9/17=0.53
  

Вот код, который я использую для их сравнения и вычисления оценки для группы1:

 value1="-----AGAAC--C--"
value2="-----ATATA-----"

count=0
for a,b in zip(value1,value2):
    print(a.isalpha(),b.isalpha())
    if a.isalpha() == True and b.isalpha()==False:
        count  = 1
    if a.isalpha()==False and b.isalpha()== True :
        count  =1

print(count/len(value1))
  

но мне не удается сделать это для всех значений автоматически… У кого-нибудь есть идея?
Спасибо за вашу помощь.

Ответ №1:

Вот способ сделать это:

 from itertools import combinations

# Input data
dict = {
    'group1': ['-----AGAAC--C--', '-----ATATA-----'],
    'group2': ['------AGGCGGA----', '--AAACC----------', '--AAACCG---------']
}

# Iterate groups
for group, elements in dict.items():
    # Print group name
    print(group)
    # Iterate every pair of elements
    for element1, element2 in combinations(elements, 2):
        # Check both elements have the same length
        n = len(element1)
        if len(element2) != n:
            raise ValueError
        # Count the number of times character types do not match
        count = sum(c1.isalpha() != c2.isalpha() for c1, c2 in zip(element1, element2))
        # Compute ratio
        ratio = count / n
        # Print result
        print(f'    * {element1} vs {element2}: {ratio:.4f} ({count}/{n})')
    print()
  

Вывод:

 group1
    * -----AGAAC--C-- vs -----ATATA-----: 0.0667 (1/15)

group2
    * ------AGGCGGA---- vs --AAACC----------: 0.5882 (10/17)
    * ------AGGCGGA---- vs --AAACCG---------: 0.5294 (9/17)
    * --AAACC---------- vs --AAACCG---------: 0.0588 (1/17)
  

РЕДАКТИРОВАТЬ: Если вы хотите собрать список пар, которые дают оценку выше некоторого порога, вы можете немного изменить приведенный выше код:

 from itertools import combinations

dict = {
    'group1': ['-----AGAAC--C--', '-----ATATA-----'],
    'group2': ['------AGGCGGA----', '--AAACC----------', '--AAACCG---------']
}
threshold = 0.10

interesting_pairs = []
for group, elements in dict.items():
    for element1, element2 in combinations(elements, 2):
        n = len(element1)
        if len(element2) != n:
            raise ValueError
        count = sum(c1.isalpha() != c2.isalpha() for c1, c2 in zip(element1, element2))
        ratio = count / n
        if ratio > threshold:
            interesting_pairs.append((element1, element2))

print(interesting_pairs)
# [('------AGGCGGA----', '--AAACC----------'), ('------AGGCGGA----', '--AAACCG---------')]
  

РЕДАКТИРОВАТЬ 2: Следуя обсуждению в комментариях, вот еще один вариант, который группирует элементы с коэффициентом, превышающим некоторый порог, транзитивно. На самом деле это еще одна отдельная проблема, а именно поиск связанных компонентов графика, заданного этим отношением. Вы можете сделать это, например, с помощью поиска в глубину:

 from itertools import combinations

dict = {
    'group1': ['-----AGAAC--C--', '-----ATATA-----'],
    'group2': ['------AGGCGGA----', '--AAACC----------', '--AAACCG---------']
}
threshold = 0.10

# Find connected elements
connected = {}
for group, elements in dict.items():
    for element1, element2 in combinations(elements, 2):
        n = len(element1)
        if len(element2) != n:
            raise ValueError
        count = sum(c1.isalpha() != c2.isalpha() for c1, c2 in zip(element1, element2))
        ratio = count / n
        if ratio > threshold:
            connected.setdefault(element1, {element1}).add(element2)
            connected.setdefault(element2, {element2}).add(element1)

# Search components with DFS
result = []
visited = set()
for elem, conn in  connected.items():
    if elem in visited:
        continue
    visited.add(elem)
    conn = set(conn)
    pending = list(conn)
    while pending:
        subelem = pending.pop()
        if subelem in visited:
            continue
        visited.add(subelem)
        subconn = connected[subelem]
        conn.update(subconn)
        pending.extend(subconn)
    result.append(conn)
print(result)
# [{'------AGGCGGA----', '--AAACCG---------', '--AAACC----------'}]
  

Комментарии:

1. Ого, спасибо, я не ожидал чего-то подобного. Спасибо за ваше время 🙂

2. Есть ли у вас идея, как я мог бы поместить, например, все элементы, которые имеют отношение > 0.10, в новый список list вместе? например, поместите ------AGGCGGA---- , --AAACC---------- и --AAACCG--------- вместе в такой список (и то же самое для group1), как : list1 = [["------AGGCGGA----" , "--AAACC----------", "--AAACCG---------"],["-----AGAAC--C--","-----ATATA----"]

3. @chippycentra Я не уверен, что понимаю, что вы имеете в виду, list1 определенный вами файл содержит все элементы в group2 и group1 .

4. Ho извините, на самом деле я хотел бы создать новый список и внутри этого списка создать список пар последовательностей, которые имеют отношение > 0.10 . Итак, здесь, в этом примере, если соотношение между ------AGGCGGA---- vs --AAACCG--------- становится 0.005 вместо 0.5294 и -----AGAAC--C-- vs -----ATATA----- становится 0.5 вместо 0.0667 list1 = [["------AGGCGGA----" , "--AAACC----------"],"[-----AGAAC--C--","-----ATATA-----"]] , я должен получить список, такой как:, , , но в реальном примере я должен получить : list1 = [["------AGGCGGA----" , "--AAACC----------", "--AAACCG---------"]]

5. @chippycentra Я добавил вариант решения, я не уверен, что это то, чего вы добивались.