2 series/columns 个不同长度之间的模糊查找
fuzzy lookup between 2 series/columns of nonidentical lengths
我正在尝试在 df1 和 df2 之间的 2 series/columns 之间进行模糊查找,其中 df1 是字典文件(用作基础),df2 是目标文件(要查找的)
import pandas as pd
df1 = pd.DataFrame(data ={'Brand_var':['Altmeister Bitter','Altos Las Hormigas Argentinian Wine','Amadeus Contri Sparkling Wine','Amadeus Cream Liqueur','Amadeus Sparkling Sparkling Wine']})
df2 = pd.DataFrame(data = {'Product':['1960 Altmeister 330ML CAN METAL','Hormi 12 Yr Bottle','test']})
我在 SO 中查找了一些解决方案,不幸的是似乎没有找到解决方案。
已用:
df3 = df2['ProductLongDesc'].apply(lambda x: difflib.get_close_matches(x, df1['Brand_var'])[0])
还有:
df3 = df2['Product'].apply(lambda x: difflib.get_close_matches(x, df1['Brand_var']))
第一个给我一个索引错误,第二个只给我索引。
我想要的输出是使用模糊查找打印 df1 项和 df2 项之间的映射,并打印 Brand_var 和 Product 以进行各自的匹配。
期望的输出:
Brand_var Product
Altmeister Bitter 1960 Altmeister 330ML CAN METAL
Altos Las Hormigas Argentinian Wine Hormi 12 Yr Bottle
对于df2中的不匹配项ex:test,可以忽略。
注意:匹配的字符串名称也可以不完全相同,因为其中可能会缺少 1 或 2 个字母。 :(
提前感谢您抽出宝贵时间解决此问题。 :)
如果您安装 fuzzywuzzy
,您仍然会遇到一个问题,即如何选择适当的启发式 select 正确的产品并删除那些 select 编辑不正确的产品(下面的解释)
安装fuzzywuzzy
:
pip install fuzzywuzzy
fuzzywuzzy
有几种比率计算方法 (examples on github)。你面临的问题:如何选择最好的?我在你的数据上试过了,但都失败了。
代码:
import pandas as pd
import numpy as np
from fuzzywuzzy import fuzz
# df1 = ...
# df2 = ...
def get_top_by_ratio(x, df2):
product_values = df2.Product.values
# compare two strings by characters
ratio = np.array([fuzz.partial_ratio(x, val) for val in product_values])
argmax = np.argmax(ratio)
rating = ratio[argmax]
linked_product = product_values[argmax]
return rating, linked_product
将此函数应用于您的数据:
partial_ratio = (df1.Brand_var.apply(lambda x: get_top_by_ratio(x, df2))
.apply(pd.Series) # convert returned Series of tuples into pd.DataFrame
.rename(columns={0: 'ratio', 1: 'Product'})) # just rename columns
print(partial_ratio)
Out:
0 65 1960 Altmeister 330ML CAN METAL # Altmeister Bitter
1 50 test # Altos Las Hormigas Argentinian Wine
2 33 test
3 50 test
4 50 test
这样不好。 fuzz.ratio
、fuzz.token_sort_ratio
等其他比率方法也失败了。
所以我想扩展启发式来比较单词,而不仅仅是字符可能有帮助。定义一个函数,它将根据您的数据创建词汇表,对所有句子进行编码,并使用更复杂的启发式查找单词:
def create_vocab(df1, df2):
# Leave 0 index free for unknow words
all_words = set((df1.Brand_var.str.cat(sep=' ') + df2.Product.str.cat(sep=' ')).split())
vocab = dict([(i + 1, w) for i, w in enumerate(all_words)])
return vocab
def encode(string, vocab):
"""This function encodes a sting with vocabulary"""
return [vocab[w] if w in vocab else 0 for w in string.split()]
定义新启发式:
def get_top_with_heuristic(x, df2, vocab):
product_values = df2.Product.values
# compare two strings by characters
ratio_per_char = np.array([fuzz.partial_ratio(x, val) for val in product_values])
# compare two string by words
ratio_per_word = np.array([fuzz.partial_ratio(x, encode(val, vocab)) for val in product_values])
ratio = ratio_per_char + ratio_per_word
argmax = np.argmax(ratio)
rating = ratio[argmax]
linked_product = product_values[argmax]
return rating, linked_product
创建词汇表,对数据应用复杂的启发式方法:
vocab = create_vocab(df1, df2)
heuristic_rating = (df1.Brand_var.apply(lambda x: get_top_with_heuristic(x, df2, vocab))
.apply(pd.Series)
.rename(columns={0: 'ratio', 1: 'Product'}))
print(heuristic_rating)
Out:
ratio Product
0 73 1960 Altmeister 330ML CAN METAL # Altmeister Bitter
1 61 Hormi 12 Yr Bottle # Altos Las Hormigas Argentinian Wine
2 45 Hormi 12 Yr Bottle
3 50 test
4 50 test
看来是对的!将此数据帧连接到 df1,更改索引:
result_heuristic = pd.concat((df1, heuristic_rating), axis=1).set_index('Brand_var')
print(result_heuristic)
Out:
ratio Product
Brand_var
Altmeister Bitter 73 1960 Altmeister 330ML CAN METAL
Altos Las Hormigas Argentinian Wine 61 Hormi 12 Yr Bottle
Amadeus Contri Sparkling Wine 45 Hormi 12 Yr Bottle
Amadeus Cream Liqueur 50 test
Amadeus Sparkling Sparkling Wine 50 test
现在您应该选择一些经验法则来删除不正确的数据。对于此示例,ratio <= 50
效果很好,但您可能 需要一些研究来定义最佳启发式和正确阈值 。无论如何你也会得到一些错误。选择可接受的错误率,即 2%、5% ... 并改进您的算法直到达到它(此任务类似于机器学习分类算法的验证)。
剪错了"predictions":
result = result_heuristic[result_heuristic.ratio > 50][['Product']]
print(result)
Out: Product
Brand_var
Altmeister Bitter 1960 Altmeister 330ML CAN METAL
Altos Las Hormigas Argentinian Wine Hormi 12 Yr Bottle
希望对您有所帮助!
P.S. 当然,这个算法非常非常慢,当你'优化'它时你应该做一些优化,例如缓存差异等.
我正在尝试在 df1 和 df2 之间的 2 series/columns 之间进行模糊查找,其中 df1 是字典文件(用作基础),df2 是目标文件(要查找的)
import pandas as pd
df1 = pd.DataFrame(data ={'Brand_var':['Altmeister Bitter','Altos Las Hormigas Argentinian Wine','Amadeus Contri Sparkling Wine','Amadeus Cream Liqueur','Amadeus Sparkling Sparkling Wine']})
df2 = pd.DataFrame(data = {'Product':['1960 Altmeister 330ML CAN METAL','Hormi 12 Yr Bottle','test']})
我在 SO 中查找了一些解决方案,不幸的是似乎没有找到解决方案。
已用:
df3 = df2['ProductLongDesc'].apply(lambda x: difflib.get_close_matches(x, df1['Brand_var'])[0])
还有:
df3 = df2['Product'].apply(lambda x: difflib.get_close_matches(x, df1['Brand_var']))
第一个给我一个索引错误,第二个只给我索引。
我想要的输出是使用模糊查找打印 df1 项和 df2 项之间的映射,并打印 Brand_var 和 Product 以进行各自的匹配。
期望的输出:
Brand_var Product
Altmeister Bitter 1960 Altmeister 330ML CAN METAL
Altos Las Hormigas Argentinian Wine Hormi 12 Yr Bottle
对于df2中的不匹配项ex:test,可以忽略。
注意:匹配的字符串名称也可以不完全相同,因为其中可能会缺少 1 或 2 个字母。 :(
提前感谢您抽出宝贵时间解决此问题。 :)
如果您安装 fuzzywuzzy
,您仍然会遇到一个问题,即如何选择适当的启发式 select 正确的产品并删除那些 select 编辑不正确的产品(下面的解释)
安装fuzzywuzzy
:
pip install fuzzywuzzy
fuzzywuzzy
有几种比率计算方法 (examples on github)。你面临的问题:如何选择最好的?我在你的数据上试过了,但都失败了。
代码:
import pandas as pd
import numpy as np
from fuzzywuzzy import fuzz
# df1 = ...
# df2 = ...
def get_top_by_ratio(x, df2):
product_values = df2.Product.values
# compare two strings by characters
ratio = np.array([fuzz.partial_ratio(x, val) for val in product_values])
argmax = np.argmax(ratio)
rating = ratio[argmax]
linked_product = product_values[argmax]
return rating, linked_product
将此函数应用于您的数据:
partial_ratio = (df1.Brand_var.apply(lambda x: get_top_by_ratio(x, df2))
.apply(pd.Series) # convert returned Series of tuples into pd.DataFrame
.rename(columns={0: 'ratio', 1: 'Product'})) # just rename columns
print(partial_ratio)
Out:
0 65 1960 Altmeister 330ML CAN METAL # Altmeister Bitter
1 50 test # Altos Las Hormigas Argentinian Wine
2 33 test
3 50 test
4 50 test
这样不好。 fuzz.ratio
、fuzz.token_sort_ratio
等其他比率方法也失败了。
所以我想扩展启发式来比较单词,而不仅仅是字符可能有帮助。定义一个函数,它将根据您的数据创建词汇表,对所有句子进行编码,并使用更复杂的启发式查找单词:
def create_vocab(df1, df2):
# Leave 0 index free for unknow words
all_words = set((df1.Brand_var.str.cat(sep=' ') + df2.Product.str.cat(sep=' ')).split())
vocab = dict([(i + 1, w) for i, w in enumerate(all_words)])
return vocab
def encode(string, vocab):
"""This function encodes a sting with vocabulary"""
return [vocab[w] if w in vocab else 0 for w in string.split()]
定义新启发式:
def get_top_with_heuristic(x, df2, vocab):
product_values = df2.Product.values
# compare two strings by characters
ratio_per_char = np.array([fuzz.partial_ratio(x, val) for val in product_values])
# compare two string by words
ratio_per_word = np.array([fuzz.partial_ratio(x, encode(val, vocab)) for val in product_values])
ratio = ratio_per_char + ratio_per_word
argmax = np.argmax(ratio)
rating = ratio[argmax]
linked_product = product_values[argmax]
return rating, linked_product
创建词汇表,对数据应用复杂的启发式方法:
vocab = create_vocab(df1, df2)
heuristic_rating = (df1.Brand_var.apply(lambda x: get_top_with_heuristic(x, df2, vocab))
.apply(pd.Series)
.rename(columns={0: 'ratio', 1: 'Product'}))
print(heuristic_rating)
Out:
ratio Product
0 73 1960 Altmeister 330ML CAN METAL # Altmeister Bitter
1 61 Hormi 12 Yr Bottle # Altos Las Hormigas Argentinian Wine
2 45 Hormi 12 Yr Bottle
3 50 test
4 50 test
看来是对的!将此数据帧连接到 df1,更改索引:
result_heuristic = pd.concat((df1, heuristic_rating), axis=1).set_index('Brand_var')
print(result_heuristic)
Out:
ratio Product
Brand_var
Altmeister Bitter 73 1960 Altmeister 330ML CAN METAL
Altos Las Hormigas Argentinian Wine 61 Hormi 12 Yr Bottle
Amadeus Contri Sparkling Wine 45 Hormi 12 Yr Bottle
Amadeus Cream Liqueur 50 test
Amadeus Sparkling Sparkling Wine 50 test
现在您应该选择一些经验法则来删除不正确的数据。对于此示例,ratio <= 50
效果很好,但您可能 需要一些研究来定义最佳启发式和正确阈值 。无论如何你也会得到一些错误。选择可接受的错误率,即 2%、5% ... 并改进您的算法直到达到它(此任务类似于机器学习分类算法的验证)。
剪错了"predictions":
result = result_heuristic[result_heuristic.ratio > 50][['Product']]
print(result)
Out: Product
Brand_var
Altmeister Bitter 1960 Altmeister 330ML CAN METAL
Altos Las Hormigas Argentinian Wine Hormi 12 Yr Bottle
希望对您有所帮助!
P.S. 当然,这个算法非常非常慢,当你'优化'它时你应该做一些优化,例如缓存差异等.