合并Pandas DataFrames(左键连接样式)会产生奇怪的结果

时间:2015-12-09 01:37:08

标签: python pandas

请查看此问题的摘要以及底部的实际完整数据

我正在尝试将两个Pandas DataFrames与多对一关系合并。 这通常是一个使用LEFT连接的类似SQL的过程,但是我得到了一个意想不到的结果。

一个DataFrame包含药物名称及其成分列表(左侧)以及一些额外信息(不相关的ID和制造药物的公司),另一个包含成分列表及其数字ID(右侧) )。

显然,我想得到的是合并的DataFrame,其中每种成分的ID列在成分名称旁边,考虑到这是多对一的情况,一些药物将会重复使用相同的成分。

两个DataFrames的设计示例(为简洁起见省略索引):

药物(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):

ingredient                id
meclizine hydrochloride   1
fomepizole                2
toxyphenonium bromide     3
...                       ...
[3354 rows x 2 columns]

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

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)DataFrame(3354)中的行数。

两个DataFrame上的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()仅对两个DataFrame的子集进行合并:

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)的大量行之后,只有Drugs DataFrame(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。除此之外,它们仍然是DataFrame对象,其结构与我通过该操作之前的结构相同。

这里可能会发生什么?为什么合并会产生如此奇怪的结果,除非我首先通过head()拉出DataFrame?

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

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

完整数据:对于想要尝试完全相同数据的人,我在Github上创建了两个要点,其中包含药物和上面提到的成分DataFrame的完整数据(字典形式)

使用DataFrame.to_dict()导出它们,可以使用DataFrame.from_dict(data)将其导入/转换回DataFrame。

0 个答案:

没有答案