как выполнить внутреннее или внешнее соединение DataFrames с Pandas по не упрощенному критерию

Учитывая два кадра данных, как показано ниже:

>>> import pandas as pd >>> df_a = pd.DataFrame([{"a": 1, "b": 4}, {"a": 2, "b": 5}, {"a": 3, "b": 6}]) >>> df_b = pd.DataFrame([{"c": 2, "d": 7}, {"c": 3, "d": 8}]) >>> df_a ab 0 1 4 1 2 5 2 3 6 >>> df_b cd 0 2 7 1 3 8 

мы хотели бы создать соединение SQL-стиля обоих фреймов данных с использованием не упрощенных критериев, скажем, «df_b.c> df_a.a». Из того, что я могу сказать, в то время как merge() , безусловно, является частью решения, я не могу использовать его напрямую, поскольку он не принимает произвольные выражения для критериев «ON» (если только я что-то не хватает?).

Результаты SQL выглядят следующим образом:

 # inner join sqlite> select * from df_a join df_b on c > a; 1|4|2|7 1|4|3|8 2|5|3|8 # outer join sqlite> select * from df_a left outer join df_b on c > a; 1|4|2|7 1|4|3|8 2|5|3|8 3|6|| 

мой текущий подход к внутреннему соединению состоит в том, чтобы произвести декартово произведение df_a и df_b, добавив столбец «1» s к обоим, затем используя merge () в столбце «1», а затем применив «c> a», критерии.

 >>> import numpy as np >>> df_a['ones'] = np.ones(3) >>> df_b['ones'] = np.ones(2) >>> cartesian = pd.merge(df_a, df_b, left_on='ones', right_on='ones') >>> cartesian ab ones cd 0 1 4 1 2 7 1 1 4 1 3 8 2 2 5 1 2 7 3 2 5 1 3 8 4 3 6 1 2 7 5 3 6 1 3 8 >>> cartesian[cartesian.c > cartesian.a] ab ones cd 0 1 4 1 2 7 1 1 4 1 3 8 3 2 5 1 3 8 

для внешнего соединения я не уверен в лучшем пути, пока я играл с получением внутреннего соединения, а затем применяю отрицание критериев, чтобы получить все остальные строки, а затем попытаюсь отредактировать это «отрицание» «установлен на оригинал, но на самом деле он не работает.

Изменить . HYRY ответила на конкретный вопрос здесь, но мне нужно было что-то более общее и более в рамках API Pandas, так как мой критерий присоединения мог быть чем угодно, а не только одним сравнением. Для внешнего присоединения сначала добавляю дополнительный указатель на «левую» сторону, которая будет поддерживать себя после внутреннего соединения:

 df_a['_left_index'] = df_a.index 

то мы делаем декартову и получаем внутреннее соединение:

 cartesian = pd.merge(df_a, df_b, left_on='ones', right_on='ones') innerjoin = cartesian[cartesian.c > cartesian.a] 

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

 remaining_left_ids = set(df_a['_left_index']).\ difference(innerjoin['_left_index']) remaining = df_a.ix[remaining_left_ids] 

то мы используем прямой concat (), который заменяет отсутствующие столбцы на «NaN» для левой (я думал, что раньше это не делалось, но, я думаю, это так):

 outerjoin = pd.concat([innerjoin, remaining]).reset_index() 

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

вопросов:

  1. Как бы вы создали «объединение» df_1 и df_2 на «c> a»? Будете ли вы делать то же самое «декартово произведение, фильтр» или лучше?

  2. Как бы вы производили «левое внешнее соединение» того же?

2 Solutions collect form web for “как выполнить внутреннее или внешнее соединение DataFrames с Pandas по не упрощенному критерию”

Я использую внешний метод ufunc для вычисления результата, вот пример:

