Pandas左外连接结果表大于左表

148 投票
6 回答
128630 浏览
提问于 2025-04-18 00:21

根据我对左外连接的理解,结果表的行数应该不会超过左边的表……如果我说错了,请告诉我……

我的左边表有192572行和8列。

我的右边表有42160行和5列。

我的左边表有一个叫做'id'的字段,它和右边表中的一个叫做'key'的列是匹配的。

所以我这样把它们合并:

combined = pd.merge(a,b,how='left',left_on='id',right_on='key')

但是合并后的结果却有236569行。

我哪里理解错了呢?

6 个回答

0

要解决这个问题,首先在左边的数据表中创建一个唯一的索引列。这样,在你准备好合并后的数据表后,就可以用这个“索引”列来跟踪“重复”的数据。

 1. LEFT_df['INDEX'] = LEFT_df.index + 1
 2. LEFT_df.shape 
 3. Merged_df = pd.merge(LEFT_df , Right_df , how = "left", on = 'Common column')
 4. LEFT_df['INDEX'].duplicated().sum()
 5. Merged_df = Merged_df.drop_duplicates(subset=['INDEX'], keep='first')
 6. Merged_df.shape (will now match with the LEFT_df.shape)
0

可能会有多个条目使用相同的键值。请确保右边的表中没有重复的键。

# One workaround could be remove duplicates from right table w.r.t key.

combined = pd.merge(a.reset_index(),b.drop_duplicates(['key']),how='left',left_on='id',right_on='key')


12

还有一些方法可以避免这种情况,而不需要丢失重复的数据,前提是并不是所有的列都是重复的。如果你有

In [1]: df = pd.DataFrame([[1, 3], [2, 4]], columns=['A', 'B'])

In [2]: df2 = pd.DataFrame([[1, 5], [1, 6]], columns=['A', 'C'])

一种方法是对重复的数据取平均值(也可以取总和等等...)

In [3]: df3 = df2.groupby('A').mean().reset_index()

In [4]: df3
Out[4]: 
     C
A     
1  5.5

In [5]: merged = pd.merge(df,df3,on=['A'], how='outer')

In [6]: merged
Out[204]: 
   A  B    C
0  1  3  5.5
1  2  4  NaN

另外,如果你有一些非数字的数据,不能用pd.to_numeric()转换,或者你就是不想取平均值,你可以通过给重复的数据编号来改变合并的变量。不过,这种方法适用于两个数据集中都有重复的情况(这会导致同样的问题,也是一个常见的问题):

In [7]: df = pd.DataFrame([['a', 3], ['b', 4],['b',0]], columns=['A', 'B'])

In [8]: df2 = pd.DataFrame([['a', 3], ['b', 8],['b',5]], columns=['A', 'C'])

In [9]: df['count'] = df.groupby('A')['B'].cumcount()

In [10]: df['A'] = np.where(df['count']>0,df['A']+df['count'].astype(str),df['A'].astype(str))

In[11]: df
Out[11]: 
    A  B  count
0   a  3      0
1   b  4      0
2  b1  0      1

对df2做同样的操作,去掉df和df2中的计数变量,然后在'A'列上进行合并:

In [16]: merged
Out[16]: 
    A  B  C
0   a  3  3        
1   b  4  8        
2  b1  0  5        

有几点需要注意。在最后这种情况下,我使用了.cumcount()而不是.duplicated(),因为可能会有多个重复的观察值。此外,我使用.astype(str)将计数值转换为字符串,因为我使用了np.where()命令,但使用pd.concat()或其他方法可能会有不同的应用。

最后,如果只有一个数据集中有重复数据,但你仍然想保留它们,那么你可以使用前面提到的策略的一部分来区分合并结果中的重复项。

15

在之前的回答中,还有一个小补充,就是有一个叫做 validate 的参数。如果在右边的表中找到了重复的 ID,这个参数可以用来抛出一个错误。

combined = pd.merge(a,b,how='left',left_on='id',right_on='key', validate = 'm:1')
206

如果在另一个数据表中,某个键对应多于一行数据,你可以预期结果会增加:

In [11]: df = pd.DataFrame([[1, 3], [2, 4]], columns=['A', 'B'])

In [12]: df2 = pd.DataFrame([[1, 5], [1, 6]], columns=['A', 'C'])

In [13]: df.merge(df2, how='left')  # merges on columns A
Out[13]: 
   A  B   C
0  1  3   5
1  1  3   6
2  2  4 NaN

为了避免这种情况,可以在df2中去掉重复的项

In [21]: df2.drop_duplicates(subset=['A'])  # you can use take_last=True
Out[21]: 
   A  C
0  1  5

In [22]: df.merge(df2.drop_duplicates(subset=['A']), how='left')
Out[22]: 
   A  B   C
0  1  3   5
1  2  4 NaN

撰写回答