パンダのマージを使用するときにインデックスを保持する方法


126

2つをマージDataFramesし、最初のフレームのインデックスを、マージされたデータセットのインデックスとして保持します。ただし、マージを実行すると、結果のDataFrameに整数インデックスが含まれます。左のデータフレームのインデックスを保持するように指定するにはどうすればよいですか?

In [4]: a = pd.DataFrame({'col1': {'a': 1, 'b': 2, 'c': 3}, 
                          'to_merge_on': {'a': 1, 'b': 3, 'c': 4}})

In [5]: b = pd.DataFrame({'col2': {0: 1, 1: 2, 2: 3}, 
                          'to_merge_on': {0: 1, 1: 3, 2: 5}})

In [6]: a
Out[6]:
   col1  to_merge_on
a     1            1
b     2            3
c     3            4

In [7]: b
Out[7]:
   col2  to_merge_on
0     1            1
1     2            3
2     3            5

In [8]: a.merge(b, how='left')
Out[8]:
   col1  to_merge_on  col2
0     1            1   1.0
1     2            3   2.0
2     3            4   NaN

In [9]: _.index
Out[9]: Int64Index([0, 1, 2], dtype='int64')

編集:簡単に再現できるサンプルコードに切り替えました


2
特定の列でマージする場合、どのインデックスを使用するかが明確ではありません(両方が異なる場合)。
ボノボ

回答:


161
In [5]: a.reset_index().merge(b, how="left").set_index('index')
Out[5]:
       col1  to_merge_on  col2
index
a         1            1     1
b         2            3     2
c         3            4   NaN

注:一部の左マージ操作のために複数の一致が間にある場合は、複数の行で終わることab、あなたは(重複排除する必要があります重複排除のためのマニュアルを参照して)。これが、パンダがインデックスを保持しない理由です。


4
非常に賢い。a.merge(b、how = "left")。set_index(a.index)も機能しますが、堅牢性は低くなります(最初の部分でインデックス値がaに失われてからリセットされるため)
DanB

11
この特定のケースでは、これらは同等です。しかし、多くのマージ操作では、結果のフレームには元の行と同じ数の行がありませんaフレーム。reset_indexはインデックスを通常の列に移動し、マージ操作によってマージの後にaの行が複製/削除されたときにset_indexがこの列から移動します。
Wouter Overmeire 2012

1
@Wouter左側のマージがデフォルトで再インデックスされる理由を知りたいです。詳細はどこで確認できますか?
Matthew

7
いいね!インデックス名を明示的に指定しないようにするには、を使用しますa.reset_index().merge(b, how="left").set_index(a.index.names)
トゥルル

3
Pandasは、APIが再びストライキを起こすとは考えていませんでした。
ヘンリーヘンリンソン

7

左側のデータフレームにインデックスのコピーを作成し、マージすることができます。

a['copy_index'] = a.index
a.merge(b, how='left')

この単純な方法は、大規模なデータフレームを操作してpd.merge_asof()(またはdd.merge_asof())を使用しているときに非常に役立つことがわかりました。

このアプローチは、インデックスのリセットにコストがかかる場合(データフレームが大きい場合)に優れています。


1
これが最良の答えです。マージ中に古いインデックスを保持したい理由はたくさんあります(受け入れられた回答はインデックスを保持せず、リセットするだけです)。3つ以上のデータフレームをマージしようとしている場合などに役立ちます...
Marses

2
(元の)インデックス名を保持する優れたソリューション
Martien Lubberink

賛成ですが、警告に注意してください。マルチインデックスを使用すると、インデックスはタプルとしてa [copy_index]という単一の列に格納されます
geekidharsh

6

非pd.mergeソリューションがあります。使用するmapと、set_index

In [1744]: a.assign(col2=a['to_merge_on'].map(b.set_index('to_merge_on')['col2']))
Out[1744]:
   col1  to_merge_on  col2
a     1            1   1.0
b     2            3   2.0
c     3            4   NaN

また、indexインデックスにダミーの名前を付けません。


1
これは、マルチインデックスのようなエッジケースでおそらくよりうまく機能するため、受け入れられた回答よりも優れているようです。誰もがこれについてコメントできますか?
BallpointBen

1
質問、複数の列を割り当てる必要がある場合、このアプローチは機能しますか、それとも1つのフィールドのみに制限されますか?
ユカ

@Yuca:複数の列をサブセット化すると最終的にa pd.Dataframeではなくaになるため、これは複数の列では機能しない可能性がありますpd.Series.map()この方法は、唯一のために定義されますpd.Series。これは、次のことを意味しますa[['to_merge_on_1', 'to_merge_on_2']].map(...)。機能しません。
Dataman

4
df1 = df1.merge(
        df2, how="inner", left_index=True, right_index=True
    )

これにより、df1のインデックスを保持できます。


動作するようですが、で使用するとon=list_of_cols]、ドキュメントと矛盾しますIf joining columns on columns, the DataFrame indexes *will be ignored*。インデックスと列のどちらを使用するのが優先されますか?
Itamar Katz

0

別の解決策を考え出したと思います。左のテーブルのインデックスに基づいて、左のテーブルをインデックス値で結合し、右のテーブルを列値で結合していました。私がしたことは通常のマージでした:

First10ReviewsJoined = pd.merge(First10Reviews, df, left_index=True, right_on='Line Number')

次に、マージされたテーブルから新しいインデックス番号を取得し、それらをSentiment Line Numberという名前の新しい列に入れました。

First10ReviewsJoined['Sentiment Line Number']= First10ReviewsJoined.index.tolist()

次に、Line Numberという名前の既存の列(左のテーブルインデックスから結合した列の値)に基づいて、インデックスを手動で元の左のテーブルインデックスに戻しました。

First10ReviewsJoined.set_index('Line Number', inplace=True)

次に、Line Numberのインデックス名を削除して、空白のままにします。

First10ReviewsJoined.index.name = None

少しハックかもしれませんが、うまく機能し、比較的単純なようです。また、データの重複や混乱のリスクが減ると思います。うまくいけば、すべてが理にかなっています。


0

別の簡単なオプションは、インデックスの名前を以前の名前に変更することです。

a.merge(b, how="left").set_axis(a.index)

マージはデータフレーム「a」での順序を維持しますが、インデックスをリセットするだけなので、set_axisを使用するために保存されます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.