Страницы: 1
RSS
Сравнение схожести текста для работы с большими списками, оптимизация макроса
 
В прикрепленных файл примера сравнения схожести текста из каждой ячейки с ячейками из того же столбика без учета ячейки, откуда был взят текст для поиска.
В соседних трех столбиках получаем номер строчки с ячейкой в которой находится текст с наибольшей схожестью, процентный показатель схожести и собственно "трансляцию" текста из ячейки с наибольшей схожестью.
При использовании данных макросов и формул, при работе со списками более 500+ строк, после добавления новой строчки оно уводит Excel в пересчет всех показателей схожести по всем строчкам с загрузкой процессора на 100%. Я понимаю, что это логичное действие от Excel и скорее всего этого избежать не получится, но возможно ли оптимизировать работу макросов и формул без ущерба результату? Или минимизировать время обработки данных макросами?
Есть идеи?
 
обновил список ссылок
Изменено: Jack Famous - 31.08.2021 12:04:46
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous,
Сразу уточняю: списков не 2. В том и проблема, что нету "словаря" для сравнения. Текстовое значение для сравнения находится в том же диапазоне где проводится поиск/Сравнение. Если дублировать столбик с названиями и превратить его в "словарь", то по результату работы двух предложенных решений из этих топиков станет 100% совпадение со своим клоном из списка-словаря. Цель достигнута не будет.
 
Доброе время суток.
А вам зачем при каждом вводе пересчитывать, какая в этом цель? Не проще ли выполнить ввод и запустить макрос, который расставить номер строки и процент наилучшего совпадения? В этом случае будет достаточно переделать ваш код для макроса на кнопку.
 
Андрей VG,
Цель постоянного пересчета: предупредить меня о том, что компания уже есть в списке (при учете того, что она может быть написана чуть по другому) и мне не надо вводить еще 29 уже существующих реквизитов и увеличивать кол-во сущностей в таблице.
Скажите, как можно перевести расчет % схожести на кнопку? Возможно это будет как вариант решения проблемы.
 
Код фактически не смотрел, его много и вникать нет никакого резона. Скорее тут нужен комбинированный подход. То есть.
Однократно строим статистику по словам и храним её в переменных модуля. Например, либо создаём её по кнопке, либо функция проверяет инициализирована ли одна из переменных модуля, создаёт её при первом обращении. Тогда сэкономите на времени создания структур для анализа. Плюс, кнопку, которая добавляет текущую фразу в данные статистики, если вы эту фразу считаете новым эталоном.
Может упростить задачу (насколько понял у вас там нечёткое сравнение и на уровне слов). Если ограничится только поиском равных слов во фразах. Создать базу данных с таблицами Фразы(текст фразы; количество слов; индекс фразы [ключевое индексированное поле]), Слова(слово [ключевое индексированное поле]; индекс слова), Слова во фразах (индекс слова [не уникальный индекс], индекс фразы [не уникальный индекс]). Тогда запросом к такой базе можно достаточно быстро получать ответ с какой фразой будет совпадение. Ну, и также по кнопке добавлять в базу текущую фразу, если она эталонна с точки зрения последующих проверок.
 
Ради интереса преобразовал базу названий разделов форума, почистил получилось 59397 предложений, 23928 слов, 323241 сочетаний слов с предложениями. Настроил таблицы в SQL Server LocalDb. Код простой
Код
Const strConn = "Driver={SQL Server Native Client 11.0};Server=(localdb)\mssqllocaldb;Database=TSQL;Trusted_Connection=yes;"
Const baseQuery As String = "Select Top(1) tm.sentence, (Cast(tf.findCount As float) / $1) As [percent] From dbo.sentences tm Inner Join (Select Top (10) ts.sentenceId, Count(*) As findCount From dbo.words tw Inner Join dbo.wordToSentence ts On (tw.wordId = ts.wordId) Where tw.[word] In ($2) Group By ts.sentenceId Order By Count(*) Desc ) tf On (tm.sentenceId = tf.sentenceId) Order By tf.findCount Desc, Abs(tm.wordCount - tf.findCount) Asc;"
Private pConn As ADODB.Connection

Private Sub Worksheet_Change(ByVal Target As Range)
    If TypeName(Target.Value) = "String" And Target.Column = 1 And Target.Row > 1 Then
        Application.EnableEvents = False
        doQuery CStr(Target.Value), Target.Row
        Application.EnableEvents = True
    End If
End Sub

