Присоединение, групповая сортировка и режим взятия кортежа

У меня есть следующая проблема с ограничением, что у меня нет доступа к import pandas или чему-либо, кроме стандартных библиотек.

Словарь с ID-type1 : метка.

{'ID1': 'Label1',
 'ID2': 'Label2',
 'ID3': 'Label2',
 'ID3': 'Label3',
 'ID4': 'Label1',
 'ID5': 'Label4'...}

Список 3-кортежей с ID-type1, ID-type2, Val. Каждый идентификатор имеет тысячи уникальных значений.

[('ID1', 'ID_Type2_1', 0.3695652173913043),
 ('ID1', 'ID_Type2_2', 0.35714285714285715),
 ('ID1', 'ID_Type2_3', 0.4146341463414634),
 ('ID2', 'ID_Type2_1', 0.3125),
 ('ID2', 'ID_Type2_2', 0.4418604651162791),
 ('ID2', 'ID_Type2_3', 0.34285714285714286),
 ('ID3', 'ID_Type2_5', 0.35714285714285715),
 ('ID3', 'ID_Type2_3', 0.3488372093023256),
 ('ID3', 'ID_Type2_2', 0.3958333333333333)...]

Если бы словарь был кадром данных с именем A (3 столбца), а список — кадром данных с именем B (2 столбца). Я хотел бы сделать следующую псевдологику.

Прикрепить метку к списку кортежей.

C = left_join(A, B, on =ID-type1)

Затем выберите режим (метку) для каждого ID-type2 среди строк, соответствующих m верхним значениям в столбце Val, или, другими словами, сгруппируйте по ID-type-2, затем сохраните только верхние m (целочисленные) строки на основе Val столбец, затем выберите режим/наиболее распространенное значение столбца label.

C.groupby(ID_type-2).arrange(Val).select(rank = n()).filter(rank <= m).select(mode(label))

Другими словами, желаемый результат — это список кортежей с (ID-type2, Label)

редактировать: я думаю, что первый шаг можно сделать с чем-то вроде этого? Но второй шаг - сложная часть

from collections import defaultdict
dd = defaultdict(list)
for d in (d1, labels): # you can list as many input dicts as you want here
    # d.iteritems() in 2.0
    for key, value in d.items():
        dd[key].append(value)

person Vlo    schedule 16.10.2018    source источник
comment
Я не вижу никаких попыток кодирования в рамках заданных вами ограничений. То, что вы предоставили, не является псевдокодом в рамках данной парадигмы. Это кажется простым делом: перебрать ваши триплеты. Для каждого используйте первый элемент для поиска метки. Выпустите это со своим вторым элементом, добавив кортеж этот к вашему выходному списку.   -  person Prune    schedule 16.10.2018
comment
Я изо всех сил пытаюсь понять вопрос второй части, мне не ясно, что такое m и как фильтровать на его основе?   -  person Sven Harris    schedule 16.10.2018
comment
@SvenHarris Для каждой группы ID-type2 сохраните только верхние m (целочисленных) значений Val и соответствующие им label.   -  person Vlo    schedule 16.10.2018


Ответы (1)


Я думаю, вы можете сделать это с помощью itertools.groupby и statistics. Рассмотрим следующие примеры данных, которые вы разместили в своем вопросе:

import itertools
import statistics

d = {'ID1': 'Label1',
     'ID2': 'Label2',
     'ID3': 'Label2',
     'ID3': 'Label3',
     'ID4': 'Label1',
     'ID5': 'Label4'}

tups = [('ID1', 'ID_Type2_1', 0.3695652173913043),
        ('ID1', 'ID_Type2_2', 0.35714285714285715),
        ('ID1', 'ID_Type2_3', 0.4146341463414634),
        ('ID2', 'ID_Type2_1', 0.3125),
        ('ID2', 'ID_Type2_2', 0.4418604651162791),
        ('ID2', 'ID_Type2_3', 0.34285714285714286),
        ('ID3', 'ID_Type2_5', 0.35714285714285715),
        ('ID3', 'ID_Type2_3', 0.3488372093023256),
        ('ID3', 'ID_Type2_2', 0.3958333333333333),
        ('ID2', 'ID_Type2_5', 0.4958333333333333)]

Вы можете создать «объединение» с помощью простого понимания списка:

res = [(idt2, idt1, d[idt1], val) for idt1, idt2, val in tups]

Теперь вы можете создавать свои группы с помощью itertools.groupby. Здесь я сохраняю сгруппированные результаты в другом словаре:

res.sort() # groupby expects the list to be sorted by the grouping key

# group by id type 2 and store those grouped lists sorted in descending order of Val
groups = {k: sorted(list(g), key=lambda x: x[-1], reverse=True) for k, g in itertools.groupby(res, key=lambda x: x[0])}

Для примера данных выше группы выглядят следующим образом:

[('ID_Type2_3', 'ID1', 'Label1', 0.4146341463414634), ('ID_Type2_3', 'ID3', 'Label3', 0.3488372093023256), ('ID_Type2_3', 'ID2', 'Label2', 0.34285714285714286)]                   
[('ID_Type2_1', 'ID1', 'Label1', 0.3695652173913043), ('ID_Type2_1', 'ID2', 'Label2', 0.3125)]                                                                                     
[('ID_Type2_2', 'ID2', 'Label2', 0.4418604651162791), ('ID_Type2_2', 'ID3', 'Label3', 0.3958333333333333), ('ID_Type2_2', 'ID1', 'Label1', 0.35714285714285715)]                   
[('ID_Type2_5', 'ID2', 'Label2', 0.4958333333333333), ('ID_Type2_5', 'ID3', 'Label3', 0.35714285714285715)]

И теперь вы можете получить свой режим с помощью простого фрагмента списка каждой группы до m значений:

for k, g in groups.items():
    # label_mode_of_first_m_values_for_this_group = statistics.mode([label for idt2, idt1, label, val in g[:m]])
person slider    schedule 16.10.2018
comment
Спасибо, это сработало. На python 2 пришлось использовать другой метод для режима. - person Vlo; 16.10.2018