7

以下のように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のアイデアは基本的に正しい答えですが、私の特定のケースでは、実装するのが少し難しいかもしれません(一般化されたものすべて)。

質問:

  1. 「c>a」でdf_1とdf_2の「結合」をどのように生成しますか?同じ「デカルト積、フィルター」アプローチを実行しますか、それともより良い方法がありますか?

  2. 同じものの「左外側結合」をどのように作成しますか?

4

3 に答える 3

6

結果を計算するために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
   a  b
0  1  4
1  2  5
2  3  6
3  4  8
4  1  7
df_b
   c   d
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)

出力:

   a  b  c   d
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

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)

出力:

   a  b   c   d
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
于 2013-03-23T01:29:41.417 に答える
1

これは、broadcastingと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

于 2016-08-18T02:24:21.383 に答える
0

pyjanitorのconditional_joinは、抽象化/利便性に役立つ場合があります。関数は現在開発中です:

# pip install git+https://github.com/pyjanitor-devs/pyjanitor.git
import pandas as pd
import janitor

内部結合

 df_a.conditional_join(df_b, ('a', 'c', '<'))

  left    right
     a  b     c  d
0    1  4     2  7
1    1  4     3  8
2    2  5     3  8

左参加

df_a.conditional_join(df_b, ('a', 'c', '<'), how = 'left')

  left    right
     a  b     c    d
0    1  4   2.0  7.0
1    1  4   3.0  8.0
2    2  5   3.0  8.0
3    3  6   NaN  NaN

col from leftこの関数は、条件( 、、)のタプルの変数(* args)引数を取りますcol from_rightjoin operator

于 2021-10-11T04:28:33.590 に答える