distancia de levenshtein

12
Distancia de Levenshtein 1 Distancia de Levenshtein En Teoría de la información y Ciencias de la Computación se llama Distancia de Levenshtein, distancia de edición, o distancia entre palabras, al número mínimo de operaciones requeridas para transformar una cadena de caracteres en otra. Se entiende por operación, bien una inserción, eliminación o la sustitución de un carácter. Esta distancia recibe ese nombre en honor al científico ruso Vladimir Levenshtein, quien se ocupara de esta distancia en 1965. Es útil en programas que determinan cuán similares son dos cadenas de caracteres, como es el caso de los correctores de ortografía. Por ejemplo, la distancia de Levenshtein entre "casa" y "calle" es de 3 porque se necesitan al menos tres ediciones elementales para cambiar uno en el otro. 1. casa cala (sustitución de 's' por 'l') 2. cala calla (inserción de 'l' entre 'l' y 'a') 3. calla calle (sustitución de 'a' por 'e') Se le considera una generalización de la distancia de Hamming, que se usa para cadenas de la misma longitud y que solo considera como operación la sustitución. Hay otras generalizaciones de la distancia de Levenshtein, como la distancia de Damerau-Levenshtein, que consideran el intercambio de dos caracteres como una operación El algoritmo Se trata de un algoritmo de tipo bottom-up, común en programación dinámica. Se apoya en el uso de una matriz (n + 1) × (m + 1), donde n y m son las longitudes de los cadenas. Aquí se indica el algoritmo en pseudocódigo para una función LevenshteinDistance que toma dos cadenas, str1 de longitud lenStr1, y str2 de longitud lenStr2, y calcula la distancia Levenshtein entre ellos: int LevenshteinDistance(char str1[1..lenStr1], char str2[1..lenStr2]) // d is a table with lenStr1+1 rows and lenStr2+1 columns declare int d[0..lenStr1, 0..lenStr2] // i and j are used to iterate over str1 and str2 declare int i, j, cost for i from 0 to lenStr1 d[i, 0] := i for j from 0 to lenStr2 d[0, j] := j for i from 1 to lenStr1 for j from 1 to lenStr2 if str1[i] = str2[j] then cost := 0 else cost := 1 d[i, j] := minimum( d[i-1, j] + 1, // deletion d[i, j-1] + 1, // insertion d[i-1, j-1] + cost // substitution ) return d[lenStr1, lenStr2]

Upload: lt-omicron

Post on 27-Oct-2014

93 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Distancia de Levenshtein

Distancia de Levenshtein 1

Distancia de LevenshteinEn Teoría de la información y Ciencias de la Computación se llama Distancia de Levenshtein, distancia de edición,o distancia entre palabras, al número mínimo de operaciones requeridas para transformar una cadena de caracteres enotra. Se entiende por operación, bien una inserción, eliminación o la sustitución de un carácter. Esta distancia recibeese nombre en honor al científico ruso Vladimir Levenshtein, quien se ocupara de esta distancia en 1965. Es útil enprogramas que determinan cuán similares son dos cadenas de caracteres, como es el caso de los correctores deortografía.Por ejemplo, la distancia de Levenshtein entre "casa" y "calle" es de 3 porque se necesitan al menos tres edicioneselementales para cambiar uno en el otro.1. casa → cala (sustitución de 's' por 'l')2. cala → calla (inserción de 'l' entre 'l' y 'a')3. calla → calle (sustitución de 'a' por 'e')Se le considera una generalización de la distancia de Hamming, que se usa para cadenas de la misma longitud y quesolo considera como operación la sustitución. Hay otras generalizaciones de la distancia de Levenshtein, como ladistancia de Damerau-Levenshtein, que consideran el intercambio de dos caracteres como una operación

El algoritmoSe trata de un algoritmo de tipo bottom-up, común en programación dinámica. Se apoya en el uso de una matriz (n+ 1) × (m + 1), donde n y m son las longitudes de los cadenas. Aquí se indica el algoritmo en pseudocódigo parauna función LevenshteinDistance que toma dos cadenas, str1 de longitud lenStr1, y str2 de longitud lenStr2, ycalcula la distancia Levenshtein entre ellos:

int LevenshteinDistance(char str1[1..lenStr1], char str2[1..lenStr2])

// d is a table with lenStr1+1 rows and lenStr2+1 columns

declare int d[0..lenStr1, 0..lenStr2]

// i and j are used to iterate over str1 and str2

declare int i, j, cost

for i from 0 to lenStr1

d[i, 0] := i

for j from 0 to lenStr2

d[0, j] := j

