Fuzzy text matching is very useful when you want to compare a text string against other strings that don’t have to be identical. You still, however, want to find the one that is closest in terms of words. Fuzzy matching is very useful when e.g. you want to compare a user question against a database of solutions/answers. That is basically what Google does everyday. Rarely will your question ideally match the title of a blog or news article so Google tries to rank pages using fuzzy matching to find ones that are closest to your query.
Microsoft Fuzzy Lookup AddIn
As Fuzzy matching / lookup is a frequent feature Excel users required Microsoft decide to create their own Fuzzy Lookup AddIn. The AddIn basically allows you to lookup columns from another table using Fuzzy Matching and copy them to your source table.
Go here to find Microsoft Official Fuzzy Lookup AddIn for Excel
When playing with the Fuzzy Lookup AddIn I wasn’t happy with it. I had an enormous database of user Questions and Answers and I wanted to have a choice of which items it will match for each of my records basis the user query. Often the fuzzy match algorithm would suggest a match that wasn’t perfect given context. Hence I decide to create my own Fuzzy Match VBA UserForm….
Custom Fuzzy Match using VBA UserForm
What I wanted was an easy way to lookup my query against a Knowledge Base of questions that are ranked in terms of their match against the query. The closer the query is to the question the higher the match. That way I can decide whether indeed I want to take the answer from the question with the highest match rate or maybe one of the below. The additional requirement was to ignore so called “stop words” in my query (the, a, it etc.) as these could generate a lot of false matches, while I wanted fuzzy matching only focus on the keywords.
To show you how the Fuzzy Match VBA UserForm works I created a simple Knowledge Base of Excel/VBA related questions. The KB consists of 3 basis columns: Questions, Answer and Category. The Category column is especially useful as looking at the query you might want to limit the Fuzzy algorithm to run on only a subset of items in your database.
Designing the Fuzzy Match UserForm
Below a quick overview of the Fuzzy Match VBA UserForm if you want to see it in action:
Below you can find the design of the VBA Fuzzy Match UserForm.
Each field is explained below:
- Text Selected – text from the Excel cell you selected in your workbook before running the VBA macro
- Search Question – if you want to override the “Text Selected” field simply type your query here and hit the Search button again. A typical scenario for this field is when you see that the result for your “Text Selected” don’t return satisfactory results and you would like to adjust the query
- Category(s) – if you want to improve the algorithm performance or simply reduce the categories to be searched then select the ones you are interested in
- Search – the Search button will run the algorithm and return results to the “Results” table
- Selected Question / Selected Answer – when you click on one of the results these fields will show the full text of the Question and Answer column. This makes it easier to copy the results where needed
The VBA Code
Initializing the UserForm
Firstly we will initialize our UserForm and assure it is showing us the current list of categories in our “KnowledgeBase” worksheet:
Private Sub UserForm_Initialize() Set catDict = GetListofCategories() For Each it In catDict.keys lbCategory.AddItem it Next it lbCategory.AddItem "Any" For i = 0 To lbCategory.ListCount - 1 lbCategory.Selected(i) = True Next i tbSelectedQuestion.Text = Selection.Value End Sub Function GetListofCategories() Dim question As Range Set dict = CreateObject("Scripting.Dictionary") Set wsQnA = GetQnAWorksheet For Each question In wsQnA.Range("C:C").SpecialCells(xlCellTypeConstants) If question.Row > 1 Then If Not dict.Exists(question.Value) Then dict.Add question.Value, 1 End If End If Next question Set GetListofCategories = dict End Function Function GetQnAWorksheet() As Worksheet Dim ws As Worksheet For Each ws In ActiveWorkbook.Sheets If ws.Name Like "KnowledgeBase*" And ws.Visible Then Set GetQnAWorksheet = ws Exit Function End If Next ws MsgBox "KnowledgeBase worksheet not found!~", vbCritical + vbOKOnly, "Error" Set GetQnAWorksheet = Nothing End Function
Function for removing Stop Words
Before we focus on generating matches let us focus for a sec on creating a function that will remove stop words from a given sentence. This will help us get rid of all those unnecessary words like “the, it, this” etc. that will dilute the fuzzy algorithm.
Function RemoveStopWords(sentence As String) As Collection If IsEmpty(stopWords) Then stopWords = Split("a;about;above;after;again;against;all;am;an;and;any;are;aren't;as;at;be;because;been;before;being;below;between;both;but;by;can't;cannot;chat;could;couldn't;did;didn't;do;does;doesn't;doing;don't;down;during;each;few;for;from;further;had;hadn't;has;hasn't;have;haven't;having;he;he'd;he'll;he's;her;here;here's;hers;herself;hi;him;himself;his;how;how's;i;i'd;i'll;i'm;i've;if;in;into;is;isn't;it;it's;its;itself;let's;me;more;most;mustn't;my;myself;need;needs;no;nor;not;of;off;on;once;only;or;other;ought;our;ours;out;over;own;same;shan't;she;she'd;she'll;she's;should;shouldn't;so;some;such;than;that;that's;the;their;theirs;them;themselves;then;there;there's;these;they;they'd;they'll;they're;they've;this;those;through;to;too;under;until;up;very;was;wasn't;we;we'd;we'll;we're;we've;were;weren't;what;what's;when;when's;where;where's;which;while;who;who's;whom;why;why's;with;won't;would;wouldn't;you;you'd;you'll;you're;you've;your;yours;yourself;yourselves;?;!;" & _ "-;,;", ";") Dim stopR As Range, r As Variant, col As Collection Set col = New Collection For Each w In Split(sentence, " ") If Not (IsNumeric(Trim(w))) Then w = Trim(w) If Len(w) > 0 Then col.Add w End If Next w For Each r In stopWords For i = col.Count To 1 Step -1 If UCase(col(i)) = UCase(r) Then col.Remove i End If Next i Next r Set RemoveStopWords = col End Function
You probably noticed I embedded a lot of words directly in the function. This makes it easy to add or remove stop words quickly.
Fuzzy Matching algorithm
Now for the meaty part :). Below the key logic for generating the results:
Public stopWords As Variant Dim selectedChat As Range Private Sub cbSearch_Click() 'Clear Search worksheet Set selectedChat = Selection Dim wsRes As Worksheet: Set wsRes = GetSearchWorksheet selectedChat.Worksheet.Activate 'Remove stop words from question Dim qCol As Collection Set qCol = RemoveStopWords(Selection.Value) 'Search Dim wsQnA As Worksheet, r As Range, saCol As Collection, sa() As String, saIndex As Long Dim dict As Object, dstR As Range, startCount As Long, pMax As Long, currProgress As Long Set dict = CreateObject("Scripting.Dictionary") For i = 0 To lbCategory.ListCount - 1 If lbCategory.Selected(i) Then dict.Add lbCategory.List(i), lbCategory.List(i) End If Next i 'Search question matching Service Area, search query and calculate match Set wsQnA = GetQnAWorksheet If wsQnA Is Nothing Then Exit Sub startCount = wsRes.Range("A:A").SpecialCells(xlCellTypeConstants).Count pMax = wsQnA.Range("A:A").SpecialCells(xlCellTypeConstants).Count For Each r In wsQnA.Range("A:A").SpecialCells(xlCellTypeConstants) If dict.Exists(r.Offset(0, 4).Value) Or IsEmpty(r.Offset(0, 4).Value) And r.Row > 1 Then If tbSearch.Value = vbNullString Or InStr(1, r.Value, tbSearch.Value, vbTextCompare) > 0 Then Set dstR = wsRes.Range("A1").Offset(startCount): startCount = startCount + 1 dstR.Value = r.Value dstR.Offset(0, 1).Value = r.Offset(0, 1).Value dstR.Offset(0, 2).Value = r.Offset(0, 2).Value dstR.Offset(0, 3).Value = CalculateMatch(qCol, r.Value) dstR.Offset(0, 3).NumberFormat = "0%" End If End If currProgress = currProgress + 1 If currProgress Mod 100 = 0 Then lStatus.Caption = "Searching " & Format(CDbl(currProgress) / pMax, "0%") DoEvents End If Next r 'Display Search sorted by Match If wsRes.UsedRange.Rows.Count > 0 Then With wsRes.Sort .SortFields.Clear .SortFields.Add2 Key:=GetSearchLastColumn(wsRes), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal .SetRange wsRes.UsedRange .Header = xlYes .MatchCase = False .Orientation = xlTopToBottom .SortMethod = xlPinYin .Apply End With End If lbResult.RowSource = GetSearchRangeAddress(wsRes) lStatus.Caption = "" & lbResult.ListCount & " Questions found" End Sub Function GetSearchRangeAddress(ws As Worksheet) GetSearchRangeAddress = "'" & ws.Name & "'!" & Range(ws.Range("A2"), ws.Cells(ws.UsedRange.Rows.Count, ws.UsedRange.Columns.Count)).AddressLocal End Function Function GetSearchLastColumn(ws As Worksheet) As Range Set GetSearchLastColumn = Range(ws.Range("D2"), ws.Cells(ws.UsedRange.Rows.Count, ws.UsedRange.Columns.Count)) End Function Function CalculateMatch(sentCol As Collection, sentence As String) As Double Dim m As Long, s() As String s = Split(sentence, " ") For Each w In sentCol For Each ws In s If UCase(ws) = UCase(w) Then m = m + 1 Exit For End If Next ws Next w CalculateMatch = m / sentCol.Count End Function Sub CreateSearchResultsHeader(ws As Worksheet) ws.Range("A1").Value = "Questions" ws.Range("B1").Value = "Answer" ws.Range("C1").Value = "Category" ws.Range("D1").Value = "Match" End Sub Sub AddSearchResultsRow(ws As Worksheet, rowNum As Long, question As String, answer As String, sa As String, match As String) ws.Range("A" & rowNum).Value = question ws.Range("B" & rowNum).Value = answer ws.Range("C" & rowNum).Value = sa ws.Range("D" & rowNum).Value = match End Sub Function GetSearchWorksheet() Dim ws As Worksheet For Each ws In ActiveWorkbook.Sheets If ws.Name = "SearchResults" Then ws.UsedRange.Clear CreateSearchResultsHeader ws Set GetSearchWorksheet = ws Exit Function End If Next ws Set ws = ActiveWorkbook.Sheets.Add ws.Name = "SearchResults" CreateSearchResultsHeader ws Set GetSearchWorksheet = ws End Function
The above code will do the following – compare the query to each question from the selected categories, calculate the match and add it to a temporary worksheet. Once done the table in the form will be connected to the range in the temporary worksheet and displayed.
Below a few other pieces of code that help display the Q/A in the text boxes and help us clean-up:
Private Sub lbResult_Click() 'Display question and answer in textbox below For i = 0 To lbResult.ListCount - 1 If lbResult.Selected(i) Then tbQ.Value = lbResult.List(i, 0) tbA.Value = lbResult.List(i, 1) End If Next i End Sub Private Sub UserForm_Terminate() On Error Resume Next Application.DisplayAlerts = False ActiveWorkbook.Sheets("SearchResults").Delete Application.DisplayAlerts = True End Sub
Download the entire VBA Code Module
If you want to download the entire VBA Code Module for the Excel VBA Fuzzy Match UserForm click the download button below:
Download
Одна из самых неприятных ситуаций, с которой может столкнуться пользователь при работе в Microsoft Excel — это поиск и подстановка данных с неточным совпадением. Когда вам надо подставить данные из одной таблицы в другую, но вы при этом уверены, что в обеих таблицах совпадающие элементы называются одинаково, то проблем нет — к вашим услугам множество способов: функции ВПР и её аналоги, надстройка Power Query и т.д.
А вот если в одной таблице «Пупкин Василий», а в другой просто «Пупкин», или «Пупкин В.», или даже «Пупкен», то все эти красивые способы не работают. Причем на практике такое встречается постоянно, особенно с почтовыми адресами или названиями компаний:
Обратите внимание на различные типы несоответствий, которые могут встречаться:
- переставлены местами улица, город, дом
- отсутствует какая-то часть адреса или, наоборот, есть что-то лишнее (индекс, номер квартиры)
- по-разному записан город (с буквой «г.» или без) или улица
- опечатки и ошибки (Козань вместо Казань)
Про точное соответствие или даже поиск по маске тут говорить не приходится. Помочь в таком случае могут только специальные макросы или надстройки для Excel. Про одну из таких макро-функций на VBA я уже писал, а здесь хочется рассказать про еще один вариант решения подобной задачи — надстройку Fuzzy Lookup от компании Microsoft.
Эта надстройка существует с 2011 года и совершенно бесплатно скачивается с сайта Microsoft. Системные требования: Windows 7 или новее, Office 2007 или новее, соответственно. После установки у вас в Excel появляется одноименная вкладка с единственной кнопкой на ней:
Нажатие на эту кнопку включает специальную панель в правой части окна Excel, где и задаются все настройки поиска:
Сразу хочу отметить, что эта надстройка умеет работать только с умными таблицами, поэтому все исходные таблицы нужно конвертировать в умные с помощью сочетания Ctrl+T или кнопки Форматировать как таблицу на вкладке Главная (Home — Format as Table):
Алгоритм действий при работе с надстройкой Fuzzy Lookup следующий:
- Выберите какие таблицы нужно связать в выпадающих списках Left и Right Table.
- Выберите ключевые столбцы в левой и правой таблицах, по которым нужно проверить соответствие и нажмите кнопку для добавления созданной пары в список Match Columns
- В списке Output Columns отметьте галочками столбцы, которые вы хотите получить на выходе в качестве результата.
- Установите активную ячейку в пустое место на листе, куда вы хотите вывести данные
- Нажмите кнопку Go
После анализа мы получаем таблицу, где каждому элементу ключевого столбца из первой таблицы подобрано максимально похожее значение из второй:
Лепота!
Нюансы и подводные камни
- Точность подбора можно регулировать с помощью ползунка Similarity Threshold в нижней части панели Fuzzy Lookup. Чем правее его положение, тем строже будет поиск, и — как следствие — тем меньше результатов надстройка будет находить. Если сдвинуть его влево, то результатов станет больше, но возрастет риск ошибочного совпадения. Тут все зависит от вашей конкретной ситуации — экспериментируйте.
- На больших таблицах поиск может занимать приличное количество времени (до нескольких десятков секунд), хотя многое, конечно, зависит от мощности вашего компьютера. Как вариант, для ускорения в настройках (кнопка Configure в нижней части панели) можно попробовать включить параметр UseApproximateIndexing в разделе Global Settings.
- Перед нажатием на кнопку Go не забудьте выделить пустую ячейку, начиная с которой вы хотите вывести результаты. Если случайно вы оставите активную ячейку где-нибудь в исходных данных, то надстройка выведет итоговую таблицу прямо поверх них, и вы их потеряете. Причем отмена последнего действия будет невозможна, а кнопка Undo в нижней части панели не всегда срабатывает почему-то.
- Для вывода столбца с коэффициентом подобия FuzzyLookup.Similarity необходимо, чтобы у вашего Excel была точка в качестве десятичного разделителя (целой и дробной части). Если это не так, то эту настройку временно можно поменять через Файл — Параметры — Дополнительно (File — Options — Advanced).
- Fuzzy Lookup — это не обычная надстройка, написанная на VBA (как мой PLEX, например), а COM-надстройка. Разница в том, что она устанавливается как отдельная программа, т.е. вам нужны соответствующие права на установку ПО на вашем компьютере. Дома, ясное дело, проблем не будет, а вот многим корпоративным пользователям, скорее всего, придется обращаться к вашим айтишникам. После установки отключать и подключать ее в дальнейшем можно на вкладке Разработчик — Надстройки COM (Developer — COM Add-ins).
В любом случае, при всех имеющихся минусах, эта надстройка однозначно стоит того, чтобы находиться в арсенале любого продвинутого пользователя Microsoft Excel.
Ссылки по теме
- Неточный поиск ближайшего похожего текста с помощью макрофункции
- Анализ текста регулярными выражениями (RegExp) в Excel
- Ссылка на скачивание надстройки Fuzzy Lookup с сайта Microsoft
Here is a VBA implementation of the Levenshein Distance. You can adjust the threshold to fit your needs.
Public Function Levenshtein(str1 As String, str2 As String) As Integer
On Error GoTo ErrHandler
Dim arrLev, intLen1 As Integer, intLen2 As Integer, i As Integer
Dim j, arrStr1, arrStr2, intMini As Integer
intLen1 = Len(str1)
ReDim arrStr1(intLen1 + 1)
intLen2 = Len(str2)
ReDim arrStr2(intLen2 + 1)
ReDim arrLev(intLen1 + 1, intLen2 + 1)
arrLev(0, 0) = 0
For i = 1 To intLen1
arrLev(i, 0) = i
arrStr1(i) = Mid(str1, i, 1)
Next
For j = 1 To intLen2
arrLev(0, j) = j
arrStr2(j) = Mid(str2, j, 1)
Next
For j = 1 To intLen2
For i = 1 To intLen1
If arrStr1(i) = arrStr2(j) Then
arrLev(i, j) = arrLev(i - 1, j - 1)
Else
intMini = arrLev(i - 1, j) 'deletion
If intMini > arrLev(i, j - 1) Then intMini = arrLev(i, j - 1) 'insertion
If intMini > arrLev(i - 1, j - 1) Then intMini = arrLev(i - 1, j - 1) 'deletion
arrLev(i, j) = intMini + 1
End If
Next
Next
Levenshtein = arrLev(intLen1, intLen2)
Exit Function
ErrHandler:
MsgBox Err.Description
Exit Function
End Function
vba_fuzzymatching
Introduction:
This VBA module contains 4 user-defined functions (UDFs) that enable Excel users to execute fuzzy matching by using the basic algorithm for computing the Levenshtein Distance between two strings. Following are details on these functions.
Functions
=LevD([String 1],[String 2])
Calculates the Levenshtein Distance between two strings. The Levenshtein Distance is the minimum number of character insertions, deletions, and substitutions required to perfectly match one string to another. This formula isn’t case sensitive.
=Fuzzy_Match([String 1],[Array of Strings], [Threshold])
Traverses an array of strings, calculating the Levenshtein Distance between each item (string) in the [Array of Strings] and [String 1] (String 1 is the string you are seeking a match for). If a value in the array of strings is a sentence (includes a space), then it will be partitioned and matched based on the best-matching substring (see «bestword» function below). The third paramter: [Threshold], requires an input value between 0 and 1. This is the minimum string similiarity the user desires for fuzzy matching, e.g., if the user inputs «.75», then no matches will be returned with a string similarity less than 75%. This function Returns the closest match, i.e., the string with the lowest Levenshtein Distance.
Note: If two or more strings have lowest Levenshtein distance, the first one traversed in the [Array of Strings] will be returned.
=bestword([string1], [string2])
Takes a sentence ([string2] and partitions it using delimeter = (» «). Then each substring will be matched to [String1]. The best matching substring will be returned.
=String_Similarity([String 1],[String 2])
Calculates the similarity percentage between two strings using the Levenshtein Distance, e.g., «rock» and «sock» are 75% similiar, because 3 of their 4 characters are the same.
Technologies Used
Visual Basic Editor for Excel
References
Levenshtein Distance Formula: https://en.wikipedia.org/wiki/Levenshtein_distance?msclkid=154f886daafe11ec82b22174e1344ccf
Basic string similarity formula: http://adamfortuno.com/index.php/2021/07/05/levenshtein-distance-and-distance-similarity-functions/?msclkid=aa598709a8b611ec8de2ac84df81a9da
Содержание
- Нечеткий текстовый поиск с Fuzzy Lookup в Excel
- Нюансы и подводные камни
- Analyst Cave
- Excel VBA Fuzzy Match text against a table
- Microsoft Fuzzy Lookup AddIn
- Custom Fuzzy Match using VBA UserForm
- Designing the Fuzzy Match UserForm
- The VBA Code
- Initializing the UserForm
- Function for removing Stop Words
- Fuzzy Matching algorithm
- Download the entire VBA Code Module
- Matching similar but not exact text strings in Excel VBA projects
- 5 Answers 5
Нечеткий текстовый поиск с Fuzzy Lookup в Excel
Одна из самых неприятных ситуаций, с которой может столкнуться пользователь при работе в Microsoft Excel — это поиск и подстановка данных с неточным совпадением. Когда вам надо подставить данные из одной таблицы в другую, но вы при этом уверены, что в обеих таблицах совпадающие элементы называются одинаково, то проблем нет — к вашим услугам множество способов: функции ВПР и её аналоги, надстройка Power Query и т.д.
А вот если в одной таблице «Пупкин Василий», а в другой просто «Пупкин», или «Пупкин В.», или даже «Пупкен», то все эти красивые способы не работают. Причем на практике такое встречается постоянно, особенно с почтовыми адресами или названиями компаний:
Обратите внимание на различные типы несоответствий, которые могут встречаться:
- переставлены местами улица, город, дом
- отсутствует какая-то часть адреса или, наоборот, есть что-то лишнее (индекс, номер квартиры)
- по-разному записан город (с буквой «г.» или без) или улица
- опечатки и ошибки (Козань вместо Казань)
Про точное соответствие или даже поиск по маске тут говорить не приходится. Помочь в таком случае могут только специальные макросы или надстройки для Excel. Про одну из таких макро-функций на VBA я уже писал, а здесь хочется рассказать про еще один вариант решения подобной задачи — надстройку Fuzzy Lookup от компании Microsoft.
Эта надстройка существует с 2011 года и совершенно бесплатно скачивается с сайта Microsoft. Системные требования: Windows 7 или новее, Office 2007 или новее, соответственно. После установки у вас в Excel появляется одноименная вкладка с единственной кнопкой на ней:
Нажатие на эту кнопку включает специальную панель в правой части окна Excel, где и задаются все настройки поиска:
Сразу хочу отметить, что эта надстройка умеет работать только с умными таблицами, поэтому все исходные таблицы нужно конвертировать в умные с помощью сочетания Ctrl + T или кнопки Форматировать как таблицу на вкладке Главная (Home — Format as Table) :
Алгоритм действий при работе с надстройкой Fuzzy Lookup следующий:
- Выберите какие таблицы нужно связать в выпадающих списках Left и Right Table.
- Выберите ключевые столбцы в левой и правой таблицах, по которым нужно проверить соответствие и нажмите кнопку для добавления созданной пары в список Match Columns
- В списке Output Columns отметьте галочками столбцы, которые вы хотите получить на выходе в качестве результата.
- Установите активную ячейку в пустое место на листе, куда вы хотите вывести данные
- Нажмите кнопку Go
После анализа мы получаем таблицу, где каждому элементу ключевого столбца из первой таблицы подобрано максимально похожее значение из второй:
Нюансы и подводные камни
- Точность подбора можно регулировать с помощью ползунка Similarity Threshold в нижней части панели Fuzzy Lookup. Чем правее его положение, тем строже будет поиск, и — как следствие — тем меньше результатов надстройка будет находить. Если сдвинуть его влево, то результатов станет больше, но возрастет риск ошибочного совпадения. Тут все зависит от вашей конкретной ситуации — экспериментируйте.
- На больших таблицах поиск может занимать приличное количество времени (до нескольких десятков секунд), хотя многое, конечно, зависит от мощности вашего компьютера. Как вариант, для ускорения в настройках (кнопка Configure в нижней части панели) можно попробовать включить параметр UseApproximateIndexing в разделе Global Settings.
- Перед нажатием на кнопку Goне забудьте выделить пустую ячейку, начиная с которой вы хотите вывести результаты. Если случайно вы оставите активную ячейку где-нибудь в исходных данных, то надстройка выведет итоговую таблицу прямо поверх них, и вы их потеряете. Причем отмена последнего действия будет невозможна, а кнопка Undo в нижней части панели не всегда срабатывает почему-то.
- Для вывода столбца с коэффициентом подобия FuzzyLookup.Similarity необходимо, чтобы у вашего Excel была точка в качестве десятичного разделителя (целой и дробной части). Если это не так, то эту настройку временно можно поменять через Файл — Параметры — Дополнительно (File — Options — Advanced) .
- Fuzzy Lookup — это не обычная надстройка, написанная на VBA (как мой PLEX, например), а COM-надстройка. Разница в том, что она устанавливается как отдельная программа, т.е. вам нужны соответствующие права на установку ПО на вашем компьютере. Дома, ясное дело, проблем не будет, а вот многим корпоративным пользователям, скорее всего, придется обращаться к вашим айтишникам. После установки отключать и подключать ее в дальнейшем можно на вкладке Разработчик — Надстройки COM (Developer — COM Add-ins) .
В любом случае, при всех имеющихся минусах, эта надстройка однозначно стоит того, чтобы находиться в арсенале любого продвинутого пользователя Microsoft Excel.
Источник
Analyst Cave
Simply the best place to learn Excel and Analytics
Home » Excel VBA Fuzzy Match text against a table
Excel VBA Fuzzy Match text against a table
Fuzzy text matching is very useful when you want to compare a text string against other strings that don’t have to be identical. You still, however, want to find the one that is closest in terms of words. Fuzzy matching is very useful when e.g. you want to compare a user question against a database of solutions/answers. That is basically what Google does everyday. Rarely will your question ideally match the title of a blog or news article so Google tries to rank pages using fuzzy matching to find ones that are closest to your query.
Microsoft Fuzzy Lookup AddIn
As Fuzzy matching / lookup is a frequent feature Excel users required Microsoft decide to create their own Fuzzy Lookup AddIn. The AddIn basically allows you to lookup columns from another table using Fuzzy Matching and copy them to your source table.
When playing with the Fuzzy Lookup AddIn I wasn’t happy with it. I had an enormous database of user Questions and Answers and I wanted to have a choice of which items it will match for each of my records basis the user query. Often the fuzzy match algorithm would suggest a match that wasn’t perfect given context. Hence I decide to create my own Fuzzy Match VBA UserForm….
Custom Fuzzy Match using VBA UserForm
What I wanted was an easy way to lookup my query against a Knowledge Base of questions that are ranked in terms of their match against the query. The closer the query is to the question the higher the match. That way I can decide whether indeed I want to take the answer from the question with the highest match rate or maybe one of the below. The additional requirement was to ignore so called “stop words” in my query (the, a, it etc.) as these could generate a lot of false matches, while I wanted fuzzy matching only focus on the keywords.
To show you how the Fuzzy Match VBA UserForm works I created a simple Knowledge Base of Excel/VBA related questions. The KB consists of 3 basis columns: Questions, Answer and Category. The Category column is especially useful as looking at the query you might want to limit the Fuzzy algorithm to run on only a subset of items in your database. An example Knowledge Base
Designing the Fuzzy Match UserForm
Below a quick overview of the Fuzzy Match VBA UserForm if you want to see it in action:
Below you can find the design of the VBA Fuzzy Match UserForm.
The design of the VBA Fuzzy Match UserForm
Each field is explained below:
- Text Selected – text from the Excel cell you selected in your workbook before running the VBA macro
- Search Question – if you want to override the “Text Selected” field simply type your query here and hit the Search button again. A typical scenario for this field is when you see that the result for your “Text Selected” don’t return satisfactory results and you would like to adjust the query
- Category(s) – if you want to improve the algorithm performance or simply reduce the categories to be searched then select the ones you are interested in
- Search – the Search button will run the algorithm and return results to the “Results” table
- Selected Question / Selected Answer – when you click on one of the results these fields will show the full text of the Question and Answer column. This makes it easier to copy the results where needed
The VBA Code
Initializing the UserForm
Firstly we will initialize our UserForm and assure it is showing us the current list of categories in our “KnowledgeBase” worksheet:
Function for removing Stop Words
Before we focus on generating matches let us focus for a sec on creating a function that will remove stop words from a given sentence. This will help us get rid of all those unnecessary words like “the, it, this” etc. that will dilute the fuzzy algorithm.
You probably noticed I embedded a lot of words directly in the function. This makes it easy to add or remove stop words quickly.
Fuzzy Matching algorithm
Now for the meaty part :). Below the key logic for generating the results:
The above code will do the following – compare the query to each question from the selected categories, calculate the match and add it to a temporary worksheet. Once done the table in the form will be connected to the range in the temporary worksheet and displayed.
Below a few other pieces of code that help display the Q/A in the text boxes and help us clean-up:
Download the entire VBA Code Module
If you want to download the entire VBA Code Module for the Excel VBA Fuzzy Match UserForm click the download button below:
Download
Источник
Matching similar but not exact text strings in Excel VBA projects
Okay, I have been trying to find a solution for this and I just don’t seem to be able. I can’t even break down the problem properly. This is the idea.
I have two sheets with many rows (one with 800 and the other with 300,000). Each row contains a Name column and then several columns that contain information about this Name. Each sheet has different kinds of information.
I want to consolidate these two sheets into a master sheet based on this Name column they both have, so the consolidate function is perfect for this. Now the problem is that the names don’t match perfectly.
For example Sheet1 contains
«Company B.V.», «Info #1»
«Company Total», «Info #2»
«Company Ltd», «Info #3»
and sheet 2 contains
«Company and Co.», «Info #4»
«Company and Co», «Info #5»
Sheet 1 contains all the names that are going to be used (around a 100 but in different forms as stated above) and sheet 2 contains all these 100 in multiple rows plus names that aren’t in the 100 list and therefore I don’t care about.
How would I make a VBA code project where the end result would be something like this, Master sheet:
«Company», «Info #1», «Info #2», «Info #3», «Info #4», «Info #5»
for every single «Company» (the 100 list) in there??
I do hope there is a solution for this. I’m pretty new to VBA projects, but I have done some minimal coding before.
5 Answers 5
I would place the macro in your PERSONAL section, this way the macro is available in all worksheets. Do this by recording a dummy macro and select to store it in Personal Macro workbook. Now you can manually add new macro’s and functions in this personal workbook.
I just tried this one (don’t know the original source) and it works fine.
The formula looks like this: =PERSONAL.XLSB!FuzzyFind(A1,B$1:B$20)
The code is here:
You can Google Excel UDF Fuzzy lookup or Levensthein distance. There are some UDF’s floating around and Microsoft does have a Fuzzy lookup/match add-on as well (when I used it, it was crash prone and not intuitive).
I used Robert solution and it works fine for me. I am posting whole solution for people who are new for excel but knows coding:
Though this thread is old but I took some code from another threads and tried and looks like solution is giving approx match. Here I am trying to match one column of sheet1 with one column of sheet2:
- add command button in excel
- put following code and click/run button and function gives you result in selected column
Take a look at the functions on this DDoE post. You could generate a longest common sequence string and compare the length to the original string. Feed it some known matches and some close non-matches and see if you can see a clear dividing line between them.
These functions are used for diffing, not finding close matches, but they may work for you.
Not exactly on point but similar, and people dealing with my issue are likely to find this page when searching.
Task: A list of patients who have been in car wrecks, including street addresses. Find related accounts based on same street address. The list will be a maximum of maybe 120 records—so partial manual review is realistic.
Problem: Street addresses are similar but not identical, e.g. 123 JONES LANE and 123 JONES LN or 72 MAIN STREET #32 and 72 MAIN STREET # 32.
Part of the solution is to compare only the street numbers. With a list that size it’s unusual to have two different addresses with the same street number (e.g., 123 JONES LANE and 123 MAIN STREET).
Caution: You can’t use VAL() to pull the street number. Try it with 167 E 13 ST. VBA sees that as 167^13 and will crash if you are outputting to Street_Num As Integer. So you have to use a loop to pull the digits into a new string and stop at the first non-digit character.
Источник