以下のように2つのデータフレームが与えられます。
>>> 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
単純化されていない基準を使用して、両方のデータフレームの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||
内部結合の現在のアプローチは、両方に「1」の列を追加し、「1」の列でmerge()を使用して、「c> a」を適用することにより、df_aとdf_bのデカルト積を生成することです。基準。
>>> 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
外部結合の場合、最善の方法がわかりません。これまで、内部結合を取得し、基準の否定を適用して他のすべての行を取得し、その「否定」を編集しようとしてきました。 「オリジナルに設定しましたが、実際には機能しません。
編集します。HYRYはここで特定の質問に答えましたが、参加基準は1つの比較だけでなく、何でもかまいません。アウタージョインの場合、最初に「左側」側に追加のインデックスを追加します。これは、インナージョインを行った後もそれ自体を維持します。
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」の追加のインデックスIDを取得し、「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のアイデアは基本的に正しい答えですが、私の特定のケースでは、実装するのが少し難しいかもしれません(一般化されたものすべて)。
質問:
「c>a」でdf_1とdf_2の「結合」をどのように生成しますか?同じ「デカルト積、フィルター」アプローチを実行しますか、それともより良い方法がありますか?
同じものの「左外側結合」をどのように作成しますか?