for i from 1 to lenStr1

for j from 1 to lenStr2

if str1[i] = str2[j] then cost := 0

else cost := 1

d[i, j] := minimum(

d[i-1, j] + 1, // deletion

d[i, j-1] + 1, // insertion

d[i-1, j-1] + cost // substitution

)

return d[lenStr1, lenStr2]

Page 2: Distancia de Levenshtein

Distancia de Levenshtein 2

El invariante mantenido a través del algorítmo es que pueda transformar el segmento inicial str1[1..i] enstr2[1..j] empleando un mínimo de d[i,j] operaciones. Al final, el elemento ubicado en la parteINFERIOR derecha de la matriz contiene la respuesta.

ImplementaciónA continuación se puede ver la implementación de la función para varios lenguajes de programación. Otros lenguajesde más alto nível, como php o la funciones de usuario de MySQL, las incorporan ya, sin necesidad de implementarlapara ser usada.

C++#include <string>

#include <vector>

#include <algorithm>

using namespace std;

int levenshtein(const string &s1, const string &s2)

{

int N1 = s1.size();

int N2 = s2.size();

int i, j;

vector<int> T(N2+1);

for ( i = 0; i <= N2; i++ )

T[i] = i;

for ( i = 0; i < N1; i++ ) {

T[0] = i+1;

int corner = i;

for ( j = 0; j < N2; j++ ) {

int upper = T[j+1];

if ( s1[i] == s2[j] )

T[j+1] = corner;

else

T[j+1] = min(T[j], min(upper, corner)) + 1;

corner = upper;

}

}

return T[N2];

}

Page 3: Distancia de Levenshtein

Distancia de Levenshtein 3

C#public int LevenshteinDistance(string s, string t, out double

porcentaje)

{

porcentaje = 0;

// d es una tabla con m+1 renglones y n+1 columnas

int costo = 0;

int m = s.Length;

int n = t.Length;

int[,] d = new int[m + 1, n + 1];

// Verifica que exista algo que comparar

if (n == 0) return m;

if (m == 0) return n;

// Llena la primera columna y la primera fila.

for (int i = 0; i <= m; d[i, 0] = i++) ;

for (int j = 0; j <= n; d[0, j] = j++) ;

/// recorre la matriz llenando cada unos de los pesos.

/// i columnas, j renglones

for (int i = 1; i <= m; i++)

{

// recorre para j

for (int j = 1; j <= n; j++)

{

/// si son iguales en posiciones equidistantes el peso es 0

/// de lo contrario el peso suma a uno.

costo = (s[i - 1] == t[j - 1]) ? 0 : 1;

d[i, j] = System.Math.Min(System.Math.Min(d[i - 1, j] + 1,

//Eliminacion

d[i, j - 1] + 1),

//Inserccion

d[i - 1, j - 1] + costo);

//Sustitucion

}

}

/// Calculamos el porcentaje de cambios en la palabra.

if (s.Length > t.Length)

porcentaje = ((double)d[m, n] / (double)s.Length);

else

porcentaje = ((double)d[m, n] / (double)t.Length);

return d[m, n];

}

Page 4: Distancia de Levenshtein

Distancia de Levenshtein 4

JavaImplementado como una clase estática.

public class LevenshteinDistance {

private static int minimum(int a, int b, int c) {

if(a<=b && a<=c)

{

return a;

}

if(b<=a && b<=c)

{

return b;

}

return c;

}

public static int computeLevenshteinDistance(String str1, String

str2) {

return computeLevenshteinDistance(str1.toCharArray(),

str2.toCharArray());

}

private static int computeLevenshteinDistance(char [] str1, char []

str2) {

int [][]distance = new int[str1.length+1][str2.length+1];

for(int i=0;i<=str1.length;i++)

{

distance[i][0]=i;

}

for(int j=0;j<=str2.length;j++)

{

distance[0][j]=j;

}

for(int i=1;i<=str1.length;i++)

{

for(int j=1;j<=str2.length;j++)

{

distance[i][j]= minimum(distance[i-1][j]+1,

distance[i][j-1]+1,

distance[i-1][j-1]+

((str1[i-1]==str2[j-1])?0:1));

}

}

return distance[str1.length][str2.length];

Page 5: Distancia de Levenshtein

Distancia de Levenshtein 5

}

}

Perlsub fastdistance

