作者 | Audhi Aprilliant

编译 | VK
来源 | Towards Data Science

在处理真实数据时,最大的问题主要是数据预处理。

匹配可能是许多分析师面临的最大挑战之一。例如,当我们谈论乔治·华盛顿和G·华盛顿时,当然,我们谈论的是一个人,即美国的第一任总统。幸运的是,研究人员已经开发出了概率数据匹配算法或众所周知的模糊匹配。

研究表明,94%的企业承认有重复的数据,而且这些重复的数据大部分是不完全匹配的,因此通常不会被发现

什么是模糊字符串匹配?

概率数据匹配,通常称为模糊字符串匹配,是一种算法或计算技术,用于寻找与模式近似(而不是精确)匹配的某些字符串。

概率数据匹配中的概率明确指示输出必须是概率(在0到1的范围内或相似度的百分比),而不是精确的数字。

有很多方法可以执行模糊字符串匹配,但是随着数据大小的增加,它们的性能会受到很大的影响,例如Levenshtein距离。原因是每个记录都要与数据中的所有其他记录进行比较。

随着数据大小的增加,执行模糊字符串匹配所花费的时间呈二次增长。这种现象被称为二次时间复杂度。二次时间复杂度表示一种算法,其性能与输入数据的平方大小成正比。

随着数据的增长,对速度的需求也在增长。

TF-IDF和KNN如何加速计算时间?

词频-逆文档频率(TF-IDF)是一种自然语言处理(NLP)技术,用于测量文档集合中一个单词对文档的重要性。

例如,从一个文档集合中,单词“flower”有多重要?TF-IDF值与单词出现的次数成比例增加(术语频率),但随着包含该单词的文档数量减少(与文档频率相反)。

IDF部分有助于解释这样一个事实,即某些词通常更常见(例如单词“The”没有任何信息)。

TF-IDF是使用n个字母组来实现的,这些字母组可能是由拼写错误或打字错误引起的。例如,independence这个词被分成以下形式,取决于n的个数。

1-gram
['independence']
2-gram
['in','nd','de','ep','pe','en','nd','de','en','nc','ce']
3-gram
['ind','nde','dep','epe','pen','end','nde','den','enc','nce']

因此,n-gram是从用于字符串匹配的字符串列表中创建的。

TF-IDF背后的思想是,它将文档表示为数据,并且选择用k最近邻和余弦相似度,而不是Levenshtein距离(插入、删除或替换)匹配。

余弦相似度是一种相似性度量,可用于比较文档,或者根据给定的查询词向量给出文档的排序。x和y是两个比较的向量。用余弦度量作为相似函数,我们得到

之后,最匹配的候选数据将与主数据进行比较。它的目的是计算主数据中最匹配的候选字符串之间的相似度。

让我们来练习一下

对于本例,我将通过从Room Type Kaggle数据来演示TF-IDF模糊字符串匹配方法

https://www.kaggle.com/leandrodoze/room-type

老实说,我选择这个数据是因为:(1)数据非常小,只有103行,(2)列表示要比较的混乱字符串和主字符串。在实际情况中,这两种数据(杂乱的和干净的)可能来自不同的来源。

请先运行下面的命令,使用TF-IDF和KNN创建一个模糊字符串匹配函数。

