Dize benzerliği için en iyi hangi algoritmayı kullanırsınız?


23

Adresleri temel alarak, çeşitli web sayfalarındaki içeriği benzersiz şekilde tanımlamak için bir eklenti tasarlıyorum.

Öyleyse şuna benzeyen bir adres alabilirim:

1 someawesome street, anytown, F100 211

daha sonra bu adresi biraz farklı bir biçimde bulabilirim.

1 someawesome street, F100 211,

veya belki de belirsiz

someawesome street F100

Bunlar teknik olarak aynı adres, ancak benzer düzeyde. A) arama yapmak için her adres için benzersiz bir tanımlayıcı oluşturmak ve b) çok benzer bir adresin ne zaman ortaya çıktığını bulmak.

Hangi algoritma / teknik / String metriklerine bakmalıyım? Levenshtein mesafesi bariz bir seçenek gibi gözükse de, burada kendilerini ödünç verecek başka bir yaklaşım varsa merak ediyorum.


"Levenshtein mesafesi" bir algoritma değildir.
gnasher729 13:16

Bazı temel ayrıştırma işlemlerini yapmadığınız sürece, ham Levenstein mesafesi o kadar iyi olmaz. En azından cadde, şehir adı vb. Olabilecek kelimeleri ve sokak numaraları veya posta kodları olabilecek kelimeleri tanımlamaya çalışmalısınız. O zaman belki Levenstein'ı gerçek yerler / sokak isimleriyle beslenen bazı istatistiksel bulanık eşleştiricilerle bunlara uygulayabilirsiniz. Kolay bir şey değil :)

7
@gnasher: Ama Levenshtein mesafeyi hesaplayan bir fonksiyon olan bir algoritma. Böyle bir fonksiyon olmadan, Levenshtein mesafesi sadece entelektüel bir meraktır.
Robert Harvey,

Burada örneklerle çok pratik bir açıklama buldum: algortihms karşılaştırması . Sonuç olarak, Levenstein'ın algoritması, dizenin uzunluğuna bağlı olduğundan, Jaro-Winkler benzerliğinin kullanılmasını önermektedir , bu nedenle karşılaştırmanın faydası yoktur.
Sandra Meneses

Yanıtlar:


14

Levenstein'ın algoritması , dizelerdeki ekleme, silme ve değiştirme sayısına dayanmaktadır.

Ne yazık ki, 2 karakterin aktarılması olan ortak bir yazım hatası hesaba katılmaz (örn. Başkalarına karşı çok kötü). Bu yüzden daha sağlam Damerau-Levenstein algoritmasını tercih ederim .

Uzaklığı tüm dizgelere uygulamanın iyi bir fikir olduğunu sanmıyorum çünkü zaman, dizgilerin uzunluğuyla aniden artmaktadır. Ancak, daha da kötüsü, ZIP gibi adres bileşenleri kaldırıldığında, tamamen farklı adresler daha iyi eşleşebilir ( çevrimiçi Levenshtein hesaplayıcısı kullanılarak ölçülür ):

1 someawesome street, anytown, F100 211       (reference) 
1 someawesome st.,anytown                     (difference of 15, same address)     
1 otherplaces street,anytown,F100211          (difference of 13, different ddress) 
1 sameawesome street, othertown, CA98200      (difference of 13, different ddress)
anytown, 1 someawesome street                 (28 different same address)
anytown, F100 211, 1 someawesome street       (37 different same address)

Bu etkiler daha kısa cadde adı için kötüleşme eğilimindedir.

Yani daha akıllı algoritmalar kullansanız iyi edersiniz. Örneğin, Arthur Ratz, CodeProject'de akıllı metin karşılaştırması için bir algoritma yayınladı . Algoritma bir mesafeyi basmaz (buna göre kesinlikle zenginleştirilebilir), ancak metin bloklarının taşınması gibi zor şeyleri tanımlar (örneğin, ilk örneğim ile son örneğim arasında şehir ve sokak arasındaki takas).

Böyle bir algoritma sizin durumunuz için çok genelse, o zaman gerçekten bileşenlerle çalışmalı ve sadece karşılaştırılabilir bileşenleri karşılaştırmalısınız. Dünyadaki herhangi bir adres biçimini ayrıştırmak istiyorsanız bu kolay bir şey değildir. Fakat eğer hedef daha spesifikse, ABD'yi söyleyin, kesinlikle uygulanabilir. Örneğin, "sokak", "st.", "Yer", "plazza" ve genel yazım hataları, adresin cadde bölümünü ortaya çıkarabilir; bunun başında, önceliği ilke sayı olacaktır. ZIP kodu, şehri bulmak için yardımcı olabilir veya alternatif olarak muhtemelen adresin son elemanıdır veya tahmin etmekten hoşlanmıyorsanız, şehir adlarının bir listesini arayabilirsiniz (örneğin, ücretsiz bir posta kodu veritabanı indirme). Daha sonra Damerau-Levenshtein'i yalnızca ilgili bileşenlere uygulayabilirsiniz.


Karşılaştırmadan önce her iki karşılaştırma dizesini de sıralamaya ne dersiniz? Bunun aktarıma yardımcı olabileceğini öğrendim.
openwonk


1

Öncelikle, adresleri almak için web sayfasını ayrıştırmanız gerekir, RegEx almak için yazılmıştır, ancak RegEx kullanarak adresleri ayrıştırmak çok zor olabilir. Muhtemelen olası adresleme biçimlerinin bir listesini ve bunlarla eşleşen harika bir veya daha fazla ifadeyi kullanmak zorunda kalacaksınız. Adres ayrıştırmaya çok aşina değilim, ancak benzer bir düşünce çizgisini izleyen bu soruya bir göz atmanızı tavsiye ederim: Serbest Biçimli Metin için Genel Adres Ayrıştırıcı.

