2014-12-09 5 views
14

Если у меня есть переменное число наборов (назовём число п), которые имеют самое м элементов каждый, что является самым эффективным способом для вычисления попарных пересечений для всех пар наборы? Обратите внимание, что это отличается от пересечения всех n наборов.Pairwise Set Пересечения в Python

Например, если у меня есть следующие наборы:

A={"a","b","c"} 
B={"c","d","e"} 
C={"a","c","e"} 

Я хочу, чтобы иметь возможность найти:

intersect_AB={"c"} 
intersect_BC={"c", "e"} 
intersect_AC={"a", "c"} 

Другой приемлемый формат (если он делает вещи проще) будет карта элементов в заданном наборе к наборам, которые содержат тот же элемент. Например:

intersections_C={"a": {"A", "C"}, 
       "c": {"A", "B", "C"} 
       "e": {"B", "C"}} 

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

Некоторые дополнительные справочная информация:

  1. Каждое из множеств имеют примерно одинаковую длину, но и очень большой (достаточно большим, чтобы хранить их в памяти реалистическое беспокойство, и алгоритм, который позволяет избежать что было бы предпочтительным, хотя это и не обязательно)
  2. Размер пересечений между любыми двумя наборами очень мал по сравнению с самими размерами множеств
  3. Если это помогает, мы можем предположить все, что нам нужно, относительно порядка наборы ввода.
+0

Вы пробовали метод, который, как вы знаете, работает? –

+0

Я бы предложил следующее: Пройдите все наборы и постройте карту, отслеживая, где вы найдете каждый элемент. Это O (NlogN) (при условии, что словарь добавляет логарифмические служебные данные), где N - общее количество элементов. – nickie

+0

Я пробовал метод, который я описал на небольших образцах, но проблема в том, что многие данные, которые я буду использовать с этим, будут загружены пользователем. Я бы идеально хотел, чтобы иметь возможность поддерживать гораздо большие варианты использования, поэтому мне было интересно, есть ли более общий/эффективный способ сделать это, чем наивный подход, который я описал. – ankushg

ответ

4

это должен делать то, что вы хотите

import random as RND 
import string 
import itertools as IT 

фиктивные некоторые данные

fnx = lambda: set(RND.sample(string.ascii_uppercase, 7)) 
S = [fnx() for c in range(5)] 

генерировать список индексов множеств в S так, что наборы могут быть ссылки более сжато ниже

idx = range(len(S)) 

получить все возможные уникальные пары предметов в S; Однако, так как множество пересечения коммутативности, мы хотим комбинации, а не перестановки

pairs = IT.combinations(idx, 2) 

написать функция выполняет пересечение множеств

nt = lambda a, b: S[a].intersection(S[b]) 

сложите эту функцию по парам & ключевых результат от каждой функции вызывает ее аргументы

res = dict([ (t, nt(*t)) for t in pairs ]) 

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

это решение, на самом деле просто две строки кода: (I) Вычислить перестановки; (ii) затем применить некоторую функцию к каждой перестановке, сохраняя возвращаемое значение в контейнере структурированного контейнера (значение ключа)

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

res = ((t, nt(*t)) for t in pairs) 

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

+1

Это занимает время O (n \ * n \ * m), если у вас есть n наборов размера m. – nickie

+1

временная сложность пересечения двух множеств, x и y равна O (len (x) * len (y)); неблагоприятная временная сложность присуща этой проблеме, поэтому лучшее, что вы можете сделать, это не сделать ее хуже и просто обратиться к постоянным факторам времени (например, не выполнять повторное внедрение базового сценария C вместо использования оптимизированных функций python, таких как списки – doug

+0

Это определенно выполняет эту работу, но было бы здорово, если бы был способ использовать этот простой синтаксис с гораздо более эффективным для работы с памятью, например [tzaman описал] (http://stackoverflow.com/a/27370005/ 152514). Спасибо! – ankushg

3

Если мы можем предположить, что наборы входных данных упорядочены, подход с псевдо-объединением кажется многообещающим. Рассматривая каждый набор как отсортированный поток, продвигайте потоки параллельно, всегда только продвигая те, где значение является самым низким среди всех текущих итераторов. Сравните каждое текущее значение с новым минимумом при каждом продвижении итератора и дамте совпадения в коллекции того же элемента.

+0

Это была следующая вещь, которую я рассматривал - идея словаря (там, где словарь вводится в объединение всех наборов * n *), казалось легче осмыслять и реализовывать, но я чувствовал, что это интуитивно это сэкономит время и потребление памяти , Любая идея, как количественно оценить экономию, которую этот подход использует по методу словаря? – ankushg

+1

Основным преимуществом подхода потоковой передачи является то, что вам нужно иметь только один элемент из каждого набора в памяти за раз. Словарный подход использует гораздо больше: ~ O (количество уникальных элементов * среднее членство). Вы можете даже сами записать пересечения в набор файлов, если это необходимо. – tzaman

-2

Как насчет использования метода пересечения множества. См. Ниже:

A={"a","b","c"} 
B={"c","d","e"} 
C={"a","c","e"} 

intersect_AB = A.intersection(B) 
intersect_BC = B.intersection(C) 
intersect_AC = A.intersection(C) 

print intersect_AB, intersect_BC, intersect_AC 
+0

Пример, который я дал, был предназначен для обобщенного примера (у меня будет много больше, чем просто наборы A, B и C), и я хотел бы избежать повторной работы, если это возможно, потому что размер моих наборов может быть огромным , – ankushg

Смежные вопросы