请在底部找到本问题的摘要和实际完整数据。
我试图用多对一的关系合并两个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不重复。在两个数据帧上的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)
导入/转换回数据帧。在
目前没有回答
相关问题 更多 >
编程相关推荐