使用熊猫合并时如何保持索引


126

我想合并两个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
如果在特定列上合并,则不清楚要使用哪些索引(如果它们都不同)。
no黑猩猩

Answers:


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(二,如何=“左”)set_index(a.index)也适用,但似乎不太可靠(因为它的第一部分丢失索引值到之前对它们进行复位。)
DanB

11
对于这种特殊情况,它们是等效的。但是对于许多合并操作,结果帧的行数与原始a帧的行数不同。合并后,reset_index将索引移至常规列,并从该列将set_index移至该列,当由于合并操作而复制/删除了a的行时,也要小心。
Wouter Overmeire 2012年

1
@Wouter我想知道为什么默认情况下左合并会重新索引。在哪里可以了解更多?
马修

7
真好!为了避免显式指定索引名,我使用a.reset_index().merge(b, how="left").set_index(a.index.names)
Truls

3
熊猫严重地认为API会再次出现。
亨利·亨林森

7

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

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

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

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


1
这是最好的答案。有许多原因使您想要在合并期间保留旧索引(并且可接受的答案不会保留索引,只会重置它们)。当您尝试合并两个以上的数据

2
出色的解决方案,因为它保留了(原始)索引名称
Martien Lubberink

赞成,但请注意,使用多索引时,您的索引将作为元组存储在称为a [copy_index]的单个列中
geekidharsh

6

有一个非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

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


1
这似乎优于已接受的答案,因为它可能会在诸如多索引的边缘情况下更好地工作。有人可以对此发表评论吗?
BallpointBen19年

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')

然后,我从合并表中检索了新的索引号,并将它们放在名为“情感行号”的新列中:

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

然后,我基于称为行号(我从左表索引加入的列值)的现有列,将索引手动设置回原始的左表索引:

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

然后删除行号的索引名称,使其保持空白:

First10ReviewsJoined.index.name = None

也许有点破解,但似乎运行良好且相对简单。另外,猜测它会减少重复/混乱数据的风险。希望一切都有意义。


0

另一个简单的选择是将索引重命名为之前的名称:

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

合并保留数据帧“ a”的顺序,但只是重置索引,因此可以保存以使用set_axis

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.