pandas - 合并字符串列不起作用(错误?)
Posted
技术标签:
【中文标题】pandas - 合并字符串列不起作用(错误?)【英文标题】:pandas - Merging on string columns not working (bug?) 【发布时间】:2017-01-27 17:20:26 【问题描述】:我正在尝试在两个数据框之间进行简单的合并。它们来自两个不同的 SQL 表,其中连接键是字符串:
>>> df1.col1.dtype
dtype('O')
>>> df2.col2.dtype
dtype('O')
我尝试使用以下方法合并它们:
>>> merge_res = pd.merge(df1, df2, left_on='col1', right_on='col2')
inner join的结果是空的,首先提示我交集可能没有任何条目:
>>> 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!?!
因此,列是使用“对象”dtype 定义的。将它们作为字符串搜索不会产生任何结果。将它们作为整数搜索确实会返回结果,我认为这就是合并在上面不起作用的原因..
有什么想法吗?
这几乎就像认为 Pandas 将 df1.col1
转换为整数只是因为它可以,即使它应该在匹配时被视为字符串。
(我尝试使用示例数据框复制此内容,但对于小示例,我没有看到这种行为。任何关于如何找到更具描述性示例的建议也将不胜感激。)
【问题讨论】:
看起来你的列中混合了 dtypes,我建议首先尝试将所有值强制为数字所以df1['col1'] = df1['col1'].astype(int)
这可能会失败,这意味着你有一些 str 值不能表示为 int,所以接下来尝试df1['col1'] = pd.to_numeric(df1['col1'], errors='coerce')
,它将强制将 duff 值设置为NaN
,它可以
啊,谢谢@EdChum!一些值可以转换为int
,但其他值不能。因此,该列的正确 dtype 应该是 str
,但由于这不是正确的 dtype,我认为 object
会起作用。但是当我手动将所有内容转换为str
时,合并确实有效。谢谢!
你能否发布一个答案,然后在几天后接受你自己的答案,这样这个问题就不会没有答案了,谢谢
【参考方案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
【讨论】:
【参考方案2】:您的列可能存在一些差异或导致此错误的空格。
首先检查您的列类型以及项目之间是否有任何不同
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")
如果有空格
df1.col1 = df1.col1.apply(str).str.strip()
# This apply(str) is being used because without it, the program returns an error related to being enable to convert from byte.
【讨论】:
【参考方案3】:上述解决方案都不适合我,因为合并实际上已正确完成,但索引却搞砸了。删除索引为我解决了它:
df['sth'] = df.merge(df2, how='left', on=['x', 'y'])['sth'].values
【讨论】:
哇,这出乎意料。谢谢,这个答案对我帮助很大;合并两个字符串列,其中一个是唯一的。 pd.merge 有它的怪癖。【参考方案4】:谢谢,@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()
【讨论】:
【参考方案5】:我遇到了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 for 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']
这只是一个稍微不同的解决方案。我不知道在什么情况下第一个示例不起作用,第二个示例不起作用,但我想提供两者以防万一有人遇到它:)
【讨论】:
非常有帮助!有同样的问题,结果是编码,我没想到!谢谢! 谢谢,这是 \xa0 问题,因为我的案例使用 beautifulsoup 进行网络抓取。更换它解决了问题【参考方案6】:问题在于 object
dtype 具有误导性。我认为这意味着所有项目都是字符串。但显然,在读取文件时,pandas 正在将一些元素转换为整数,并将其余元素保留为字符串。
解决方案是确保每个字段都是字符串:
>>> df1.col1 = df1.col1.astype(str)
>>> df2.col2 = df2.col2.astype(str)
然后合并按预期工作。
(我希望有一种方法可以指定 dtype
的 str
...)
【讨论】:
很奇怪。你的解决方案奏效了。但是在之前和之后,有问题的变量的 dtype 都是“O”。我想,就像你提到的那样,这些对象类型还有更多内容。希望它更透明。 上帝保佑你这个好人!你节省了我抓头的时间! 当您在 excel 中为此类列应用 vlookup 时,也会发生同样的情况。我在快速查找时得到了错误的结果,所以求助于 pandas 但在那里得到了相同的输出(nan)。以上是关于pandas - 合并字符串列不起作用(错误?)的主要内容,如果未能解决你的问题,请参考以下文章
从 pandas DataFrame 中的多个字符串列中删除子字符串