# 导入数据操作模块
import pandas as pd
# 导入线性代数模块
import numpy as np
# 导入模糊字符串匹配模块
from fuzzywuzzy import fuzz, process
# 导入正则表达式模块
import re
# 导入迭代模块
import itertools
# 导入函数开发模块
from typing import Union, List, Tuple
# 导入TF-IDF模块
from sklearn.feature_extraction.text import TfidfVectorizer
# 导入余弦相似度模块
from sklearn.metrics.pairwise import cosine_similarity
# 导入KNN模块
from sklearn.neighbors import NearestNeighbors# 字符串预处理
def preprocess_string(s):# 去掉字符串之间的空格s = re.sub(r'(?<=\b\w)\s*[ &]\s*(?=\w\b)', '', s)return s# 字符串匹配- TF-IDF
def build_vectorizer(clean: pd.Series,analyzer: str = 'char', ngram_range: Tuple[int, int] = (1, 4), n_neighbors: int = 1, **kwargs) -> Tuple:# 创建vectorizervectorizer = TfidfVectorizer(analyzer = analyzer, ngram_range = ngram_range, **kwargs)X = vectorizer.fit_transform(clean.values.astype('U'))# 最近邻nbrs = NearestNeighbors(n_neighbors = n_neighbors, metric = 'cosine').fit(X)return vectorizer, nbrs# 字符串匹配- KNN
def tfidf_nn(messy, clean, n_neighbors = 1, **kwargs):# 拟合干净的数据和转换凌乱的数据vectorizer, nbrs = build_vectorizer(clean, n_neighbors = n_neighbors, **kwargs)input_vec = vectorizer.transform(messy)# 确定可能的最佳匹配distances, indices = nbrs.kneighbors(input_vec, n_neighbors = n_neighbors)nearest_values = np.array(clean)[indices]return nearest_values, distances# 字符串匹配-匹配模糊
def find_matches_fuzzy(row, match_candidates, limit = 5):row_matches = process.extract(row, dict(enumerate(match_candidates)), scorer = fuzz.token_sort_ratio, limit = limit)result = [(row, match[0], match[1]) for match in row_matches]return result# 字符串匹配- TF-IDF
def fuzzy_nn_match(messy,clean,column,col,n_neighbors = 100,limit = 5, **kwargs):nearest_values, _ = tfidf_nn(messy, clean, n_neighbors, **kwargs)results = [find_matches_fuzzy(row, nearest_values[i], limit) for i, row in enumerate(messy)]df = pd.DataFrame(itertools.chain.from_iterable(results),columns = [column, col, 'Ratio'])return df# 字符串匹配-模糊
def fuzzy_tf_idf(df: pd.DataFrame,column: str,clean: pd.Series,mapping_df: pd.DataFrame,col: str,analyzer: str = 'char',ngram_range: Tuple[int, int] = (1, 3)) -> pd.Series:# 创建vectorizerclean = clean.drop_duplicates().reset_index(drop = True)messy_prep = df[column].drop_duplicates().dropna().reset_index(drop = True).astype(str)messy = messy_prep.apply(preprocess_string)result = fuzzy_nn_match(messy = messy, clean = clean, column = column, col = col, n_neighbors = 1)# 混乱到干净return result

请将数据保存在特定的文件夹中,这样我们可以很容易的加载到jupyter上。

# 导入计时模块
import time# 加载数据
df = pd.read_csv('room_type.csv')# 检查数据的维度
print('Dimension of data: {} rows and {} columns'.format(len(df), len(df.columns)))# 打印前5行
df.head()

在这种情况下,Expedia将成为混乱的数据,而Booking.com将成为干净的主数据。为了清楚地理解,我将演示如何运行代码并显示结果。