{

my $word1 = shift;

my $word2 = shift;

return 0 if $word1 eq $word2;

my @d;

my $len1 = length $word1;

my $len2 = length $word2;

$d[0][0] = 0;

for (1.. $len1) {

$d[$_][0] = $_;

return $_ if $_!=$len1 && substr($word1,$_) eq

substr($word2,$_);

}

for (1.. $len2) {

$d[0][$_] = $_;

return $_ if $_!=$len2 && substr($word1,$_) eq

substr($word2,$_);

}

for my $i (1.. $len1) {

my $w1 = substr($word1,$i-1,1);

for (1.. $len2) {

$d[$i][$_] = _min($d[$i-1][$_]+1,

$d[$i][$_-1]+1,

$d[$i-1][$_-1]+($w1 eq

substr($word2,$_-1,1) ?

0 : 1));

}

}

return $d[$len1][$len2];

}

sub _min

{

return $_[0] < $_[1]

? $_[0] < $_[2] ? $_[0] : $_[2]

: $_[1] < $_[2] ? $_[1] : $_[2];

}

Page 6: Distancia de Levenshtein

Distancia de Levenshtein 6

Pythondef distance(str1, str2):

d=dict()

for i in range(len(str1)+1):

d[i]=dict()

d[i][0]=i

for i in range(len(str2)+1):

d[0][i] = i

for i in range(1, len(str1)+1):

for j in range(1, len(str2)+1):

d[i][j] = min(d[i][j-1]+1, d[i-1][j]+1, d[i-1][j-1]+(not str1[i-1] == str2[j-1]))

return d[len(str1)][len(str2)]

Rubyclass String

def levenshtein(other)

other = other.to_s

distance = Array.new(self.size + 1, 0)

(0..self.size).each do |i|

distance[i] = Array.new(other.size + 1)

distance[i][0] = i

end

(0..other.size).each do |j|

distance[0][j] = j

end

(1..self.size).each do |i|

(1..other.size).each do |j|

distance[i][j] = [distance[i - 1][j] + 1,

distance[i][j - 1] + 1,

distance[i - 1][j - 1] + ((self[i - 1] == other[j - 1]) ? 0 : 1)].min

end

end

distance[self.size][other.size]

end

end

puts "casa".levenshtein "calle" #=> 3

Page 7: Distancia de Levenshtein

Distancia de Levenshtein 7

PHP<?

$lev = levenshtein($input, $word);

?>

Delphifunction LevenshteinDistance(Str1, Str2: String): Integer;

var

d : array of array of Integer;

Len1, Len2 : Integer;

i,j,cost:Integer;

begin

Len1:=Length(Str1);

Len2:=Length(Str2);

SetLength(d,Len1+1);

for i := Low(d) to High(d) do

SetLength(d[i],Len2+1);

for i := 0 to Len1 do

d[i,0]:=i;

for j := 0 to Len2 do

d[0,j]:=j;

for i:= 1 to Len1 do

for j:= 1 to Len2 do

begin

if Str1[i]=Str2[j] then

cost:=0

else

cost:=1;

d[i,j]:= Min(d[i-1, j] + 1, // deletion,

Min(d[i, j-1] + 1, // insertion

d[i-1, j-1] + cost) // substitution

);

end;

Result:=d[Len1,Len2];

end;

VB.NET Public Function Levenshtein(ByVal s1 As String, ByVal s2 As String)

As Integer

Dim coste As Integer = 0

Dim n1 As Integer = s1.Length

Dim n2 As Integer = s2.Length

Dim m As Integer(,) = New Integer(n1, n2) {}

Page 8: Distancia de Levenshtein

Distancia de Levenshtein 8

For i As Integer = 0 To n1

m(i, 0) = i

Next

For i As Integer = 1 To n2

m(0, i) = i

Next

For i1 As Integer = 1 To n1

For i2 As Integer = 1 To n2

coste = Iif((s1(i1 - 1) = s2(i2 - 1)), 0, 1)

m(i1, i2) = Math.Min(Math.Min(m(i1 - 1, i2) + 1, m(i1,

i2 - 1) + 1), m(i1 - 1, i2 - 1) + coste)

Next

Next

Return m(n1, n2)

End Function

Gambas 2PUBLIC FUNCTION Levenshtein(s1 AS String, s2 AS String) AS Integer

DIM iCost AS Integer = 0

DIM iN1 AS Integer = String.Len(s1)

DIM iN2 AS Integer = String.Len(s2)

DIM ariM AS NEW Integer[iN1 + 1, iN2 + 1]

DIM i AS Integer

DIM j AS Integer

DIM i1 AS Integer

DIM j2 AS Integer

FOR i = 0 TO iN1

ariM[i, 0] = i

NEXT

FOR i = 1 TO iN2

ariM[0, i] = i

NEXT

FOR i1 = 1 TO iN1

