Разделение словаря в список словаря на основе перекрывающихся значений - PullRequest
0 голосов
/ 19 марта 2020

У меня есть словарь с хромосомными координатами, как в следующем примере:

First_dict = {Key1: ['chr10', 19010495, 19014590, 19014064],
Key2: ['chr10', 19010495, 19014658],
Key3: ['chr10', 19010502, 19014641],
Key4: ['chr10', 37375766, 37377526],
Key5: ['chr10', 76310389, 76315990, 76312224, 76312963],
Key6: ['chr11', 14806147, 14814006]} 

Я хотел бы создать список словарей, где находятся текущие ключи с минимумом и максимумом хромосомных координат (словарь значения) перекрываются, скажем, по крайней мере 1000, сгруппированы в новый словарь, а остальные являются отдельными словарями в новом списке.

В идеале что-то вроде:

New_list = 
[{Key1: ['chr10', 19010495, 19014590, 19014064],Key2: ['chr10', 19010495, 19014658], Key3: ['chr10', 19010502, 19014641]}, 
{Key4: ['chr10', 37375766, 37377526]},
{Key5: ['chr10', 76310389, 76315990, 76312224, 76312963]},
{Key6: ['chr11', 14806147, 14814006]}]

Где key1, key2 и key3 сгруппированы вместе как новый словарь в New_list, поскольку их хромосомные координаты перекрываются, а key4, key5, key6 индивидуальны словари с New_list, так как они не перекрываются вообще.

Моя первоначальная идея заключалась в том, чтобы разделить «First_dict» на список словарей, используя

[{k: v} for (k, v) in First_dict.items()]

, а затем выполнить итерацию по каждому dict, чтобы сравнить минимальное и максимальное значения с предыдущим словарем, чтобы проверить перекрываются, а затем создать новый список. Но у меня есть несколько проблем, с которыми я не могу разобраться.

Я также искал другие вопросы, объединяющие словари, как в вопросе: Группировка Python словарных ключей в виде списка и создайте новый словарь с этим списком в качестве значения

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

Может ли кто-нибудь помочь с этим или предложить предложение попробовать? Большое спасибо.

1 Ответ

1 голос
/ 19 марта 2020

Этот вопрос, вероятно, лучше подходит для решения на основе графов. Ничто не препятствует перекрытию нескольких диапазонов с разными интервалами.

#!/usr/bin/env python3

from pprint import pprint
from itertools import groupby


def mapper(d, overlap=1000):
    """Each chromsomal coordinate must be interrogated
    to determine if it is within +/-overlap of any other

    Range within any other    Original Dictionary     Transcript
    value will match          key and chromosome      element from the list
    ------------------------  ----------------------  ----------
    (el-overlap, el+overlap), (dict-key, chromosome), el)
    """
    for key, ch in d.items():
        for el in ch[1:]:
            yield ((el-overlap, el+overlap), (key, ch[0]), el)

def sorted_mapper(d, overlap=1000):
    """Simply sort the mapper data by its first element
    """
    for r in sorted(mapper(d, overlap), key=lambda x: x[0]):
        yield r

def groups(iter_):
    previous = next(iter_)
    retval = [previous]
    for chrm in iter_:
        if previous[0][0] <= chrm[-1] <= previous[0][1]:
            retval.append(chrm)
        else:
            yield retval
            previous = chrm
            retval = [previous]
    yield retval

def reduce_phase1(iter_):
    for l in iter_:
        retval = {}
        for (minc, maxc), (key, lbl), chrm in l:
            x = retval.get(key,[lbl])
            x.append(chrm)
            retval[key] = x
        yield retval

def update_dict(d1, d2):
    retval = d1
    for key, value in d2.items():
        if key in d1.keys():
            retval[key].extend(value[1:])
    return retval

def reduce_phase2(iter_):
    retval = [next(iter_)]
    retval_keys = [set([k for k in retval[0].keys()])]
    for d in iter_:
        keyset = set([k for k in d.keys()])
        isnew = True
        for i, e in enumerate(retval_keys):
            if keyset <= e:
                isnew = False
                retval[i] = update_dict(retval[i], d)
        if isnew:
            retval.append(d)
            retval_keys.append(keyset)
    return retval

