Algoritma apa yang sebaiknya Anda gunakan untuk kesamaan string?

23

Saya merancang plugin untuk mengidentifikasi konten secara unik di berbagai halaman web, berdasarkan alamat.

Jadi saya mungkin punya satu alamat yang terlihat seperti:

1 someawesome street, anytown, F100 211

nanti saya dapat menemukan alamat ini dalam format yang sedikit berbeda.

1 someawesome street, F100 211,

atau mungkin tidak jelas

someawesome street F100

Ini secara teknis alamat yang sama, tetapi dengan tingkat kesamaan. Saya ingin a) menghasilkan pengidentifikasi unik untuk setiap alamat untuk melakukan pencarian, dan b) mencari tahu kapan alamat yang sangat mirip muncul.

Algoritme / teknik / metrik string apa yang harus saya perhatikan? Jarak Levenshtein sepertinya pilihan yang jelas, tetapi ingin tahu apakah ada pendekatan lain yang akan membantu mereka.

Squiggs.
sumber
"Jarak Levenshtein" bukan algoritma.
gnasher729
Kecuali Anda memperkenalkan parsing dasar, jarak Levenstein mentah tidak akan menyenangkan. Anda harus mencoba untuk setidaknya mengidentifikasi kata-kata yang bisa berupa nama jalan, nama kota, dll dan kata-kata yang bisa berupa angka jalan atau kode pos. Maka mungkin menerapkan Levenstein pada ini dengan beberapa pencocokan fuzzy statistik diberi makan oleh tempat nyata / nama jalan. Bukan hal yang mudah :)
7
@gnasher: Tapi fungsi yang menghitung jarak Levenshtein adalah sebuah algoritma. Tanpa fungsi seperti itu, jarak Levenshtein hanyalah sebuah keingintahuan intelektual.
Robert Harvey
Saya menemukan penjelasan yang sangat praktis dengan contoh-contoh di sini: perbandingan algortihms . Sebagai kesimpulan, mereka merekomendasikan untuk menggunakan kesamaan Jaro-Winkler karena algoritma Levenstein tergantung pada panjang string, sehingga tidak berguna untuk membandingkan.
Sandra Meneses

Jawaban:

14

Algoritma Levenstein didasarkan pada jumlah penyisipan, penghapusan, dan penggantian dalam string.

Sayangnya itu tidak memperhitungkan kesalahan ejaan yang umum yang merupakan transposisi dari 2 karakter (mis. Someawesome vs someaewsome). Jadi saya lebih suka algoritma Damerau-Levenstein yang lebih kuat .

Saya tidak berpikir itu ide yang baik untuk menerapkan jarak pada string keseluruhan karena waktu meningkat secara tiba-tiba dengan panjang string dibandingkan. Tetapi yang lebih buruk lagi, ketika komponen alamat, seperti ZIP dihapus, alamat yang sama sekali berbeda mungkin lebih cocok (diukur menggunakan kalkulator Levenshtein online ):

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)

Efek ini cenderung memburuk untuk nama jalan yang lebih pendek.

Jadi sebaiknya Anda menggunakan algoritma yang lebih cerdas. Sebagai contoh, Arthur Ratz menerbitkan di CodeProject suatu algoritma untuk perbandingan teks cerdas. Algoritma tidak mencetak jarak (tentu dapat diperkaya sesuai), tetapi mengidentifikasi beberapa hal-hal sulit seperti memindahkan blok teks (misalnya swap antara kota dan jalan antara contoh pertama saya dan contoh terakhir saya).

Jika algoritma seperti itu terlalu umum untuk kasus Anda, Anda harus benar-benar bekerja dengan komponen dan hanya membandingkan komponen yang sebanding. Ini bukan hal yang mudah jika Anda ingin mem-parsing format alamat apa pun di dunia. Tetapi jika targetnya lebih spesifik, katakanlah AS, itu tentu layak. Misalnya, "jalan", "st.", "Tempat", "plazza", dan salah ejaan mereka yang biasa dapat mengungkapkan bagian jalan alamat tersebut, bagian utama yang pada prinsipnya akan menjadi nomor. Kode ZIP akan membantu untuk menemukan kota, atau alternatifnya mungkin adalah elemen terakhir dari alamat, atau jika Anda tidak suka menebak, Anda dapat mencari daftar nama kota (misalnya mengunduh basis data kode pos gratis). Anda kemudian dapat menerapkan Damerau-Levenshtein hanya pada komponen yang relevan.

Christophe
sumber
Bagaimana dengan mengurutkan kedua string perbandingan sebelum perbandingan? Saya telah menemukan bahwa ini dapat membantu dengan transposisi.
openwonk
2

Jarak Levenshtein lebih baik untuk kata-kata

Jika kata-kata (terutama) dieja dengan benar maka lihatlah sekumpulan kata-kata . Saya mungkin tampak seperti over kill tetapi TF-IDF dan cosine similarity .

Atau Anda bisa menggunakan Lucene gratis. Saya pikir mereka melakukan kesamaan cosinus.

paparazzo
sumber
1

Pertama, Anda harus menguraikan halaman web untuk alamat, RegEx adalah salah satu yang harus diambil, tetapi bisa sangat sulit untuk menguraikan alamat menggunakan RegEx. Anda kemungkinan besar harus melalui daftar format pengalamatan potensial dan satu atau lebih ekspresi yang cocok dengan mereka. Saya tidak terlalu terbiasa dengan penguraian alamat, tetapi saya sarankan melihat pertanyaan ini yang mengikuti alur pemikiran yang serupa: General Address Parser for Freeform Text.

