我试图在两个数据帧之间进行简单的合并。它们来自两个不同的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
转换为整数只是因为它可以,即使它应该在匹配时被视为字符串。
(我尝试使用示例数据框复制此内容,但对于小示例,我不会看到此行为。有关如何找到更具描述性的示例的任何建议也将受到赞赏。)
答案 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")