# 运行模糊字符串匹配算法
start = time.time()
df_result = (df.pipe(fuzzy_tf_idf, # 函数和混乱的数据column = 'Expedia', # 混乱数据列clean = df['Booking.com'], # 主数据(列表)mapping_df = df, # 主数据col = 'Result') # 可以自定义)
end = time.time()# 打印计算时间
print('Fuzzy string matching in {} seconds'.format(end - start))# 查看模糊字符串匹配的结果
df_result.head()

该算法只需要0.050秒就可以将103行杂乱数据与103行主数据进行比较。

它可以在你自己的更大的数据上运行。但是当我们使用Levenshtein距离时,计算过程有多长?

我们必须进行比较,以确保TF-IDF和k -最近邻能够有效地提高计算时间。

与Levenshtein 距离的比较

对于本教程,我制作了一个与前一个函数具有类似输入和输出的函数(与TF-IDF和k近邻进行模糊字符串匹配)。

首先,运行以下代码来实现Levenshtein距离模糊字符串匹配。

# 导入数据操作模块
import pandas as pd
# 导入线性代数模块
import numpy as np
# 导入模糊字符串匹配模块
from fuzzywuzzy import fuzz, process
# 导入二分搜索模块def stringMatching(df: pd.DataFrame,column: str,clean: pd.Series,mapping_df: pd.DataFrame,col: str):# 创建vectorizercategoryClean = clean.drop_duplicates().reset_index(drop = True)categoryMessy = df[column].drop_duplicates().dropna().reset_index(drop = True).astype(str)categoryFuzzy = {}ratioFuzzy = {}for i in range(len(categoryMessy)):resultFuzzy = process.extractOne(categoryMessy[i].lower(), categoryClean)# 映射catFuzzy = {categoryMessy[i]:resultFuzzy[0]}ratFuzzy = {categoryMessy[i]:resultFuzzy[1]}# 保存结果categoryFuzzy.update(catFuzzy)#保存比率ratioFuzzy.update(ratFuzzy)# 创建列名catCol = colratCol = 'Ratio'# 合并结果df[catCol] = df[column]df[ratCol] = df[column]# 映射结果df[catCol] = df[catCol].map(categoryFuzzy)df[ratCol] = df[ratCol].map(ratioFuzzy)return df

现在,是时候使用Levenshtein距离实现模糊字符串匹配算法了!

# 运行模糊字符串匹配算法
start = time.time()
df_result = (df.pipe(stringMatching, # 函数和混乱的数据column = 'Expedia', # 混乱数据列clean = df['Booking.com'], # 主数据mapping_df = df, # 主数据col = 'Result') # 可以自定义)
end = time.time()# 打印计算时间
print('Fuzzy string matching in {} seconds'.format(end - start))# 查看模糊字符串匹配的结果
df_result.head()

与使用TF-IDF和KNN的模糊字符串匹配算法相比,Levenshtein距离需要1.216秒,长24.32倍。

需要注意的是,这个计算时间将随着数据的数量而增加。在这里了解更多关于TF-IDF和Levenshtein距离计算时间的比较。

https://medium.com/tim-black/fuzzy-string-matching-at-scale-41ae6ac452c2

结论

对于小数据,Levenshtein距离(fuzzy-wuzzy模块)是执行模糊字符串匹配的好选择。然而,随着数据大小的增长,计算时间也会增加。

另一种方法是使用TF-IDF结合k近邻和n-gram的NLP技术来查找匹配的字符串。FAISS和HSNW是其他的一些算法,可以用来提高寻找最近邻居的性能。

参考文献

[1] J. Han, M. Kamber, J. Pei. Data Mining: Concepts and Techniques (2012). Elsevier Inc.

[2] C. van den Berg. Super Fast String Matching in Python (2019). https://bergvca.github.io/2017/10/14/super-fast-string-matching.html.

[3] E. Elahi. Fuzzy Matching 101: Cleaning and Linking Messy Data Across the Enterprise(2019). https://dataladder.com/fuzzy-matching-101/.

[4] A. Pearl. Fuzzy String Matching with TF-IDF (2019). https://adrianpearl.github.io/fuzzystring.html.

往期精彩回顾适合初学者入门人工智能的路线及资料下载机器学习及深度学习笔记等资料打印机器学习在线手册深度学习笔记专辑《统计学习方法》的代码复现专辑
AI基础下载机器学习的数学基础专辑温州大学《机器学习课程》视频
本站qq群851320808,加入微信群请扫码:

【NLP】基于TF-IDF和KNN的模糊字符串匹配优化相关推荐

  1. 如何在Postgresql中使用模糊字符串匹配

    It's a fact - people make typos or simply use alternate spellings on a frequent basis. 这是事实-人们经常打错字或 ...

  2. NLP-基础任务-中文分词算法(1)-基于词典: 机械分词(词典字符串匹配):前向最大匹配、后向最大匹配、双向最大匹配【OOV:基于现有词典,不能进行新词发现处理】

    分词与NLP关系:分词是中文自然语言处理的基础,没有中文分词,我们对语言很难量化,进而很能运用数学的知识去解决问题.对于拉丁语系是不需要分词的. 拉丁语系与亚系语言区别 拉丁语言系不需要分词,因为他们 ...

  3. 模糊字符串匹配:双音素算法

    介绍 名称匹配的主要问题之一是出错的可能性. 人们拼写同一个名字(错别字)的方式有很多,他们都听别人说的话. 有多种方法可以破坏自由格式语言数据. 当您需要搜索/匹配不良数据时,这会引起很多麻烦. 有 ...

  4. 模糊字符串匹配:双重解密算法

    名称匹配的一个大问题是错误的倾向.有许多不同的方式,人们拼写相同的名字,打字错误,误读了另一个人说的话.有许多方法可以免费形式的语言数据被破坏.当您需要搜索/匹配不良数据时,会导致许多头疼. 有很多不 ...

  5. NLP之WE之Skip-Gram:基于TF利用Skip-Gram模型实现词嵌入并进行可视化、过程全记录

    NLP之WE之Skip-Gram:基于TF利用Skip-Gram模型实现词嵌入并进行可视化 目录 输出结果 代码设计思路 代码运行过程全记录 输出结果 代码设计思路 代码运行过程全记录 3081 or ...

  6. scitkit-learn:计算机科学论文的TF / IDF和余弦相似度

    几个月前,我下载了数千篇计算机科学论文的元数据,这样我就可以尝试编写一个迷你推荐引擎来告诉我接下来应该读什么论文. 由于我没有任何人可以阅读每篇论文的数据,因此排除了协作过滤方法,所以我认为我可以尝试 ...

  7. tf-idf词向量和bow_使用词袋Bow和TF IDF进行多标签分类

    tf-idf词向量和bow 1.加载数据 (1. Load the data) For this study, we are using Kaggle data for Toxic Comment C ...

  8. 搜索引擎:文本分类——TF/IDF算法

    原理 TFIDF的主要思想是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类.TFIDF实际上是:TF * IDF,TF ...

  9. DL之Attention-ED:基于TF NMT利用带有Attention的 ED模型训练、测试(中英文平行语料库)实现将英文翻译为中文的LSTM翻译模型过程全记录

    DL之Attention-ED:基于TF NMT利用带有Attention的 ED模型训练(中英文平行语料库)实现将英文翻译为中文的LSTM翻译模型过程全记录 目录 测试输出结果 模型监控 训练过程全 ...

最新文章

  1. 刻意练习:LeetCode实战 -- Task04. 三数之和
  2. AI先驱、A*算法发明者Nils Nilsson去世
  3. [实践篇] Softmax Regression
  4. isis simple 运行Maven是报错: No goals have been specified for this build.
  5. css未生效,css不生效是什么原因
  6. html如何隐藏二进制字符串,如何用二进制代码隐藏字符串?
  7. POJ#1182 食物链
  8. android 登录 service_如何优雅的实现自己的Android组件化改造?
  9. 基于 Multiple Teacher Single Student 框架的多领域对话模型
  10. php \n不能换行
  11. 淘宝优惠券去哪里领?
  12. 云计算网络基础架构的实践和演进
  13. 主流无线芯片厂商的自动信道选择算法小结
  14. C++线程池原理及创建
  15. 2020/09/10华为发布会
  16. 用python做系统的感悟_python感悟
  17. 本科课程【数据结构与算法】实验1——线性表的顺序表示及插入、删除操作(C++实现)
  18. 我们要理智使用计算机英语,新视野大学英语第四册(四级)期末复习重点单词词组句子...
  19. Sweet Dreams优美的英文手写字体
  20. python: os 库

热门文章

  1. 安装Extended WPF Toolkit
  2. Python——函数 8、可变长参数
  3. 刷OJ时输入输出与字符串
  4. BZOJ.2707.[SDOI2012]走迷宫(期望 Tarjan 高斯消元)
  5. 经济学相关资料20170924.词袋.books
  6. 微信公众平台开发教程(八)Session处理
  7. JAVA中List的几个方法
  8. Struts的MVC和Spring的MVC的区别
  9. 卓越程序员和优秀程序员有哪些区别?
  10. 转载://C++中getline()、gets()等函数的用法