मुझे लगभग एक साल पहले इस समस्या के साथ प्रस्तुत किया गया था जब यह देखने के लिए आया था कि उपयोगकर्ता विविध जानकारी के डेटाबेस में एक तेल रिग के बारे में जानकारी दर्ज करता है। लक्ष्य कुछ प्रकार की फजी स्ट्रिंग खोज करना था जो सबसे आम तत्वों के साथ डेटाबेस प्रविष्टि की पहचान कर सकता था।
लेवेन्शिन दूरी एल्गोरिथ्म को लागू करने से जुड़े अनुसंधान का एक हिस्सा , जो यह निर्धारित करता है कि एक स्ट्रिंग या वाक्यांश को दूसरे स्ट्रिंग या वाक्यांश में बदलने के लिए कितने परिवर्तन किए जाने चाहिए।
मैं जिस कार्यान्वयन के साथ आया था वह अपेक्षाकृत सरल था, और इसमें दो वाक्यांशों की लंबाई, प्रत्येक वाक्यांश के बीच परिवर्तनों की संख्या, और क्या प्रत्येक शब्द लक्ष्य प्रविष्टि में पाया जा सकता है, की एक भारित तुलना शामिल थी।
लेख एक निजी साइट पर है, इसलिए मैं यहां संबंधित सामग्री को जोड़ने की पूरी कोशिश करूंगा:
फजी स्ट्रिंग मिलान दो शब्दों या वाक्यांशों की समानता का मानव जैसा प्रदर्शन करने की प्रक्रिया है। कई मामलों में, इसमें उन शब्दों या वाक्यांशों की पहचान करना शामिल है जो एक-दूसरे के समान हैं। इस लेख में फजी स्ट्रिंग मिलान समस्या और विभिन्न प्रकार की समस्याओं को हल करने में इसकी उपयोगिता के बारे में इन-हाउस समाधान का वर्णन किया गया है जो हमें उन कार्यों को स्वचालित करने की अनुमति दे सकता है जो पहले थकाऊ उपयोगकर्ता की भागीदारी की आवश्यकता थी।
परिचय
मूल रूप से फजी स्ट्रिंग मिलान करने की आवश्यकता मेक्सिको की खाड़ी के उपकरण के विकास के समय के बारे में आई थी। जो अस्तित्व में था वह मेक्सिको ऑयल रिग्स और प्लेटफ़ॉर्म के ज्ञात खाड़ी का एक डेटाबेस था, और बीमा खरीदने वाले लोग हमें अपनी संपत्ति के बारे में कुछ बुरी तरह से टाइप की गई जानकारी देंगे और हमें इसे ज्ञात प्लेटफार्मों के डेटाबेस से मेल खाना था। जब बहुत कम जानकारी दी गई थी, तो हम जो सबसे अच्छा कर सकते थे, वह एक अंडरराइटर पर भरोसा करने के लिए किया गया था, जिसे वे उचित जानकारी के लिए बुला रहे थे। यह वह जगह है जहां यह स्वचालित समाधान काम में आता है।
मैंने एक दिन फजी स्ट्रिंग मिलान के तरीकों पर शोध किया, और अंततः विकिपीडिया पर बहुत उपयोगी लेवेन्सहाइट दूरी एल्गोरिथ्म पर ठोकर खाई।
कार्यान्वयन
इसके पीछे के सिद्धांत के बारे में पढ़ने के बाद, मैंने इसे लागू करने और इसे अनुकूलित करने के तरीके ढूंढे। यह मेरा कोड VBA में कैसा दिखता है:
'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
सरल, शीघ्र और बहुत उपयोगी मीट्रिक। इसका उपयोग करते हुए, मैंने दो तारों की समानता के मूल्यांकन के लिए दो अलग-अलग मीट्रिक बनाए। एक को मैं "valuePhrase" कहता हूं और एक को मैं "valueScript" कहता हूं। valuePhrase दो वाक्यांशों के बीच सिर्फ लेवेंसहाइट दूरी है, और मानदंड अलग-अलग शब्दों में स्ट्रिंग को विभाजित करते हैं, जैसे कि सीमांकक के आधार पर रिक्त स्थान, डैश, और कुछ भी जो आप चाहते हैं, और प्रत्येक शब्द की एक दूसरे से तुलना करते हैं, सबसे छोटा संक्षेप। किसी भी दो शब्दों को जोड़ते हुए लेवेन्सेटिन दूरी। अनिवार्य रूप से, यह मापता है कि क्या एक 'वाक्यांश' में जानकारी वास्तव में दूसरे में निहित है, बस एक शब्द-वार क्रमपरिवर्तन के रूप में। मैंने एक पक्ष परियोजना के रूप में कुछ दिन बिताए हैं जो कि एक सबसे महत्वपूर्ण तरीका है जो कि सीमांकक के आधार पर एक स्ट्रिंग को विभाजित करने के लिए संभव है।
मान, मान, मान और स्प्लिट फ़ंक्शन:
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
समानता के उपाय
इन दो मैट्रिक्स का उपयोग करना, और एक तिहाई जो केवल दो तारों के बीच की दूरी की गणना करता है, मेरे पास चर की एक श्रृंखला है जिसे मैं सबसे बड़ी संख्या में मैच प्राप्त करने के लिए एक अनुकूलन एल्गोरिथ्म चला सकता हूं। फजी स्ट्रिंग मिलान, अपने आप में, एक फजी विज्ञान है, और इसलिए स्ट्रिंग समानता को मापने के लिए रैखिक स्वतंत्र मैट्रिक्स बनाकर, और तार के एक ज्ञात सेट के साथ हम एक दूसरे से मेल खाना चाहते हैं, हम उन मापदंडों को पा सकते हैं, जो हमारी विशिष्ट शैलियों के लिए हैं तार, सबसे अच्छा फजी मैच परिणाम दे।
प्रारंभ में, मीट्रिक का लक्ष्य एक सटीक मैच के लिए कम खोज मूल्य और तेजी से अनुमत उपायों के लिए खोज मूल्यों में वृद्धि करना था। एक अव्यवहारिक मामले में, यह अच्छी तरह से परिभाषित क्रमपरिवर्तन के एक सेट का उपयोग करके परिभाषित करने के लिए काफी आसान था, और अंतिम सूत्र को इंजीनियरिंग करना जैसे कि उनके पास वांछित के रूप में खोज मूल्यों में वृद्धि हुई थी।
ऊपर दिए गए स्क्रीनशॉट में, मैंने अपने उत्तराधिकारी को कुछ ऐसा करने के लिए कहा, जिसे मैंने खोज शब्द और परिणाम के बीच मेरे कथित अंतर को बारीकी से महसूस किया। 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
- एक भारित औसत। दोनों में से जो भी स्कोर कम था उसका वजन 80% और उच्च स्कोर का 20% था। यह सिर्फ एक अनुमान है कि एक अच्छी मैच दर पाने के लिए मेरे उपयोग के मामले में अनुकूल था। ये वज़न कुछ ऐसे हैं कि एक तो अपने परीक्षण डेटा के साथ सबसे अच्छा मैच दर पाने के लिए tweak कर सकते हैं।
जैसा कि आप देख सकते हैं, अंतिम दो मैट्रिक्स, जो फजी स्ट्रिंग मिलान मैट्रिक्स हैं, पहले से ही तार के लिए कम स्कोर देने की एक प्राकृतिक प्रवृत्ति है जो मिलान (विकर्ण के नीचे) के लिए होती है। यह बहुत अच्छा है।
आवेदन
फजी मिलान के अनुकूलन की अनुमति देने के लिए, मैं प्रत्येक मीट्रिक का वजन करता हूं। जैसे, फजी स्ट्रिंग मैच के हर एप्लिकेशन मापदंडों को अलग तरीके से वजन कर सकते हैं। अंतिम स्कोर को परिभाषित करने वाला सूत्र केवल मैट्रिक्स और उनके भार का संयोजन है:
value = Min(phraseWeight*phraseValue, wordsWeight*wordsValue)*minWeight
+ Max(phraseWeight*phraseValue, wordsWeight*wordsValue)*maxWeight
+ lengthWeight*lengthValue
एक अनुकूलन एल्गोरिथ्म का उपयोग करना (तंत्रिका नेटवर्क यहां सबसे अच्छा है क्योंकि यह एक असतत, बहु-विषयक समस्या है), लक्ष्य अब मैचों की संख्या को अधिकतम करने के लिए है। मैंने एक फ़ंक्शन बनाया जो प्रत्येक सेट के सही मैचों की संख्या का एक दूसरे से पता लगाता है, जैसा कि इस अंतिम स्क्रीनशॉट में देखा जा सकता है। एक स्तंभ या पंक्ति को एक बिंदु मिलता है यदि निम्नतम स्कोर को स्ट्रिंग प्रदान किया जाता है जिसे मिलान किया जाना था, और आंशिक अंक दिए गए हैं यदि सबसे कम स्कोर के लिए एक टाई है, और सही मिलान बंधे हुए तार के बीच है। मैंने तब इसे अनुकूलित किया। आप देख सकते हैं कि एक ग्रीन सेल वह कॉलम है जो वर्तमान पंक्ति से सबसे अच्छा मेल खाता है, और सेल के चारों ओर एक नीला वर्ग वह पंक्ति है जो वर्तमान स्तंभ से सर्वोत्तम रूप से मेल खाता है। निचले कोने में स्कोर लगभग सफल मैचों की संख्या है और यही हम अपनी अनुकूलन समस्या को अधिकतम करने के लिए कहते हैं।
एल्गोरिथ्म एक अद्भुत सफलता थी, और समाधान पैरामीटर इस प्रकार की समस्या के बारे में बहुत कुछ कहते हैं। आप देखेंगे कि अनुकूलित स्कोर 44 था, और सबसे अच्छा संभव स्कोर 48 है। अंत में 5 कॉलम डिकॉय हैं, और पंक्ति मानों में इसका कोई मेल नहीं है। जितना अधिक डिकॉय होगा, उतना ही स्वाभाविक रूप से सबसे अच्छा मैच ढूंढना होगा।
इस विशेष मिलान मामले में, स्ट्रिंग्स की लंबाई अप्रासंगिक है, क्योंकि हम ऐसे संक्षिप्तीकरण की उम्मीद कर रहे हैं जो अधिक शब्दों का प्रतिनिधित्व करते हैं, इसलिए लंबाई के लिए इष्टतम वजन -0.3 है, जिसका अर्थ है कि हम उन स्ट्रिंग्स को दंडित नहीं करते हैं जो लंबाई में भिन्न होते हैं। हम इन संक्षिप्ताक्षरों की प्रत्याशा में स्कोर को कम करते हैं, गैर-शब्द मिलानों के लिए आंशिक शब्द मिलानों के लिए और अधिक कमरा देते हैं जिन्हें केवल कम प्रतिस्थापन की आवश्यकता होती है क्योंकि स्ट्रिंग कम होती है।
शब्द का वजन 1.0 है, जबकि वाक्यांश का वजन केवल 0.5 है, जिसका अर्थ है कि हम एक स्ट्रिंग से गायब पूरे शब्दों को दंडित करते हैं और पूरे वाक्यांश को अधिक महत्व देते हैं। यह उपयोगी है क्योंकि इनमें से बहुत सारे तार में एक शब्द सामान्य (पेरिल) है जहां वास्तव में क्या मायने रखता है कि संयोजन (क्षेत्र और जोखिम) बना हुआ है या नहीं।
अंत में, न्यूनतम वजन 10 पर अनुकूलित किया जाता है और अधिकतम वजन 1. पर होता है। इसका क्या मतलब है कि अगर दो अंकों में से सबसे अच्छा (मूल्य वाक्यांश और मूल्य शब्द) बहुत अच्छा नहीं है, तो मैच बहुत दंडित किया जाता है, लेकिन हम डॉन 'दो अंकों में से सबसे खराब दंड। अनिवार्य रूप से, यह या तो आवश्यकता पर जोर देता है तो वैल्यूवार्ड या वैल्यूफेयर की , ताकि अच्छा स्कोर हो, लेकिन दोनों नहीं। एक प्रकार का "हम क्या प्राप्त कर सकते हैं" मानसिकता लें।
यह वास्तव में आकर्षक है कि इन 5 वज़न का अनुकूलित मूल्य फ़ज़ी स्ट्रिंग मिलान के प्रकार के बारे में कहता है। फजी स्ट्रिंग मिलान के पूरी तरह से अलग व्यावहारिक मामलों के लिए, ये पैरामीटर बहुत अलग हैं। मैंने अब तक 3 अलग-अलग अनुप्रयोगों के लिए इसका उपयोग किया है।
अंतिम अनुकूलन में अप्रयुक्त होने के दौरान, एक बेंचमार्किंग शीट स्थापित की गई थी जो तिरछे नीचे सभी सही परिणामों के लिए स्तंभों से मेल खाती है, और उपयोगकर्ता को मापदंडों को बदलने की अनुमति देती है जिस पर स्कोर 0 से भिन्न होता है, और वाक्यांशों के बीच सहज समानताएं नोट करें ( जो सिद्धांत में इस्तेमाल किया जा सकता है परिणामों में झूठी सकारात्मकता की भरपाई करने के लिए)
आगे के अनुप्रयोग
इस समाधान में कहीं भी उपयोग किए जाने की क्षमता है जहां उपयोगकर्ता कंप्यूटर सिस्टम की इच्छा रखता है ताकि स्ट्रिंग के एक सेट में एक स्ट्रिंग की पहचान हो सके जहां कोई पूर्ण मिलान नहीं है। (तार के लिए एक अनुमानित मैच की तरह)।
तो आपको इससे क्या लेना चाहिए, क्या यह है कि आप शायद लेवेन्सहाइट दूरी एल्गोरिथ्म के कार्यान्वयन के साथ-साथ उच्च स्तर के आंकड़ों के संयोजन (दूसरे वाक्यांश में एक वाक्यांश से शब्द, दोनों वाक्यांशों की लंबाई, आदि) का उपयोग करना चाहते हैं। क्योंकि यह निर्णय लेना कि "सबसे अच्छा" मैच कौन सा हैजिस्टिक (फजी) निर्धारण है - आपको समानता निर्धारित करने के लिए आने वाले किसी भी मेट्रिक्स के लिए वजन के एक सेट के साथ आना होगा।
ह्यूरिस्टिक्स और वेट के उपयुक्त सेट के साथ, आप अपने तुलनात्मक कार्यक्रम जल्दी से निर्णय लेंगे जो आपने किया होगा।