Levenshtein mesafesi kullanışlıdır, ancak sadece adresini parçalara ayırdıktan sonra. Aşağıdaki adresleri göz önünde bulundurun. 123 someawesome st.ve 124 someawesome st.Bu adresler tamamen farklı yerlerdir, ancak Levenshtein uzaklıkları yalnızca 1'dir. Bu, aynı şekilde uygulanabilir 8th st.ve 9th st.Benzer sokak adları genellikle aynı web sayfasında görünmez, ancak duyulmamış değildir. Bir okulun web sayfasında, örneğin caddenin karşısındaki kütüphanenin adresi ya da birkaç blok ötedeki kilisenin adresi olabilir. Bu, Levenshtein mesafesinin kolayca kullanılabileceği tek verinin, cadde ile şehir arasındaki mesafe gibi 2 veri noktası arasındaki mesafe olduğu anlamına gelir.

Farklı alanları nasıl ayıracağımızı bulmak kadarıyla, adresleri kendilerine getirdiğimizde oldukça basit. Neyse ki çoğu adres çok özel biçimlerde geliyor, bir miktar RegEx sihirbazı ile bunları farklı veri alanlarına ayırmanız mümkün. Adres iyi biçimlendirilmemiş olsa bile, hala bazı umutlar var. Adresler her zaman (neredeyse) büyüklük sırasını izler. Adresiniz, ne kadar bilginin sağlandığına ve ne olduğuna bağlı olarak, bunun gibi doğrusal bir ızgara üzerinde bir yere düşmelidir:

StreetNumber < Street < City < State < Country

Adres, bir alandan bitişik olmayan bir alana atlarsa, nadiren olur. Sık sık, önce Sokaktan sonra Ülke'yi veya sonra Sokaktan sonra Şehir'i görmeyeceksiniz.


2
Bunun dışında, sokak adresleri normal değildir ve düzenli ifadelerle güvenilir bir şekilde çözümlenemez. Sadece serbest metne gömülmüşlerse kesinlikle doğru bir şekilde tanımlanamazlar. Elbette nerede aradığınızı biliyorsanız, farklı genel biçimlerle eşleştirmek için birkaç farklı normal ifade yazabilirsiniz.
Yararsız

@ Yararsız Bu doğru. Teoride yapılabilir, ancak içine koymak için gereken iş miktarını hafife aldım. Özellikle, potansiyel olarak daha iyi seçenekler mevcut olduğunda. Bunu yansıtacak cevabımı değiştirdim.
Ucenna

1

Dize benzerliği algoritmaları hakkında soruyorsunuz, ancak dizeleriniz adreslerdir. Adresleri Google Place Search gibi bir konum API’sine gönderir ve formatted_addresskarşılaştırma noktası olarak kullanırdım . Bu en doğru yaklaşım gibi görünüyor.

Bir API ile bulunamayan adres dizeleri için benzerlik algoritmalarına geri dönebilirsiniz.


1
+1 Dış kaynak kullanımı, böylece sizin için işi yapacak uzmanların gücüne sahip olursunuz. Orada birkaç servis sağlayıcı olduğu için Google olması gerekmez. Adres eşleştirme sizin temel işiniz değilse, bunu yaparken zamanınızı boşa harcamayın.
LoztInSpace

0

Yararlı olan ancak önceden yanıtlanmış olan önceden ayarlanmış bir veritabanını gerektiren tek bir algoritma:

Bir fonksiyon olarak satır düzenleme mesafesi, "bu iki kelimenin ne kadar farklı olduğunu" geri döndürür.

"Dogma" ve "dog" gibi bir kelimeyle, 3 değerini geri kazanırsınız (3 ekstra karakter için).

Veya "kedi" ve "şapka", 1 değerini geri alır (farklı bir karakter için).

(Kaynak: https://en.wikipedia.org/wiki/Edit_distance )


2
OP’lerin Levensthtein’dan bahsetmesinin avantajı nedir?
Christophe

-1

Nitekim bazı mesafe fonksiyonlarını kullanmak iyi bir yaklaşım gibi gözüküyor. Ancak sorun o zaman en önemsiz diziyi verilen adreslerden bulmaktır, bu önemsiz değildir.

Burada geniş bir algoritma kategorisini açıklıyorsunuz. En yakın komşu aramasını kontrol et

Bir yorumda belirtildiği gibi, adresin bileşenlerini (sokak adı, numara vb.) Ayırmanın bir yolunu bulursanız, görevi daha kolay hale getirir.


-1

LongestCommonSubsequence (Apache commons-text'den) adresleri denemek için başka bir yaklaşım olabilir. İkisinin benzerliğini " ortak eşik uzunluğu / maks (adres uzunlukları) " oranı olarak tanımlarsanız , tolerans eşiğini uygulayabilirsiniz - örneğin eşleşmeyi / eşleşmeyi tanımlamayacak olan 0.8. Bu yolla, " 1 güzel şehir, her yer " ve " 1 güzel şehir , her yer " gibi adreslerle eşleşmenize izin verir .

Süper hızlı bir algoritma değildir, bu nedenle karşılaştırmaları en aza indirmek için hızlı geri dönüşler uygulamak isteyebilirsiniz. Örnek olacaktır - posta kodları eşleşmiyorsa karşılaştırmadan kaçının veya yalnızca çıkartılan basamak sırası farklıysa karşılaştırma yapmaktan kaçının.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.