Emj*_*ora 5 python string matching pandas
我有一个多维的模糊字符串匹配问题:
假设我有一个熊猫数据框,其中包含变量“公司名称”,“股票代码”和“国家/地区”。简化的子集可能看起来像这样:
pd.DataFrame(columns = ["Company name", "Ticker", "Country"],
data = [["Vestas Wind Systems", "VWS.CO", "Denmark"],
["Vestas", "VWS", "Denmark"],
["Vestas Wind", "VWS", np.nan],
["Amazon.com Inc", np.nan, "United States of America"],
["AMAZONIA", "BAZA3 BZ", "Brazil"],
["AMAZON.COM", "AMZN US", "United States"]])
Run Code Online (Sandbox Code Playgroud)
整个数据帧将包含数十万行。
我要确定的是数据框中的公司,它们是相同的。 在这种情况下,意味着确定行0、1、2都是“ Vestas Wind Systems”公司的不同表达方式,行3、5都代表“ Amazon.com Inc”,行4代表“ Amazonia”。
为了增加正确匹配的机会,我认为最好利用所有三列的信息。
但是,所有三列都需要通过模糊逻辑进行比较:公司,股票行情和国家/地区的写法可能不同。例如,“ Vestas风力系统”与“ Vestas”或“美国”与“美国”。
另一个复杂性是,“股票行情”和“国家/地区”列都可能包含NaN值(公司名称绝不能为空)。
问题1:解决此问题的理想方法是什么?
我目前的计划:
我想通过利用三列中的信息来匹配公司。跨列的实体越相似,匹配的可能性就越高。此外,每列的权重应该不同:仅仅因为两家公司都位于美国,并不意味着它们是同一家公司。因此,例如,“国家/地区”列应具有较低的权重。
我目前尝试在每列上使用模糊算法来识别相似的字符串表示形式。这将产生如下结果,其中分数代表字符串相似度:
pd.DataFrame(columns = ["Company name 1", "Company name 2", "Score"],
data = [["vestas wind systems", "vestas wind", 0.9],
["vestas wind", "vestas", 0.85],
["amazon.com inc", "amazon.com", 0.84],
["amazon.com", "amazonia", 0.79],
["vestas wind systems", "vestas", 0.75],
["amazon.com inc", "amazonia", 0.70],
["vestas", "amazonia", 0.4],
["...", "...", "..."]])
Run Code Online (Sandbox Code Playgroud)
pd.DataFrame(columns = ["Ticker 1", "Ticker 2", "Score"],
data = [["vws.co", "vws", 0.8],
["baza3 bz", "amzn us", 0.6],
["vws", "amzn us", 0.4],
["vws.co", "amzn us", 0.35],
["baza3 bz", "vws.co", 0.3],
["baza3 bz", "vws", 0.28]])
Run Code Online (Sandbox Code Playgroud)
pd.DataFrame(columns = ["Country 1", "Country 2", "Score"],
data = [["united states", "united states of america", 0.8],
["brazil", "denmark", 0.3],
["brazil", "united states", 0.28],
["brazil", "united states of america", 0.26],
["denmark", "united states", 0.25],
["denmark", "united states of america", 0.23]])
Run Code Online (Sandbox Code Playgroud)
注意:我意识到我应该在模糊匹配之前通过正则表达式进行一些简单的字符串清理,但是为了简单起见,让我们假设我已经这样做了。同样,我在上述结果中将所有字符串都转换为小写。
所以现在我在不同的列上都有相似度分数。然后,我想使用这些相似性来识别初始数据框的哪些行代表相同的公司。如前所述,我想对列相似性应用不同的权重:假设我要使用以下权重:
weights = {"Company name" : 0.45, "Ticker" : 0.45, "Country" : 0.1}
Run Code Online (Sandbox Code Playgroud)
也就是说,当比较数据框中的任意两行时,它们的相似性得分为
similarity_score = 0.45 * Company Name similarity score + 0.45 * Ticker Name similarity score + 0.1 * Country similarity score
Run Code Online (Sandbox Code Playgroud)
例如,第0行和第1行的相似性得分为:
similarity_score_0_1 = 0.45 * 0.75 + 0.45 * 0.8 + 0.1 * 1.0 = 0.7975
Run Code Online (Sandbox Code Playgroud)
当某些行的股票行情和/或国家/地区值为空时,这当然会成为问题。
最后-当我在数据帧中有数十万行时,计算所有行之间的相似度得分非常耗时。
问题2:如何以最有效的方式完成此任务?
模糊匹配可能不会在这里解决它,因为它本质上是编辑距离搜索,它根据您需要更改的字符数进行匹配,以使第一个字符串等于第二个字符串。这意味着,虽然您可以设置阈值来将“USA”与“United States”匹配,但您会发现这需要进行大量字符更改才能使第一个字符等于第二个字符,因此必须设置阈值非常低。显然这会导致很多其他比赛的质量非常差。
有多种选择,我发现最好(也是最便宜)的一种是使用Dedupe。您可以通过网站使用该应用程序进行“集群”(我认为这是付费的,但有大量免费试用),或者您可以通过 pip 安装它(这种方式比较棘手,但如果您将将此投入生产)。
聚类的工作原理是通过简单的手动过程来训练模型,一遍又一遍地回答“这个与那个匹配吗”,直到您有足够的示例让模型能够推断出哪些字符串彼此相等。然后,它将通过模型运行您的数据集,分配 cluster_id 将所有匹配的字符串分组在一起,然后您可以检查结果。