Dati due dataframes come qui sotto:come eseguire un interno o esterno unione di DataFrames con i panda sulla non semplicistiche criterio
>>> 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
vorremmo produrre uno stile di SQL join di entrambe le dataframes utilizzando un non- criteri semplicistici, diciamo "df_b.c> df_a.a". Da quello che posso dire, mentre il merge()
è sicuramente parte della soluzione, non posso usarlo direttamente dal momento che non accetta espressioni arbitrarie per i criteri "ON" (a meno che manchi qualcosa?).
In SQL, i risultati simile a questa:
# 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||
mio approccio attuale per inner join è quello di produrre un prodotto cartesiano di df_a e df_b, con l'aggiunta di una colonna di "1" s ad entrambi, quindi usando unione() sulla colonna "1" s, quindi applicando i criteri "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
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
per outer join, non sono sicuro del modo migliore per andare, finora Ho giocato con ricevendo il join interno, applicando poi la negazione dei criteri per ottenere tutti gli altri righe, quindi prova a modificare quella "negazione" impostata sull'originale, ma in realtà non funziona.
Modifica. HYRY ha risposto alla domanda specifica qui, ma avevo bisogno di qualcosa di più generico e più all'interno dell'API Pandas, in quanto il mio criterio di adesione potrebbe essere qualsiasi cosa, non solo un confronto. Per join esterno, prima io sono l'aggiunta di un indice in più per il lato "sinistro" che mantenere se stesso dopo che faccio l'INNER JOIN:
df_a['_left_index'] = df_a.index
allora gli facciamo lo cartesiano e ottenere il INNER JOIN:
cartesian = pd.merge(df_a, df_b, left_on='ones', right_on='ones')
innerjoin = cartesian[cartesian.c > cartesian.a]
tanto sono gli iD di indice supplementari in "df_a" che avremo bisogno, e ottenere le righe da "df_a":
remaining_left_ids = set(df_a['_left_index']).\
difference(innerjoin['_left_index'])
remaining = df_a.ix[remaining_left_ids]
allora usiamo un concat diritto(), che sostituisce le colonne mancanti con "NaN" per sinistra (pensavo che lo fosse Non fare questo prima, ma credo che lo fa):
outerjoin = pd.concat([innerjoin, remaining]).reset_index()
idea di HYRY per fare il cartesiano solo su quei colli che abbiamo bisogno di confrontare su è fondamentalmente la risposta giusta, anche se nel mio caso specifico potrebbe essere un po 'difficile da implementare (generalizzato e tutto).
domande:
Come vi produrre un "join" di df_1 e df_2 su "c> a"? farebbe lo stesso approccio "prodotto cartesiano, filtro" o c'è un modo migliore ?
Come si genera il "join esterno sinistro" dello stesso?
ancora l'analisi di questo, c'è un modo per raggiungere l'espressione utilizzando una serie Pandas (cioè generata da un'espressione come "df_a.a < df_b.c "? Non avrò necessariamente" a
zzzeek
ma solo l'idea di fare cartesiano sui cols ho bisogno di risparmiare memoria, vale la pena guardare in ... – zzzeek