Во-первых, некоторые данные:

 import pandas as pd import numpy as np df_a = pd.DataFrame([{"a": 1, "b": 4}, {"a": 2, "b": 5}, {"a": 3, "b": 6}, {"a": 4, "b": 8}, {"a": 1, "b": 7}]) df_b = pd.DataFrame([{"c": 2, "d": 7}, {"c": 3, "d": 8}, {"c": 2, "d": 10}]) print "df_a" print df_a print "df_b" print df_b 

вывод:

 df_a ab 0 1 4 1 2 5 2 3 6 3 4 8 4 1 7 df_b cd 0 2 7 1 3 8 2 2 10 

Внутреннее соединение, потому что это только вычисляет декартово произведение c & a , использование памяти меньше, чем декартова произведение всего DataFrame:

 ia, ib = np.where(np.less.outer(df_a.a, df_b.c)) print pd.concat((df_a.take(ia).reset_index(drop=True), df_b.take(ib).reset_index(drop=True)), axis=1) 

вывод:

  abcd 0 1 4 2 7 1 1 4 3 8 2 1 4 2 10 3 2 5 3 8 4 1 7 2 7 5 1 7 3 8 6 1 7 2 10 

для вычисления левого внешнего соединения используйте numpy.setdiff1d() чтобы найти все строки df_a которые не df_a во внутреннее соединение:

 na = np.setdiff1d(np.arange(len(df_a)), ia) nb = -1 * np.ones_like(na) oa = np.concatenate((ia, na)) ob = np.concatenate((ib, nb)) print pd.concat([df_a.take(oa).reset_index(drop=True), df_b.take(ob).reset_index(drop=True)], axis=1) 

вывод:

  abcd 0 1 4 2 7 1 1 4 3 8 2 1 4 2 10 3 2 5 3 8 4 1 7 2 7 5 1 7 3 8 6 1 7 2 10 7 3 6 NaN NaN 8 4 8 NaN NaN 

Это можно сделать так, используя трансляцию и np.where. Используйте любой бинарный оператор, который вы хотите, для параметра True / False:

 import operator as op df_a = pd.DataFrame([{"a": 1, "b": 4}, {"a": 2, "b": 5}, {"a": 3, "b": 6}]) df_b = pd.DataFrame([{"c": 2, "d": 7}, {"c": 3, "d": 8}]) binOp = op.lt matches = np.where(binOp(df_a.a[:,None],df_b.c.values)) print pd.concat([df.ix[idxs].reset_index(drop=True) for df,idxs in zip([df_a,df_b],matches)], axis=1).to_csv() 

, А, б, в, г

0,1,4,2,7

1,1,4,3,8

2,2,5,3,8

  • Как выполнить необработанный SQL в приложении SQLAlchemy-flask
  • Django не каскадирует при удалении
  • SQLAlchemy: обновление from_select
  • Python, конвертировать 9 кортежей UTC в формат MySQL datetime
  • Веб-искатель Python с базой данных MySQL
  • Python: чтение файла конфигурации с несколькими строками на ключ
  • Как запрашивать несколько таблиц за раз?
  • Использование меток в HAVING () в SQLAlchemy
  •  
    Interesting Posts for Van-Lav

    Как вы можете получить дерево вызовов с помощью профилировщиков python?

    как загрузить пользовательский модуль python в c

    Поиск номеров телефонов в скрипте python

    Как узнать, является ли исполняемый файл CPython версией отладки в python?

    __init __ () принимает ровно 2 аргумента (1 задано)?

    Запись звука Python на обнаруженный звук

    Как выполнить нелинейную оптимизацию с помощью scipy / numpy или sympy?

    Python эквивалент функции R c ()?

    Ошибка Mercurial *** не удалось импортировать расширение hggit: нет модуля с именем hggit

    Python ImportError для strptime в spyder для Windows 7

    Python не найден как зависимость во время установки «npm jsbin». Чего не хватает?

    Список объектов python, сортировка по убыванию в зависимости от атрибута объекта

    Проверьте, существует ли поле модели в Django

    scons – запуск программы после компиляции

    PermissionError: Процесс не может получить доступ к файлу, потому что он используется другим процессом:

    Python - лучший язык программирования в мире.