Репликация SQL 'Join' в Python - PullRequest
3 голосов
/ 06 июня 2010

Я пытаюсь перейти с R на Python (в основном это касается общей гибкости). С Numpy, matplotlib и ipython я могу охватить все мои варианты использования, за исключением объединения «наборов данных». Я хотел бы имитировать соединение SQL по выражению (внутреннему, внешнему, полному) исключительно в Python. R обрабатывает это с помощью функции 'слияния'.

Я пробовал numpy.lib.recfunctions join_by, но у него есть критические проблемы с дубликатами вдоль «ключа»:


join_by(key, r1, r2, jointype='inner', r1postfix='1', r2postfix='2',
        defaults=None, usemask=True, asrecarray=False)

Объединение массивов r1 и r2 по ключу key.

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

Ни r1, ни r2 не должно иметь дубликатов вдоль key: присутствие дубликатов сделает вывод совершенно ненадежным. Обратите внимание, что дубликаты не ищет по алгоритму.

источник: http://presbrey.mit.edu:1234/numpy.lib.recfunctions.html


Любые указатели или помощь будут наиболее ценными!

Ответы [ 2 ]

6 голосов
/ 06 июня 2010

Предположим, что вы представляете эквивалент таблицы SQL, в Python, как список диктов, причем все дикты, имеющие одинаковые (предположим, строковые) ключи (другие представления, в том числе включенные numpy, могут быть логически сведены к эквивалентная форма). Теперь внутреннее соединение является (опять же, с логической точки зрения) проекцией их декартового произведения - в общем случае, принимая аргумент предиката on (который принимает два аргумента, одну «запись» [[dict]) ] из каждой таблицы и возвращает истинное значение, если две записи должны быть объединены), простой подход (использование префиксов для каждой таблицы для устранения неоднозначности против риска того, что две таблицы в противном случае могли бы иметь одноименные «поля»):

def inner_join(tab1, tab2, prefix1, prefix2, on):
  for r1 in tab1:
    for r2 in tab2:
      if on(r1, r2):
        row = dict((prefix1 + k1, v1) for k1, v1 in r1.items())
        row.update((prefix2 + k2, v2) for k2, v2 in r2.items())
        yield row

Теперь, конечно, вы не хотите, чтобы делал это таким образом, потому что производительность равна O(M * N) - но, для указанной вами общности ("имитировать SQL-соединение выражением (внутренняя , external, full) ") альтернативы действительно нет, потому что предложение ON для JOIN довольно неограниченно.

Для внешних и полных объединений вам необходимо дополнительно хранить информацию, идентифицирующую, какие записи [[из одной или обеих таблиц]] еще не были получены, а в противном случае - например, для левого соединения вы бы добавили bool, сбросьте его до yielded = False до внутреннего цикла for r2, установите на True, если выполняется yield, и после внутреннего цикла if not yielded: создайте искусственное соединение запись (предположительно, с использованием None вместо NULL вместо пропущенных значений v2, поскольку r2 фактически не используется для этой цели).

Чтобы получить какие-либо существенные улучшения эффективности, вам необходимо уточнить, какие ограничения вы хотите соблюдать в отношении предиката on и таблиц - по вашему вопросу мы уже знаем, что вы не можете жить с unique ограничение на ключи любой из таблиц, но есть много других ограничений, которые потенциально могут помочь, и заставить нас угадывать, что такие ограничения действительно применяются в вашем случае, было бы довольно непродуктивным усилием.

3 голосов
/ 11 марта 2013

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

Библиотека pandas является идеальным решением. Он предоставляет класс «фрейм данных» и метод «слияния».

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