cómo realizar una combinación interna o externa de DataFrames con Pandas en un criterio no simplista

Dados dos marcos de datos de la siguiente manera:

>>> 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
   a  b
0  1  4
1  2  5
2  3  6

>>> df_b
   c  d
0  2  7
1  3  8

nos gustaría producir una unión estilo SQL de ambos marcos de datos utilizando un criterio no simplista, digamos "df_b.c> df_a.a". De lo que puedo decir, mientrasmerge() Ciertamente es parte de la solución, no puedo usarla directamente ya que no acepta expresiones arbitrarias para los criterios de "ENCENDIDO" (¿a menos que me falte algo?).

En SQL, los resultados se ven así:

# 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||

mi enfoque actual para la unión interna es producir un producto cartesiano de df_a y df_b, agregando una columna de "1" a ambos, luego utilizando merge () en la columna de "1", luego aplicando la "c> a" criterios

>>> 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
   a  b  ones  c  d
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]
   a  b  ones  c  d
0  1  4     1  2  7
1  1  4     1  3  8
3  2  5     1  3  8

para la combinación externa, no estoy seguro de cuál es el mejor camino, hasta ahora he estado jugando para obtener la combinación interna, luego aplicar la negación de los criterios para obtener todas las demás filas y luego tratar de editar esa "negación "colocado en el original, pero realmente no funciona.

Editar. HYRY respondió la pregunta específica aquí, pero necesitaba algo más genérico y más dentro de la API de Pandas, ya que mi criterio de unión podría ser cualquier cosa, no solo esa comparación. Para la unión externa, primero estoy agregando un índice adicional al lado "izquierdo" que se mantendrá después de hacer la unión interna:

df_a['_left_index'] = df_a.index

Luego hacemos lo cartesiano y obtenemos la unión interna:

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

luego obtengo los identificadores de índice adicionales en "df_a" que necesitaremos, y obtengo las filas de "df_a":

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

luego usamos un concat () recto, que reemplaza las columnas faltantes con "NaN" para la izquierda (pensé que no estaba haciendo esto antes, pero supongo que sí):

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

La idea de HYRY de hacer el cartesiano solo en los collares que necesitamos comparar es básicamente la respuesta correcta, aunque en mi caso específico podría ser un poco difícil de implementar (generalizado y todo).

preguntas:

¿Cómo producirías una "unión" de df_1 y df_2 en "c> a"? ¿Haría el mismo enfoque de "producto cartesiano, filtro" o hay alguna forma mejor?

¿Cómo producirías la "unión externa izquierda" de la misma?

Respuestas a la pregunta(2)

Su respuesta a la pregunta