FOR j2 = 1 TO iN2

IF String.Mid(s1, i1, 1) = String.Mid(s2, j2, 1) THEN

iCost = 0

ELSE

iCost = 1

ENDIF

ariM[i1, j2] = Min(Min(ariM[i1 - 1, j2] + 1, ariM[i1, j2 - 1] + 1), ariM[i1 - 1, j2 - 1] + iCost)

NEXT

NEXT

RETURN ariM[iN1, iN2]

END

Page 9: Distancia de Levenshtein

Distancia de Levenshtein 9

Javascript function levenshtein(a, b)

{

var i, j, r=[];

r[0] = [];

r[0][0] = 0;

for(i=1; i<=a.length; i++) {

r[i] = [];

r[i][0] = i;

for(j=1; j<=b.length; j++) {

r[0][j] = j;

r[i][j] = Math.min(

r[i-1][j]+1,

r[i][j-1]+1,

r[i-1][j-1] + (a[i-1]!==b[j-1])

);

}

}

return r[a.length][b.length];

}

ActionScript 3.0public class StringUtils

{

public static function levenshtein(s1:String, s2:String):int

{

if (s1.length == 0 || s2.length == 0)

return 0;

var m:uint = s1.length + 1;

var n:uint = s2.length + 1;

var i:uint, j:uint, cost:uint;

var d:Vector.<Vector.<int>> = new Vector.<Vector.<int>>();

for (i = 0; i < m; i++)

{

d[i] = new Vector.<int>();

for (j = 0; j < n; j++)

d[i][j] = 0;

}

for (i = 0; i < m; d[i][0] = i++) ;

for (j = 0; j < n; d[0][j] = j++) ;

Page 10: Distancia de Levenshtein

Distancia de Levenshtein 10

for (i = 1; i < m; i++)

{

for (j = 1; j < n; j++)

{

cost = (s1.charAt(i - 1) == s2.charAt(j - 1)) ? 0 : 1;

d[i][j] = Math.min(Math.min(d[i - 1][j] + 1,

d[i][j - 1] + 1),

d[i - 1][j - 1] + cost);

}

}

return d[m-1][n-1];

}

}

ColdFusion<cfscript>

function levDistance(s,t) {

var d = ArrayNew(2);

var i = 1;

var j = 1;

var s_i = "A";

var t_j = "A";

var cost = 0;

var n = len(s)+1;

var m = len(t)+1;

d[n][m]=0;

if (n is 1) {

return m;

}

if (m is 1) {

return n;

}

for (i = 1; i lte n; i=i+1) {

d[i][1] = i-1;

}

for (j = 1; j lte m; j=j+1) {

d[1][j] = j-1;

}

Page 11: Distancia de Levenshtein

Distancia de Levenshtein 11

for (i = 2; i lte n; i=i+1) {

s_i = Mid(s,i-1,1);

for (j = 2; j lte m; j=j+1) {

t_j = Mid(t,j-1,1);

if (s_i is t_j) {

cost = 0;

}

else {

cost = 1;

}

d[i][j] = min(d[i-1][j]+1, d[i][j-1]+1);

d[i][j] = min(d[i][j], d[i-1][j-1] + cost);

}

}

return d[n][m];

}

</cfscript>

Aplicaciones• El projecto ASJP [1] usa la distancia de levenshtein total en una lista de palabras en diferentes lenguas del mundo,

para medir la "similaridad" o "cercanía" de las mismas, esa distancia calculada puede emplearse para proponeruna clasificación filogenética tentativa de las lenguas del mundo.[2]

• La distancia de Damerau-Levenshtein es una generalización de la distancia de Levenshtein usada por loscorrectores ortográficos y en la detección de fraudes en listas de datos.

Referencia[1] http:/ / email. eva. mpg. de/ ~wichmann/ ASJPHomePage. htm[2] ASJP - World Language Tree (http:/ / email. eva. mpg. de/ ~wichmann/ WorldLanguageTree-002. pdf)

Page 12: Distancia de Levenshtein

Fuentes y contribuyentes del artículo 12

Fuentes y contribuyentes del artículoDistancia de Levenshtein  Fuente: http://es.wikipedia.org/w/index.php?oldid=58004955  Contribuyentes: Amsantosr, Chewie, Dante Alighieri 1975, Davius, Dodo, Gaeddal, Luigli, Oncina,Pinar, RoyFocker, Sabbut, Sharop, Tamorlan, Tomasdev, 47 ediciones anónimas

LicenciaCreative Commons Attribution-Share Alike 3.0 Unported//creativecommons.org/licenses/by-sa/3.0/