合并Pandas数据帧(左连接样式)会产生奇怪的结果

2024-07-05 11:25:13 发布

您现在位置:Python中文网/ 问答频道 /正文

请在底部找到本问题的摘要和实际完整数据。

我试图用多对一的关系合并两个Pandas数据帧。 这通常是一个使用LEFT联接的非常简单的类似SQL的过程,但是我得到了一个相当意外的结果。在

一个数据框包含药物名称及其成分的列表(左侧)以及一些额外信息(不相关的ID和生产药物的公司),另一个数据框包含成分列表及其数字标识(右侧)。在

显然,我喜欢得到的是一个合并的数据框,其中每种成分的ID都列在成分名称旁边,考虑到这是一个多对一的情况,有些ID会在某些药物使用相同成分时重复出现。在

两个数据帧的人工示例(为简洁起见,省略索引):

药物(df1):

someid  name       ingredient               company
1       Antivert   meclizine hydrochloride  Drug and Co
2       Antivert   meclizine hydrochloride  Pharma Inc
3       Antivert   meclizine hydrochloride  Medicine Limited
4       Antizol    fomepizole               Drug and Co
5       Antizol    fomepizole               Medicine Limited
6       Anzeme     toxyphenonium bromide    Pharma Inc 
7       Anzemet    toxyphenonium bromide    Drug and Co
...        ...
[51397 rows x 4 columns]

成分(df2):

^{pr2}$

要进行合并,我只需执行以下操作:

df1.merge(df2, on='ingredient', how='left')

预期的输出为:

someid  name       ingredient               company           id
1       Antivert   meclizine hydrochloride  Drug and Co       1
2       Antivert   meclizine hydrochloride  Pharma Inc        1
3       Antivert   meclizine hydrochloride  Medicine Limited  1
4       Antizol    fomepizole               Drug and Co       2
5       Antizol    fomepizole               Medicine Limited  2
6       Anzeme     toxyphenonium bromide    Pharma Inc        3
7       Anzemet    toxyphenonium bromide    Drug and Co       3
...        ...
[51397 rows x 5 columns]

但是,实际输出是:

someid  name       ingredient               company           id
1       Antivert   meclizine hydrochloride  Drug and Co       1
2       Antivert   meclizine hydrochloride  Pharma Inc        2
3       Antivert   meclizine hydrochloride  Medicine Limited  3
4       Antizol    fomepizole               Drug and Co       4
5       Antizol    fomepizole               Medicine Limited  5
6       Anzeme     toxyphenonium bromide    Pharma Inc        6
7       Anzemet    toxyphenonium bromide    Drug and Co       7
...        ...
[3354 rows x 5 columns]

这里有两件重要的事要注意:

  • id列只是向上计数,id不重复。在
  • 行的数量现在限制为配料(df2)数据帧(3354)中的行数。在

两个数据帧上的info()显示了两个ingredient列的类型相同(只是为了排除比较问题):

药物(df1):

<class 'pandas.core.frame.DataFrame'>
Int64Index: 51397 entries, 0 to 51396
Data columns (total 4 columns):
someid        51397 non-null int64
name          51397 non-null object
ingredient    51397 non-null object
company       51397 non-null object
dtypes: int64(1), object(3)
memory usage: 1.2+ MB
None

成分(df2):

<class 'pandas.core.frame.DataFrame'>
Int64Index: 3354 entries, 0 to 3353
Data columns (total 2 columns):
id            3354 non-null int64
ingredient    3354 non-null object
dtypes: int64(1), object(1)
memory usage: 78.6+ KB
None

现在是有趣的部分。为了找出可能出错的地方,我尝试使用head()对两个数据帧的一个子集进行合并:

df1 = df1.head(100)
df2 = df2.head(100)

如果我再执行合并,我就可以毫无问题地得到所需的输出,只有100行。如果我继续增加head()的行数,即使它远远超过当前的行数,输出仍然是完美的。例如,这种方法非常有效:

df1 = df1.head(100000)
df2 = df2.head(100000)

注意,我包括了前100.000行(在df1中只有53.000行)。这也会给我预期的合并输出。在

有趣的一点:在使用head(100000)包含大量行之后,只有药物数据帧(df1)的信息会稍微改变:

<class 'pandas.core.frame.DataFrame'>
Int64Index: 51397 entries, 0 to 51396
Data columns (total 4 columns):
someid        51397 non-null int64
name          51397 non-null object
ingredient    51397 non-null object
company       51397 non-null object
dtypes: int64(1), object(3)
memory usage: 2.0+ MB
None

请注意,内存使用量从1.2 MB增加到2.0 MB。但除此之外,它们仍然是数据帧对象,其结构与我将它们拉过该操作之前相同。在

这可能是怎么回事?为什么合并会产生如此奇怪的结果,除非我先将数据帧拉过head()?在


总结一下:如果不使用head()merge()输出显示的是减少的行(#行=#右边的行),并且每个成分ID只是以串行方式“粘贴”在那里。但是,如果我确实使用head(),即使有足够大的数量来包含两边的所有行,连接也会按预期工作。在

Python版本:2.7.10-Pandas版本:0.17.1-NumPy版本:1.10.1


完整数据:对于那些想要尝试完全相同数据的人,我在Github上创建了两个gist,其中包含了上述药物和成分数据框的完整数据(字典形式)。在

它们使用DataFrame.to_dict()导出,并可以使用DataFrame.from_dict(data)导入/转换回数据帧。在


Tags: columnsand数据objectnullheaddf1成分