使用pandas merge时如何保持索引

Dan*_*anB 105 python pandas

我想合并两个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')
Run Code Online (Sandbox Code Playgroud)

编辑:切换到可以轻松复制的示例代码

Wou*_*ire 135

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
Run Code Online (Sandbox Code Playgroud)

注意:对于某些左合并操作,如果在a和之间存在多个匹配,则最终可能会有更多行.b您需要进行重复数据删除(重复数据删除文档).这就是为什么pandas不会保留索引的原因.

  • 对于这种特殊情况,这些是等价的.但是对于许多合并操作,结果帧的行数与原始"a"帧的行数不同.在由于合并操作而复制/删除a的行时,reset_index将索引移动到常规列并且从该列移动set_index. (9认同)
  • 太好了!为了避免显式指定索引名,我使用`a.reset_index().merge(b,how ="left").set_index(a.index.names)`. (5认同)
  • 非常聪明.a.merge(b,how ="left").set_index(a.index)也可以工作,但看起来不那么健壮(因为它的第一部分在重置之前就失去了索引值.) (4认同)
  • @Wouter 我很想知道为什么默认情况下左合并会重新索引。我在哪里可以学到更多? (2认同)
  • 熊猫严重地认为API会再次出现。 (2认同)
  • 我仍然认为 pandas 应该为你保留索引(或者至少给你选择的选项)。还有许多其他“默认”情况,其中索引会重复;例如,在 pd.concat 期间。我认为目前的工作不是最佳的。 (2认同)

Mat*_*Son 14

您可以在左侧数据帧上复制索引并进行合并。

a['copy_index'] = a.index
a.merge(b, how='left')
Run Code Online (Sandbox Code Playgroud)

我发现这个简单的方法在处理大型数据帧和使用pd.merge_asof()(或dd.merge_asof())时非常有用。

当重置索引很昂贵(大数据帧)时,这种方法会更好。

  • 这只是“reset_index()”解决方案的一个不太优雅的版本。@MartienLubberink 是不正确的,因为 `reset_index()` 默认将索引存储为列。 (3认同)
  • 这是最好的答案。您希望在合并期间保留旧索引的原因有很多(并且接受的答案不保留索引,它只是重置它们)。当您尝试合并 2 个以上的数据帧等时它会有所帮助...... (2认同)
  • 卓越的解决方案,因为它保留了(原始)索引名称 (2认同)
  • 已投票,但请注意一个警告,当使用多索引时,您的索引将作为元组存储在名为 [copy_index] 的单个列中 (2认同)

Sup*_*dar 7

df1 = df1.merge(df2, how="inner", left_index=True, right_index=True)
Run Code Online (Sandbox Code Playgroud)

这允许保留 df1 的索引

  • @Supratik Majumdar 您的建议是否假设数据帧的索引已经匹配?OP 具有不匹配的索引,并且正在对列进行合并/连接。 (7认同)

Zer*_*ero 5

有一个非pd.merge解决方案。使用mapset_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
Run Code Online (Sandbox Code Playgroud)

并且,不要index为索引引入虚拟名称。

  • 这似乎优于公认的答案,因为它可能会更好地处理多索引等边缘情况。任何人都可以对此发表评论吗? (2认同)
  • 问题,如果您需要分配多个列,这种方法会起作用还是仅限于 1 个字段? (2认同)
  • @Yuca:这可能不适用于多个列,因为当您对多个列进行子集化时,您最终会得到“pd.Dataframe”而不是“pd.Series”。`.map()` 方法仅为 `pd.Series` 定义。这意味着: `a[['to_merge_on_1', 'to_merge_on_2']].map(...)` 不起作用。 (2认同)

小智 5

您也可以使用DataFrame.join()方法来实现相同的目标。该join方法将保留原始索引。可以使用参数指定要连接的列on

In [17]: a.join(b.set_index("to_merge_on"), on="to_merge_on")
Out[17]: 
   col1  to_merge_on  col2
a     1            1   1.0
b     2            3   2.0
c     3            4   NaN
Run Code Online (Sandbox Code Playgroud)