частичное пересечение - несколько групп - PullRequest
4 голосов
/ 23 сентября 2019

Я не уверен, как подойти к моей проблеме, поэтому я не смог увидеть, существует ли она (заранее извиняюсь)

Group    Item
 A         1
 A         2
 A         3
 B         1
 B         3
 C         1
 D         2
 D         3

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

РЕЗУЛЬТАТ :

A-B: 2 (item 1 and item 3)
A-D: 2 (item 2 and item 3)

Список групп и элементов очень длинный, и максимальное количество совпадений элементов в группах, вероятно, не превышает 3-5.

NB Более 2 групп могут иметь общие элементы - например, ABE: 3 Так что недостаточно сравнивать только две группы одновременно.Мне нужно сравнить все комбинации групп.

Мои мысли

  1. Первый раунд : одна куча всех групп - по крайней мере два значения распределены между всеми?
  2. Второй раунд : Все-1 группа (все комбинации)
  3. Третий раунд : Все-2 группы (все комбинации)

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

Что вы думаете?

Спасибо!

Ответы [ 3 ]

0 голосов
/ 23 сентября 2019

Вот новое решение, которое будет работать со всеми комбинациями

Шаги:

  1. получить «группированный» фрейм данных, который группирует / перечисляет все группы, в которых находится элемент
  2. из каждой строки сгруппированных получить все возможные комбинации группы, которая имеет некоторые общие элементы
  3. из «группированного» подсчета данных для каждой комбинации, если есть 2 или более общих элементов, добавьте это в словарь

Примечание : он только перебирает групповые комбинации, которые имеют общие элементы, поэтому, если у вас много групп, он уже отфильтровывает огромную часть возможных комбинаций, у которых нет общих элементов

import numpy as np
import pandas as pd
from itertools import combinations

d = {
    "Group": "A,A,A,B,B,C,D,D".split(","),
    "Item": [1,2,3,1,3,1,2,3]
}

df = pd.DataFrame(d)

grouped = df.groupby("Item").apply(lambda x: list(x.Group))

all_combinations_with_common = [sorted(combinations(item, i)) for item in grouped 
                                    for i in range(2, len(item)) if len(item)>=2]
all_combinations_with_common = np.concatenate(all_combinations_with_common)

commons = {}
REPEAT_COUNT = 2
for comb in all_combinations_with_common:
    items = grouped.apply(lambda x: np.all(np.in1d(comb, x)))
    if sum(items)>=REPEAT_COUNT:
        commons["-".join(comb)] = grouped[items].index.values


display(commons)

выход

{'A-B': array([1, 3]), 'A-D': array([2, 3])}

0 голосов
/ 23 сентября 2019

Если у вас нет дополнительной информации для ограничения поиска, я бы просто обработал все подмножества (имеющие размер> = 2) из ​​набора уникальных групп.

Для каждого подмножества я бы искал элементы, принадлежащиевсе члены набора:

a = df['Group'].unique()
for cols in chain(*(combinations(a, i) for i in range(2, len(a) + 1))):
    vals = df['Item'].unique()
    for col in cols:
        vals = df.loc[(df.Group==col)&(df.Item.isin(vals)), 'Item'].unique()
    if len(vals) > 0: print(cols, vals)

дает:

('A', 'B') [1 3]
('A', 'C') [1]
('A', 'D') [2 3]
('B', 'C') [1]
('B', 'D') [3]
('A', 'B', 'C') [1]
('A', 'B', 'D') [3]
0 голосов
/ 23 сентября 2019

Вот как я бы подошел к проблеме, возможно, это не самый эффективный способ решения этой проблемы, но она имеет свои преимущества, чтобы быть ясной.

  1. Список для каждой группы, все элементыпринадлежит группе.
  2. Затем для каждой пары группы перечислите все общие элементы (например, для всех элементов группы A проверьте, является ли это элементом группы B).
  3. Проверьте, превышает ли количество общих элементов ваш порог X.

Это не готовая функция, но она должна быть довольно простой (или, по крайней мере, хорошим упражнением) длявоплощать в жизнь.

Веселись!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...