First_dict = {Key1: ['chr10', 19010495, 19014590, 19014064],
Key2: ['chr10', 19010495, 19014658],
Key3: ['chr10', 19010502, 19014641],
Key4: ['chr10', 37375766, 37377526],
Key5: ['chr10', 76310389, 76315990, 76312224, 76312963],
Key6: ['chr11', 14806147, 14814006]} 

New_list = [
        {
            "Key1": ['chr10', 19010495, 19014590, 19014064],
            "Key2": ['chr10', 19010495, 19014658],
            "Key3": ['chr10', 19010502, 19014641]
        },
        {"Key4": ['chr10', 37375766, 37377526]},
        {"Key5": ['chr10', 76310389, 76315990, 76312224, 76312963]},
        {"Key6": ['chr11', 14806147, 14814006]}
]

pprint(First_dict)
print('-'*40)
g = groups(sorted_ranges(First_dict))
p1 = reduce_phase1(groups(sorted_ranges(First_dict)))
p2 = reduce_phase2(p1)
pprint(p2)

Выход

{'Key1': ['chr10', 19010495, 19014590, 19014064],
 'Key2': ['chr10', 19010495, 19014658],
 'Key3': ['chr10', 19010502, 19014641],
 'Key4': ['chr10', 37375766, 37377526],
 'Key5': ['chr10', 76310389, 76315990, 76312224, 76312963],
 'Key6': ['chr11', 14806147, 14814006]}
----------------------------------------
[{'Key6': ['chr11', 14806147, 14814006]},
 {'Key1': ['chr10', 19010495, 19014064, 19014590],
  'Key2': ['chr10', 19010495, 19014658],
  'Key3': ['chr10', 19010502, 19014641]},
 {'Key4': ['chr10', 37375766, 37377526]},
 {'Key5': ['chr10', 76310389, 76312224, 76312963, 76315990]}]

TLDR;

Выход Mapper

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

((el-1000, el+1000), (dict-key, chromosome), el)

(el-1000, el + 1000) - это диапазон, в котором может совпадать любой другой хромосомный элемент.

(dict-key, chromosome) исходный словарь для этой хромосомы.

el является одним элементом из хромосомной координаты.

((19009495, 19011495), ('Key1', 'chr10'), 19010495)
((19013590, 19015590), ('Key1', 'chr10'), 19014590)
((19013064, 19015064), ('Key1', 'chr10'), 19014064)
((19009495, 19011495), ('Key2', 'chr10'), 19010495)
((19013658, 19015658), ('Key2', 'chr10'), 19014658)
((19009502, 19011502), ('Key3', 'chr10'), 19010502)
((19013641, 19015641), ('Key3', 'chr10'), 19014641)
((37374766, 37376766), ('Key4', 'chr10'), 37375766)
((37376526, 37378526), ('Key4', 'chr10'), 37377526)
((76309389, 76311389), ('Key5', 'chr10'), 76310389)
((76314990, 76316990), ('Key5', 'chr10'), 76315990)
((76311224, 76313224), ('Key5', 'chr10'), 76312224)
((76311963, 76313963), ('Key5', 'chr10'), 76312963)
((14805147, 14807147), ('Key6', 'chr11'), 14806147)
((14813006, 14815006), ('Key6', 'chr11'), 14814006)

ПРИМЕЧАНИЕ: Выход из преобразователя не отсортирован.

Сортировка

Нам нужно отсортировать преобразованные данные, используя (el-1000, el + 1000) в качестве ключа.
Это позволит нам проверить, находится ли следующее значение в пределах диапазона предыдущего значения. Поскольку ключи расположены в отсортированном порядке, мы сможем объединить значения, которые находятся в пределах указанного перекрытия.