Jarak Levenshtein berguna tetapi hanya setelah Anda memisahkan alamat menjadi bagian-bagian itu. Pertimbangkan alamat berikut. 123 someawesome st.dan 124 someawesome st.alamat-alamat ini adalah lokasi yang sama sekali berbeda, tetapi jarak Levenshtein mereka hanya 1. Ini juga dapat diterapkan untuk sesuatu seperti 8th st.dan 9th st.Nama jalan yang serupa biasanya tidak muncul di halaman web yang sama, tetapi itu tidak pernah terdengar. Halaman web sekolah mungkin memiliki alamat perpustakaan di seberang jalan misalnya, atau gereja beberapa blok ke bawah. Ini berarti bahwa satu-satunya data yang jarak Levenshtein mudah digunakan adalah jarak antara 2 titik data, seperti jarak antara jalan dan kota.

Sejauh mencari tahu cara memisahkan bidang yang berbeda, cukup sederhana setelah kami mendapatkan alamatnya sendiri. Untungnya sebagian besar alamat datang dalam format yang sangat spesifik, dengan sedikit sihir RegEx seharusnya dapat memisahkannya ke dalam bidang data yang berbeda. Bahkan jika alamatnya tidak diformat dengan baik, masih ada harapan. Alamat selalu (hampir) mengikuti urutan besarnya. Alamat Anda harus berada di suatu tempat di grid linear seperti ini tergantung pada seberapa banyak informasi yang disediakan, dan apa itu:

StreetNumber < Street < City < State < Country

Ini jarang terjadi, jika sama sekali alamat dilewati dari satu bidang ke bidang yang tidak berdekatan. Anda tidak akan melihat Street lalu Country, atau StreetNumber lalu City, sangat sering.

Ucenna
sumber
2
Kecuali bahwa alamat jalan tidak teratur, dan tidak dapat diurai dengan tepat oleh ekspresi reguler. Mereka tentu tidak dapat diidentifikasi secara akurat jika mereka hanya tertanam dalam teks bebas. Anda dapat, tentu saja, menulis beberapa ekspresi reguler yang berbeda untuk mencocokkan format umum yang berbeda, jika Anda sudah tahu di mana Anda mencari.
berguna
@ Tidak Berguna Itu benar. Secara teori itu bisa dilakukan, tetapi saya meremehkan jumlah pekerjaan yang diperlukan untuk memasukkannya. Terutama ketika ada opsi yang berpotensi lebih baik tersedia. Saya telah mengubah jawaban saya untuk mencerminkan hal ini.
Ucenna
1

Anda bertanya tentang algoritma kesamaan string tetapi string Anda adalah alamat. Saya akan mengirimkan alamat ke API lokasi seperti Google Place Search dan menggunakan formatted_addresssebagai titik perbandingan. Itu sepertinya pendekatan yang paling akurat.

Untuk string alamat yang tidak dapat ditemukan melalui API, Anda kemudian dapat kembali ke algoritma kesamaan.

Dan Wilson
sumber
1
+1 Alihkan sumbernya sehingga Anda mendapatkan kekuatan para ahli untuk melakukan pekerjaan untuk Anda. Tidak harus Google karena ada beberapa penyedia layanan di luar sana. Jangan buang waktu Anda melakukan ini kecuali pencocokan alamat adalah bisnis inti Anda.
LoztInSpace
0

Salah satu algoritma keren yang berguna tetapi membutuhkan database preset dari jawaban sebelumnya disebut: Line edit distance.

Baris edit jarak, sebagai fungsi, dapat mengembalikan kembali "betapa jauh berbeda kedua kata itu".

Sebuah kata seperti "dogma" dan "dog", Anda akan mendapatkan kembali nilai 3 (untuk 3 karakter tambahan).

Atau "kucing" dan "topi", dapatkan kembali nilai 1 (untuk satu karakter yang berbeda).

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

John Greene
sumber
2
Apa keuntungan dari Levensthtein yang disebutkan OP?
Christophe
-1

Memang menggunakan beberapa fungsi jarak sepertinya pendekatan yang bagus. Tetapi masalahnya kemudian adalah untuk menemukan string terdekat dari alamat yang diberikan, yang jauh dari sepele.

Anda menggambarkan kategori algoritma yang luas di sini. Lihat pencarian tetangga terdekat

Seperti disebutkan dalam komentar, jika Anda menemukan cara untuk memisahkan komponen alamat (nama jalan, nomor, dll), itu akan membuat tugas lebih mudah.

kjaquier
sumber
-1

LongestCommonSub berikutnyaence (dari Apache commons-text) dapat menjadi pendekatan lain untuk dicoba dengan alamat. Jika Anda mendefinisikan kesamaan dua sebagai rasio " panjang / panjang kemunculan bersama umum (panjang alamat) ", maka Anda dapat menerapkan ambang toleransi - mis. 0,8 yang akan menentukan kecocokan / tidak ada kecocokan. Dengan cara ini, Anda dapat mencocokkan alamat seperti " 1 someawesome st., Anytown " dan " 1 someawesome street., Anytown ".

Ini bukan algoritma yang super cepat, jadi Anda mungkin ingin menerapkan failback cepat untuk meminimalkan perbandingan. Contohnya adalah - hindari perbandingan jika kode pos tidak cocok, atau urutan digit yang diekstraksi berbeda.

Altair7852
sumber