আমি প্রায় এক বছর আগে যখন এই সমস্যার মুখোমুখি হয়েছি তখন ব্যবহারকারীরা বিবিধ তথ্যের একটি ডাটাবেসে একটি তেল র্যাগ সম্পর্কিত তথ্য প্রবেশ করায়। লক্ষ্যটি ছিল কিছু ধরণের ফাজি স্ট্রিং অনুসন্ধান যা খুব সাধারণ উপাদানগুলির সাথে ডাটাবেস এন্ট্রি সনাক্ত করতে পারে।
লেভেনস্টেইন দূরত্বের অ্যালগরিদম বাস্তবায়নের সাথে জড়িত গবেষণার অংশ , এটি নির্ধারণ করে যে স্ট্রিং বা বাক্যাংশে এটিকে অন্য স্ট্রিং বা বাক্যাংশে রূপান্তর করতে কতগুলি পরিবর্তন আনতে হবে।
আমি যে বাস্তবায়নটি নিয়ে এসেছি তা তুলনামূলকভাবে সহজ ছিল এবং দুটি বাক্যাংশের দৈর্ঘ্যের, প্রতিটি বাক্যাংশের মধ্যে পরিবর্তনের সংখ্যা এবং প্রতিটি শব্দের লক্ষ্য প্রবেশের মধ্যে খুঁজে পাওয়া যায় কিনা তার একটি ভারী তুলনা জড়িত।
নিবন্ধটি একটি ব্যক্তিগত সাইটে রয়েছে তাই আমি এখানে প্রাসঙ্গিক বিষয়বস্তু যুক্ত করার জন্য যথাসাধ্য চেষ্টা করব:
দুটি শব্দ বা বাক্যাংশের মিলের জন্য মানুষের মতো অনুমান করার প্রক্রিয়াটি হ'ল ফাজি স্ট্রিং ম্যাচিং। অনেক ক্ষেত্রে এটির মধ্যে শব্দ বা বাক্যাংশগুলি সনাক্ত করা জড়িত যা একে অপরের সাথে সর্বাধিক অনুরূপ। এই নিবন্ধটি ফাজি স্ট্রিং ম্যাচিং সমস্যার অভ্যন্তরীণ সমাধান এবং বিভিন্ন ধরণের সমস্যা সমাধানে এর কার্যকারিতা বর্ণনা করে যা আমাদের আগে এমন ক্লান্তিকর ব্যবহারকারীর জড়িত থাকা প্রয়োজনীয় কাজগুলিকে স্বয়ংক্রিয় করতে সক্ষম করতে পারে।
ভূমিকা
মূলত अस्पष्ट স্ট্রিং ম্যাচিংয়ের প্রয়োজনটি উপসাগরীয় মেক্সিকো ভ্যালিডেটর সরঞ্জামটি বিকাশকালে হয়েছিল। যা ছিল তা হ'ল মেক্সিকো তেল রিগ এবং প্ল্যাটফর্মগুলির জ্ঞাত উপসাগরগুলির একটি ডাটাবেস, এবং বীমা কেনার লোকেরা আমাদের তাদের সম্পদগুলি সম্পর্কে কিছু খারাপভাবে টাইপ করা তথ্য দেয় এবং আমাদের এটি পরিচিত প্ল্যাটফর্মের ডাটাবেসের সাথে মেলে। যখন খুব অল্প তথ্য দেওয়া হয়েছিল, তখন আমরা যা করতে পারি তা হ'ল একজন আন্ডারাইটারের উপর নির্ভর করা হয় যার সাথে তারা উল্লেখ করেছিল এবং "যথাযথ তথ্য" কল করতে পারে recognize এই যেখানে এই স্বয়ংক্রিয় সমাধানটি কাজে আসে।
আমি একদিন অদ্ভুত স্ট্রিং মেলানোর পদ্ধতিগুলি গবেষণা করে কাটিয়েছি এবং অবশেষে উইকিপিডিয়ায় খুব দরকারী লেভেনস্টেইন দূরত্বের অ্যালগরিদমকে হোঁচট খেয়েছি।
বাস্তবায়ন
এর পিছনে তত্ত্বটি পড়ার পরে, আমি প্রয়োগ করেছি এবং এটিটিকে অনুকূল করার উপায় খুঁজে পেয়েছি। আমার কোডটি ভিবিএ-তে কেমন দেখাচ্ছে:
'Calculate the Levenshtein Distance between two strings (the number of insertions,
'deletions, and substitutions needed to transform the first string into the second)
Public Function LevenshteinDistance(ByRef S1 As String, ByVal S2 As String) As Long
Dim L1 As Long, L2 As Long, D() As Long 'Length of input strings and distance matrix
Dim i As Long, j As Long, cost As Long 'loop counters and cost of substitution for current letter
Dim cI As Long, cD As Long, cS As Long 'cost of next Insertion, Deletion and Substitution
L1 = Len(S1): L2 = Len(S2)
ReDim D(0 To L1, 0 To L2)
For i = 0 To L1: D(i, 0) = i: Next i
For j = 0 To L2: D(0, j) = j: Next j
For j = 1 To L2
For i = 1 To L1
cost = Abs(StrComp(Mid$(S1, i, 1), Mid$(S2, j, 1), vbTextCompare))
cI = D(i - 1, j) + 1
cD = D(i, j - 1) + 1
cS = D(i - 1, j - 1) + cost
If cI <= cD Then 'Insertion or Substitution
If cI <= cS Then D(i, j) = cI Else D(i, j) = cS
Else 'Deletion or Substitution
If cD <= cS Then D(i, j) = cD Else D(i, j) = cS
End If
Next i
Next j
LevenshteinDistance = D(L1, L2)
End Function
সহজ, দ্রুত এবং একটি খুব দরকারী মেট্রিক। এটি ব্যবহার করে, আমি দুটি স্ট্রিংয়ের মিলের জন্য মূল্যায়ন করার জন্য দুটি পৃথক মেট্রিক তৈরি করেছি। একটিকে আমি "ভ্যালুফ্রেস" বলি এবং একজনকে আমি "ভ্যালু ওয়ার্ডস" বলি। ভ্যালুফ্রেস হ'ল দুটি বাক্যাংশের মধ্যে লেভেনস্টেইন দূরত্ব, এবং মান ওয়ার্ডস স্প্রেস, ড্যাশস এবং আপনার পছন্দসই যে কোনও কিছুর উপর ভিত্তি করে পৃথক শব্দের মধ্যে স্ট্রিংকে বিভক্ত করে এবং প্রতিটি শব্দের সাথে একে অপরের শব্দের সাথে তুলনা করে সংক্ষিপ্ততম সংস্থান করে ming লেভেনস্টাইন দূরত্ব যেকোন দুটি শব্দকে সংযুক্ত করে। মূলত, এটি পরিমাপ করে যে একটি 'শব্দগুচ্ছ'-এ তথ্য সত্যই অন্যথায় অন্তর্ভুক্ত রয়েছে, ঠিক যেমন শব্দ-ভিত্তিক ক্রমান্বয়ে। আমি পার্শ্ব প্রকল্প হিসাবে কিছু দিন অতিবাহিত করেছি, ডিলিমিটরের উপর ভিত্তি করে স্ট্রিংকে বিভক্ত করার সবচেয়ে কার্যকর উপায় নিয়ে আসছি।
মান ওয়ার্ডস, ভ্যালুফ্রেস এবং স্প্লিট ফাংশন:
Public Function valuePhrase#(ByRef S1$, ByRef S2$)
valuePhrase = LevenshteinDistance(S1, S2)
End Function
Public Function valueWords#(ByRef S1$, ByRef S2$)
Dim wordsS1$(), wordsS2$()
wordsS1 = SplitMultiDelims(S1, " _-")
wordsS2 = SplitMultiDelims(S2, " _-")
Dim word1%, word2%, thisD#, wordbest#
Dim wordsTotal#
For word1 = LBound(wordsS1) To UBound(wordsS1)
wordbest = Len(S2)
For word2 = LBound(wordsS2) To UBound(wordsS2)
thisD = LevenshteinDistance(wordsS1(word1), wordsS2(word2))
If thisD < wordbest Then wordbest = thisD
If thisD = 0 Then GoTo foundbest
Next word2
foundbest:
wordsTotal = wordsTotal + wordbest
Next word1
valueWords = wordsTotal
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' SplitMultiDelims
' This function splits Text into an array of substrings, each substring
' delimited by any character in DelimChars. Only a single character
' may be a delimiter between two substrings, but DelimChars may
' contain any number of delimiter characters. It returns a single element
' array containing all of text if DelimChars is empty, or a 1 or greater
' element array if the Text is successfully split into substrings.
' If IgnoreConsecutiveDelimiters is true, empty array elements will not occur.
' If Limit greater than 0, the function will only split Text into 'Limit'
' array elements or less. The last element will contain the rest of Text.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function SplitMultiDelims(ByRef Text As String, ByRef DelimChars As String, _
Optional ByVal IgnoreConsecutiveDelimiters As Boolean = False, _
Optional ByVal Limit As Long = -1) As String()
Dim ElemStart As Long, N As Long, M As Long, Elements As Long
Dim lDelims As Long, lText As Long
Dim Arr() As String
lText = Len(Text)
lDelims = Len(DelimChars)
If lDelims = 0 Or lText = 0 Or Limit = 1 Then
ReDim Arr(0 To 0)
Arr(0) = Text
SplitMultiDelims = Arr
Exit Function
End If
ReDim Arr(0 To IIf(Limit = -1, lText - 1, Limit))
Elements = 0: ElemStart = 1
For N = 1 To lText
If InStr(DelimChars, Mid(Text, N, 1)) Then
Arr(Elements) = Mid(Text, ElemStart, N - ElemStart)
If IgnoreConsecutiveDelimiters Then
If Len(Arr(Elements)) > 0 Then Elements = Elements + 1
Else
Elements = Elements + 1
End If
ElemStart = N + 1
If Elements + 1 = Limit Then Exit For
End If
Next N
'Get the last token terminated by the end of the string into the array
If ElemStart <= lText Then Arr(Elements) = Mid(Text, ElemStart)
'Since the end of string counts as the terminating delimiter, if the last character
'was also a delimiter, we treat the two as consecutive, and so ignore the last elemnent
If IgnoreConsecutiveDelimiters Then If Len(Arr(Elements)) = 0 Then Elements = Elements - 1
ReDim Preserve Arr(0 To Elements) 'Chop off unused array elements
SplitMultiDelims = Arr
End Function
মিলের পরিমাপ
এই দুটি মেট্রিক ব্যবহার করে এবং তৃতীয়টি যা কেবল দুটি স্ট্রিংয়ের মধ্যকার দূরত্বের গণনা করে, আমার বেশ কয়েকটি ভেরিয়েবল রয়েছে যা আমি সর্বোচ্চ সংখ্যক ম্যাচ অর্জনের জন্য একটি অপ্টিমাইজেশন অ্যালগরিদম চালাতে পারি। অস্পষ্ট স্ট্রিং ম্যাচিং হ'ল নিজেই, একটি अस्पष्ट বিজ্ঞান, এবং তাই স্ট্রিংয়ের মিলটি পরিমাপ করার জন্য রৈখিক স্বাধীন মেট্রিক্স তৈরি করে এবং আমরা একে অপরের সাথে মেলে থাকতে চাই এমন স্ট্রিংগুলির একটি পরিচিত সেট পেয়ে আমরা আমাদের নির্দিষ্ট শৈলীর জন্য পরামিতিগুলি খুঁজে পেতে পারি that স্ট্রিং, সেরা अस्पष्ट ম্যাচের ফলাফল দিন give
প্রাথমিকভাবে, মেট্রিকের লক্ষ্য হ'ল সঠিক মিলের জন্য কম অনুসন্ধানের মান এবং ক্রমবর্ধমান অনুমতিপ্রাপ্ত ব্যবস্থাগুলির জন্য অনুসন্ধানের মান বাড়ানো। একটি অযৌক্তিক ক্ষেত্রে, ভাল সংজ্ঞায়িত ক্রমানুসারে একটি সেট ব্যবহার করে সংজ্ঞা দেওয়া মোটামুটি সহজ ছিল এবং চূড়ান্ত সূত্রটি ইঞ্জিনিয়ারিং করা হয়েছিল যাতে তারা পছন্দসই হিসাবে অনুসন্ধানের মূল্যবোধের ফলাফল বাড়িয়ে তোলে।
উপরের স্ক্রিনশটটিতে, আমি অনুসন্ধান শব্দ এবং ফলাফলের মধ্যে আমার বোধকৃত পার্থক্যের জন্য সুন্দরভাবে বোধ করেছি এমন কিছু নিয়ে আসার জন্য আমার তাত্পর্যপূর্ণ টুইটটি করেছি। Value Phrase
উপরের স্প্রেডশিটে আমি যে বৌদ্ধিক ব্যবহার করেছি তা ছিল =valuePhrase(A2,B2)-0.8*ABS(LEN(B2)-LEN(A2))
। আমি দুটি "বাক্যাংশ" এর দৈর্ঘ্যের পার্থক্যের 80% দ্বারা লেভেনস্টিন দূরত্বের কার্যকারিতা কার্যকরভাবে হ্রাস করেছিলাম। এইভাবে, "বাক্যাংশগুলি" যার একই দৈর্ঘ্য রয়েছে সম্পূর্ণ শাস্তি ভোগ করে, তবে "বাক্যাংশগুলি" যার মধ্যে 'অতিরিক্ত তথ্য' থাকে (দীর্ঘ) তবে এগুলি বাদ দিয়ে বেশিরভাগ ক্ষেত্রে একই অক্ষরগুলি হ্রাস পায় শাস্তি ভোগ করে। আমি Value Words
ফাংশনটি যেমনটি ব্যবহার করেছি এবং তারপরে আমার চূড়ান্ত SearchVal
হিউরিস্টিক হিসাবে সংজ্ঞায়িত হয়েছিল=MIN(D2,E2)*0.8+MAX(D2,E2)*0.2
- একটি ওজনযুক্ত গড়। দুটি স্কোরগুলির মধ্যে যেটি কম ছিল তার ওজন ৮০%, এবং উচ্চতর স্কোরের ২০% got এটি কেবলমাত্র একটি তাত্পর্যপূর্ণ ছিল যা ভাল ম্যাচের হার পাওয়ার জন্য আমার ব্যবহারের ক্ষেত্রে উপযুক্ত। এই ওজনগুলি এমন এক জিনিস যা তাদের পরীক্ষার ডেটা দিয়ে সেরা ম্যাচের হার পাওয়ার জন্য কোনও টুইট করতে পারে।
আপনি দেখতে পাচ্ছেন, শেষ দুটি মেট্রিকগুলি, যা ফাজি স্ট্রিংয়ের সাথে মিলে যাওয়া মেট্রিকগুলি ইতিমধ্যে একটি স্বভাবযুক্ত প্রবণতা রয়েছে যা মেলে (ডায়াগোনালটি নীচে) মেলে বোঝানো স্ট্রিংগুলিকে কম স্কোর দেয়। এটা খুব ভাল.
অ্যাপ্লিকেশন
अस्पष्ट মিলের অপ্টিমাইজেশনের অনুমতি দিতে, আমি প্রতিটি মেট্রিকের ওজন করি। যেমন, अस्पष्ट স্ট্রিং ম্যাচের প্রতিটি অ্যাপ্লিকেশন প্যারামিটারগুলিকে আলাদাভাবে ওজন করতে পারে। যে সূত্রটি চূড়ান্ত স্কোরকে সংজ্ঞায়িত করে তা হ'ল মেট্রিক্স এবং তাদের ওজনের একটি সহজ সংমিশ্রণ:
value = Min(phraseWeight*phraseValue, wordsWeight*wordsValue)*minWeight
+ Max(phraseWeight*phraseValue, wordsWeight*wordsValue)*maxWeight
+ lengthWeight*lengthValue
একটি অপ্টিমাইজেশন অ্যালগরিদম ব্যবহার করে (নিউরাল নেটওয়ার্কটি এখানে সেরা কারণ এটি একটি বিচ্ছিন্ন, বহু-মাত্রিক সমস্যা), এখন লক্ষ্যটি ম্যাচের সংখ্যা সর্বাধিক করার জন্য। আমি একটি ফাংশন তৈরি করেছি যা একে অপরের সাথে প্রতিটি সেটের সঠিক মিলগুলির সংখ্যা সনাক্ত করে, যা এই চূড়ান্ত স্ক্রিনশটে দেখা যাবে। সর্বনিম্ন স্কোরটি মিলে যাওয়া স্ট্রিংটি নির্ধারণ করা হলে একটি কলাম বা সারি একটি পয়েন্ট পায় এবং সর্বনিম্ন পয়েন্টের জন্য টাই থাকলে আংশিক পয়েন্ট দেওয়া হয় এবং বাঁধা ম্যাচের স্ট্রিংগুলির মধ্যে সঠিক মিলটি হয়। আমি তখন এটি অপ্টিমাইজড। আপনি দেখতে পাচ্ছেন যে একটি সবুজ ঘর হল কলামটি বর্তমান সারিটির সাথে সর্বাধিক মেলে এবং ঘরের চারপাশে একটি নীল বর্গ হল সারিটি বর্তমান কলামের সাথে সবচেয়ে ভাল মেলে। নীচের কোণায় থাকা স্কোর মোটামুটি সফল ম্যাচের সংখ্যা এবং এটিই আমাদের অপ্টিমাইজেশান সমস্যাটি সর্বাধিকতর করতে বলি।
অ্যালগরিদম একটি দুর্দান্ত সাফল্য ছিল, এবং সমাধান পরামিতি এই ধরণের সমস্যা সম্পর্কে অনেক কিছু বলে। আপনি লক্ষ্য করবেন যে অপটিমাইজড স্কোরটি ছিল 44, এবং সর্বোত্তম সম্ভাব্য স্কোর 48। শেষের 5 টি কলামগুলি ডিকয়েস এবং সারির মানগুলির সাথে কোনও মিল নেই। সেখানে যত বেশি ডিকো হবে, সর্বোত্তম ম্যাচটি খুঁজে পাওয়া স্বাভাবিকভাবেই কঠিন।
এই বিশেষ মিলের ক্ষেত্রে, স্ট্রিংগুলির দৈর্ঘ্য অপ্রাসঙ্গিক, কারণ আমরা সংক্ষিপ্তসারগুলি প্রত্যাশা করি যা দীর্ঘ শব্দগুলির প্রতিনিধিত্ব করে, সুতরাং দৈর্ঘ্যের সর্বোত্তম ওজন -0.3, যার অর্থ আমরা দৈর্ঘ্যের পরিবর্তিত স্ট্রিংগুলিকে শাস্তি দিই না। আমরা এই সংক্ষিপ্ত বিবরণগুলির প্রত্যাশায় স্কোর হ্রাস করি, শব্দহীন ম্যাচগুলিকে আটকানোতে আংশিক শব্দের মিলের জন্য আরও জায়গা দেই যার জন্য স্ট্রিংটি সংক্ষিপ্ত হওয়ায় কম বিকল্পের প্রয়োজন হয়।
শব্দটি ওজন ১.০ এবং বাক্যাংশের ওজন মাত্র ০.০, যার অর্থ আমরা একটি স্ট্রিং থেকে হারিয়ে যাওয়া পুরো শব্দকে শাস্তি দিয়ে থাকি এবং পুরো বাক্যাংশটি অক্ষত থাকার জন্য আরও মূল্যবান বলে মনে করি। এটি দরকারী কারণ এই স্ট্রিংগুলির একটিতে প্রচলিত একটি শব্দ রয়েছে (বিপদ) যেখানে আসলে যা গুরুত্বপূর্ণ তা হল সংমিশ্রণটি (অঞ্চল এবং বিপদ) বজায় রাখা হয় কিনা।
পরিশেষে, সর্বনিম্ন ওজন 10 এবং সর্বোচ্চ ওজন 1 এ অনুকূলিত করা হয়েছে এর অর্থ কী যে দুটি স্কোরের সেরা (মান বাক্য এবং মান শব্দের) খুব ভাল না হলে, ম্যাচটি দুর্দান্তভাবে দণ্ডিত হয়, তবে আমরা ডন করি না দুটি স্কোরের মধ্যে সবচেয়ে খারাপটিকে শাস্তি দেবে না। মূলত, প্রয়োজন এই রাখে জোর পারেন valueWord বা valuePhrase একটি ভাল স্কোর, তবে দুটো একসাথে আছে। এক ধরণের "আমরা যা পেতে পারি তা গ্রহণ করুন" মানসিকতা।
এই 5 টি ওজনের অপ্টিমাইজড মানটি কীভাবে ফাজি স্ট্রিংয়ের মিলের ধরণের ঘটনার কথা বলে তা সত্যিই আকর্ষণীয়। অস্পষ্ট স্ট্রিং মিলের সম্পূর্ণ ভিন্ন ব্যবহারিক ক্ষেত্রে, এই পরামিতিগুলি খুব আলাদা। আমি এ পর্যন্ত এটি 3 পৃথক অ্যাপ্লিকেশন জন্য ব্যবহার করেছি।
চূড়ান্ত অপ্টিমাইজেশনে অব্যবহৃত অবস্থায়, একটি বেঞ্চমার্কিং শীট স্থাপন করা হয়েছিল যা তির্যক নীচে সমস্ত নিখুঁত ফলাফলের জন্য কলামগুলির সাথে নিজের সাথে মেলে এবং ব্যবহারকারীর প্যারামিটারগুলি যে হারে 0 থেকে আলাদা হয় তা নিয়ন্ত্রণ করতে দেয় এবং অনুসন্ধান বাক্যাংশের মধ্যে সহজাত মিলগুলি লক্ষ করে ( যা তাত্ত্বিকভাবে ফলাফলগুলিতে মিথ্যা ইতিবাচক অফসেট করতে ব্যবহৃত হতে পারে)
আরও অ্যাপ্লিকেশন
এই সমাধানটি যে কোনও জায়গায় ব্যবহার করার সম্ভাবনা রয়েছে যেখানে ব্যবহারকারী কোনও কম্পিউটার সিস্টেমের কাছে স্ট্রিংগুলির সেটগুলিতে একটি স্ট্রিং সনাক্ত করতে চান যেখানে কোনও নিখুঁত মিল নেই। (স্ট্রিংগুলির জন্য আনুমানিক ম্যাচের ভিউলআপের মতো)।
সুতরাং এগুলি থেকে আপনার কী গ্রহণ করা উচিত তা হ'ল লেভেনস্টেইন দূরত্বের অ্যালগরিদমের প্রয়োগের সাথে আপনি সম্ভবত উচ্চ স্তরের হিউরিস্টিক্সের সংমিশ্রণটি (অন্য বাক্যাংশের একটি বাক্যাংশ থেকে উভয় বাক্যাংশের দৈর্ঘ্য ইত্যাদি) ব্যবহার করতে চান) যেহেতু "সেরা" ম্যাচটি কোনটি সিদ্ধান্ত নেওয়াকে হিউরিস্টিক (ফাজি) দৃ determination়তা - আপনার মিলের সাথে মিল নির্ধারণ করতে যে কোনও মেট্রিকের জন্য ওজনের একটি সেট নিয়ে আসতে হবে।
হিউরিস্টিকস এবং ওজনগুলির উপযুক্ত সেট সহ, আপনার তুলনা প্রোগ্রামটি আপনার যে সিদ্ধান্ত নেবে তাড়াতাড়ি করে সিদ্ধান্ত নেবে।