((14805147, 14807147), ('Key6', 'chr11'), 14806147)
((14813006, 14815006), ('Key6', 'chr11'), 14814006)
((19009495, 19011495), ('Key1', 'chr10'), 19010495)
((19009495, 19011495), ('Key2', 'chr10'), 19010495)
((19009502, 19011502), ('Key3', 'chr10'), 19010502)
((19013064, 19015064), ('Key1', 'chr10'), 19014064)
((19013590, 19015590), ('Key1', 'chr10'), 19014590)
((19013641, 19015641), ('Key3', 'chr10'), 19014641)
((19013658, 19015658), ('Key2', 'chr10'), 19014658)
((37374766, 37376766), ('Key4', 'chr10'), 37375766)
((37376526, 37378526), ('Key4', 'chr10'), 37377526)
((76309389, 76311389), ('Key5', 'chr10'), 76310389)
((76311224, 76313224), ('Key5', 'chr10'), 76312224)
((76311963, 76313963), ('Key5', 'chr10'), 76312963)
((76314990, 76316990), ('Key5', 'chr10'), 76315990)

Группировать

Группировать значения, которые находятся в пределах указанного перекрытия. Появляющиеся списки будут содержать значения из хромосом, которые находятся в перекрытии предыдущей хромосомы.

[((14805147, 14807147), ('Key6', 'chr11'), 14806147)]
----------------------------------------
[((14813006, 14815006), ('Key6', 'chr11'), 14814006)]
----------------------------------------
[((19009495, 19011495), ('Key1', 'chr10'), 19010495),
 ((19009495, 19011495), ('Key2', 'chr10'), 19010495),
 ((19009502, 19011502), ('Key3', 'chr10'), 19010502)]
----------------------------------------
[((19013064, 19015064), ('Key1', 'chr10'), 19014064),
 ((19013590, 19015590), ('Key1', 'chr10'), 19014590),
 ((19013641, 19015641), ('Key3', 'chr10'), 19014641),
 ((19013658, 19015658), ('Key2', 'chr10'), 19014658)]
----------------------------------------
[((37374766, 37376766), ('Key4', 'chr10'), 37375766)]
----------------------------------------
[((37376526, 37378526), ('Key4', 'chr10'), 37377526)]
----------------------------------------
[((76309389, 76311389), ('Key5', 'chr10'), 76310389)]
----------------------------------------
[((76311224, 76313224), ('Key5', 'chr10'), 76312224),
 ((76311963, 76313963), ('Key5', 'chr10'), 76312963)]
----------------------------------------
[((76314990, 76316990), ('Key5', 'chr10'), 76315990)]
----------------------------------------

Уменьшение - Фаза 1

Очистить данные, удалив встроенные функции.

{'Key6': ['chr11', 14806147]}
----------------------------------------
{'Key6': ['chr11', 14814006]}
----------------------------------------
{'Key1': ['chr10', 19010495],
 'Key2': ['chr10', 19010495],
 'Key3': ['chr10', 19010502]}
----------------------------------------
{'Key1': ['chr10', 19014064, 19014590],
 'Key2': ['chr10', 19014658],
 'Key3': ['chr10', 19014641]}
----------------------------------------
{'Key4': ['chr10', 37375766]}
----------------------------------------
{'Key4': ['chr10', 37377526]}
----------------------------------------
{'Key5': ['chr10', 76310389]}
----------------------------------------
{'Key5': ['chr10', 76312224, 76312963]}
----------------------------------------
{'Key5': ['chr10', 76315990]}
----------------------------------------

Reduce - Phase 2

Объедините смещенные ключи словаря с их исходным словарем. Добавьте значения для соответствующей хромосомы, когда ключи словаря совпадают.

{'Key6': ['chr11', 14806147, 14814006]}
----------------------------------------
{'Key1': ['chr10', 19010495, 19014064, 19014590],
 'Key2': ['chr10', 19010495, 19014658],
 'Key3': ['chr10', 19010502, 19014641]}
----------------------------------------
{'Key4': ['chr10', 37375766, 37377526]}
----------------------------------------
{'Key5': ['chr10', 76310389, 76312224, 76312963, 76315990]}
----------------------------------------
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...