in reply to separating text words in similarity classes using levenshtein

If I were to do this, instead of using a hash and naming the clasess, I would use an array of classes where each array is a class. Then to add works you look at each class and and the word to the first class where the average distance from the new word to each word in the collection is below a certain threshold. That is what I've done below. To make it even better you could scan every class and add it to the class that has the lowest average distance. I also only added the word once, and if its already added skipped it.

#!/usr/bin/perl use strict; use warnings; use Text::Levenshtein qw/fastdistance/; use Data::Dumper; my $classes = []; my $index = {}; my $limit = 0.5; sub avg_distance { my ($new_word, $class) = @_; my $distance = 0; for my $word (@$class) { $distance += fastdistance($new_word, $word); } return $distance / @$class; } sub put_or_create { my ($w) = @_; $w =~ s/[^a-z]//g; my $found=0; return if exists $index->{$w}; foreach my $class ( @$classes ) { if((avg_distance($w,$class)/length($w)) < $limit) { push @$class, $w; $index->{$w} = $class; $found = 1; last; }; }; if(! $found) { my $class = [$w]; push @$classes, $class; $index->{$w} = $class; }; }; #watch for an error opening the file open( my $file,"<", "possible_locations.txt") or die "Failed to open f +ile: $!"; my @locations = <$file>; #remove the line endings chomp(@locations); my $count = 0; for (@locations) { #last if ++$count/@locations > 0.2;#not all put_or_create($_) } for (@$classes) { print join(",", sort @$_), "\n"; }

This approaches might need some improvement. The first that comes to mind is add the word to the class/set that is closest, then divide that set up when the average distance becomes too great. I might even give that a shot as it sounds fun!


___________
Eric Hodges

Replies are listed 'Best First'.
Re^2: separating text words in similarity classes using levenshtein
by spx2 (Deacon) on Dec 11, 2007 at 03:35 UTC
    thanks.
    it's much better than mine
    4m30s vs. 14m(I suspect it's because all that hash look-ups I make use of)
    but it's not putting the real words in the classes
    it's putting the words modified by that regex wich
    strips off unwanted characters.
    altough there still may remain cases like:
    when one writes this : アレの i るs オ i
    wich at a closer look is "Ploiesti" wich is a city
    in Romania but it is interpreted as Iasi(wich is another city in Romania) just because the edit-distance is close
    but I agree that this is a very special case
    also Caracas is a city in Venezuela and it has edit-distance
    very close to Caracal wich is a small city in Romania
    Should I check first against a list of cities ?
    I also found this list of all cities,regions and countries in the world
    and I'm wondering if it would be a good
    Ideea to parse those(they're csv I guess),get some tables in the
    database with them and check against them when a new
    entry is beein added ... but that could take some time