Private Sub doQuery(ByVal sText As String, ByVal inRow As Long)
    Dim sSQL As String, subStr() As String
    Dim pRSet As ADODB.Recordset, sIn As String
    If pConn Is Nothing Then
        Set pConn = New ADODB.Connection
        pConn.CursorLocation = adUseClient
        pConn.Open strConn
    End If
    subStr = Split(LCase$(Application.WorksheetFunction.Trim(sText)), " ")
    sIn = "N'" & Join(subStr, "',N'") & "'"
    sSQL = Replace$(Replace$(baseQuery, "$1", CStr(UBound(subStr) + 1)), "$2", sIn)
    Set pRSet = pConn.Execute(sSQL)
    If pRSet.RecordCount > 0 Then
        Me.Cells(inRow, 2).Value = pRSet(0).Value
        Me.Cells(inRow, 3).Value = pRSet(1).Value
    Else
        Me.Cells(inRow, 2).Value = "N/A"
        Me.Cells(inRow, 3).Value = 0
    End If
    pRSet.Close
End Sub

Задержки при проверке ввода словосочетаний в первый столбец листа с обработчиком события не почувствовал. Так что вариант вполне себе рабочий :)
 
msdoser, Спасибо за файлик . то что искал .  
Изменено: Doneck117 - 18.10.2018 20:08:03
 
Привет, возможно, кто-то поможет адаптировать под мой файл данный макрос.
Нужно сравнить "Название 1" и "Название 2" и вывести процент схожести.
Очень желательно, чтобы все функции лежали в одной папке для удобства переноса на другие ПК.
Готов оплатить работу.
Изменено: Валерий - 27.08.2021 18:07:13
 
Валерий, подскажите, пожалуйста, как вы получили для ячеек F2 и M2 процент совпадения 95%?
 
Андрей, огромное спасибо за помощь!
Процент совпадения в примере заполнил "на глаз"  чтобы показать куда выводить данное значение.
Изменено: vikttur - 28.08.2021 14:43:10
 
Еще вопрос, возможно ли вычислять процент не учитывая последовательность символов?
В данном варианте получается процент схожести "Аэрозольные краски" и "Аэрозольная краска" = 56%
 
Андрей VG, приветствую!
Очень заинтересовал ваш вариант Fuzzy by SQL
Попытался переделать в функцию, но выдаёт ошибку на строке pConn.Open strConn (в оригинале тоже не работает, но без ошибки, а с зависанием)
Что я делаю не так?
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Валерий написал:
не учитывая последовательность символов?
Можно получить пояснение, что вы под этим подразумеваете? Как имея строку №1 и строку №2, определить чем они между собой схожи, учитывая определение строки, как последовательность некоторых символов некоторого алфавита (именно с этим работает VBA)? Может вы под этим подразумеваете - строки схожу между собой по количеству равных символов? Но тогда гора и рога будут иметь 100% совпадение.
Изменено: Андрей VG - 30.08.2021 16:29:06
 
Код
Function ProcEqual#(s1$, s2$)
  Dim s$, ds$, i&
  If s1 = s2 Then ProcEqual = 1: Exit Function
  If Len(s1) * Len(s2) = 0 Then Exit Function
  i = 1: If s2 Like Left(s1, 1) & "*" Then s = Left(s1, 1) Else s = "*"
  Do While i < Len(s1)
    i = i + 1
    If s2 Like s & Mid(s1, i, 1) & "*" Then ds = Mid(s1, i, 1) Else ds = "*"
    s = s & ds
  Loop
  i = Len(Replace(s, "*", ""))
  If i >= Len(s2) Then ProcEqual = i / Len(s1) Else ProcEqual = i / Len(s2)
End Function
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Ігор Гончаренко, сейчас начнётся, а почему "пер Туристский" и "Туристский пер" дают только 0,142857143? :)
 
это запросто))
а если сравнить "Туристский пер" и "пер Туристский", то процент уже 64%)
но пока только Валерий знает насколько совпали эти 2 фразы
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Цитата
Андрей VG: сейчас начнётся, а почему
даже если считать, что сжимать пробелы, удалять непечатаемые, заменять латиницу на похожую кириллицу — не нужно, то, как минимум, привести к одному регистру (сравнение без учёта регистра) не помешает  :)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 

Конкретно в моем случае будут сравниваться близкие по смыслу слова или словосочетания (пример:"Аэрозольные краски" и "Аэрозольная краска"). Варианта «гора и рога» встретиться не может. Поэтому актуальнее сравнивать количество одинаковых символов =) Если поможете, буду весьма признателен.

 
см. макрос в сообщении 16
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Тут много ссылок (добавил и на эту тему)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Страницы: 1
Наверх