pandas - 在字符串列上合并不起作用(bug?)

时间:2016-09-19 22:23:31

标签: python mysql pandas merge

我试图在两个数据帧之间进行简单的合并。它们来自两个不同的SQL表,其中连接键是字符串:

>>> df1.col1.dtype
dtype('O')
>>> df2.col2.dtype
dtype('O')

我尝试使用它合并它们:

>>> merge_res = pd.merge(df1, df2, left_on='col1', right_on='col2')

内连接的结果为空,这首先提示我交叉点中可能没有任何条目:

>>> merge_res.shape
(0, 19)

但是当我尝试匹配单个元素时,我发现这真的很奇怪。

# Pick random element in second dataframe
>>> df2.iloc[5,:].col2
'95498208100000'

# Manually look for it in the first dataframe
>>> df1[df1.col1 == '95498208100000']
0 rows × 19 columns
# Empty, which makes sense given the above merge result

# Now look for the same value as an integer
>>> df1[df1.col1 == 95498208100000]
1 rows × 19 columns
# FINDS THE ELEMENT!?!

因此,列是使用'对象'来定义的。 D型。将它们搜索为字符串不会产生任何结果。将它们作为整数搜索确实会返回一个结果,我认为这就是合并无法在上面工作的原因。

任何想法会发生什么?

这几乎就像Pandas将df1.col1转换为整数只是因为它可以,即使它应该在匹配时被视为字符串。

(我尝试使用示例数据框复制此内容,但对于小示例,我不会看到此行为。有关如何找到更具描述性的示例的任何建议也将受到赞赏。)

6 个答案:

答案 0 :(得分:18)

问题是object dtype具有误导性。我认为这意味着所有项目都是字符串。但显然,在阅读文件时,pandas会将一些元素转换为int,并将剩余部分保留为字符串。

解决方案是确保每个字段都是一个字符串:

>>> df1.col1 = df1.col1.astype(str)
>>> df2.col2 = df2.col2.astype(str)

然后合并按预期工作。

(我希望有一种指定dtype str的方法......)

答案 1 :(得分:7)

我遇到了df.col = df.col.astype(str)解决方案不起作用的情况。原来问题在于编码。

我的原始数据如下所示:

In [72]: df1['col1'][:3]
Out[73]: 
             col1
0  dustin pedroia
1  kevin youkilis
2     david ortiz

In [72]: df2['col2'][:3]
Out[73]: 
             col2
0  dustin pedroia
1  kevin youkilis
2     david ortiz

使用.astype(str)后,合并仍然没有工作,所以我执行了以下操作:

df1.col1 = df1.col1.str.encode('utf-8')
df2.col2 = df2.col2.str.encode('utf-8')

并且能够找到差异:

In [95]: df1
Out[95]: 
                       col1
0  b'dustin\xc2\xa0pedroia'
1  b'kevin\xc2\xa0youkilis'
2     b'david\xc2\xa0ortiz'

In [95]: df2
Out[95]: 
                col2
0  b'dustin pedroia'
1  b'kevin youkilis'
2     b'david ortiz'

此时我所要做的就是在解码的df1.col1变量上运行df1.col1 = df1.col1.str.replace('\xa0',' ')(即在运行.str.encode('utf-8')之前)并且合并完美。

注意:无论我更换的是什么,我总是使用.str.encode('utf-8')来检查它是否有效。

<强>替代地

在Spyder IDE中为Anaconda使用正则表达式和变量资源管理器,我发现了以下区别。

import re
#places the raw string into a list
df1.col1 = df1.col1.apply(lambda x: re.findall(x, x))  
df2.col2 = df2.col2.apply(lambda x: re.findall(x, x))

我的df1数据变成了这个(从Spyder复制并粘贴):

['dustin\xa0pedroia']
['kevin\xa0youkilis']
['david\xa0ortiz']

只是略有不同的解决方案。我不知道在什么情况下第一个例子不会起作用,第二个例子会起作用但是我想提供两个以防万一有人碰到它:)

答案 2 :(得分:2)

谢谢@seeiespi,.. str.encode('utf-8')帮助我弄清楚了需要删除我的字符串,如下所示

20                 b'Belize '   ...     0,612
21                  b'Benin '   ...     0,546

解决方案是使用试纸

df1.col1 = df1.col1.str.strip()
df1.col1 = df1.col1.str.strip()

答案 3 :(得分:1)

这个答案为我解决了:

pd.merge(df1.assign(x=df1.x.astype(str)), 
         df2.assign(x=df2.x.astype(str)), 
         how='left', on='x')

来自Pandas merge issue on key of object type containing number and string values

答案 4 :(得分:0)

以上所有解决方案都不适合我,因为合并实际上已正确完成,但索引搞乱了。删除索引可以为我解决:

df['sth'] = df.merge(df2, how='left', on=['x', 'y'])['sth'].values

答案 5 :(得分:0)

可能您的列有一些差异或导致此错误的空格。

首先检查您的列类型,以及项目之间是否有任何不同

<input checked={isOrdered} type="checkbox"/> Ordered

如果它们有任何不同,您可以使用

df1.col1 = df1.col1.str.encode('utf-8')
df2.col2 = df2.col2.str.encode('utf-8')

或者如果有任何空格

df1.col1 = df1.col1.str.replace("this", "for that")