03.03.2009

Нечеткое сравнение

Встала задача для сопоставления предложений. Решалась следующим образом: использовался алгоритм для определения дистанции редактирования, разработанный Владимиром Левенштейном.
Реализация данного алгоритма на C#:



public class StringDistance
{
private int _absoluteMeasure;
/// Абсолютное значение функции похожести
public int AbsoluteMeasure
{
get { return _absoluteMeasure; }
}

private int _procentMeasure;
/// Относительное значение функции похожести
public int ProcentMeasure
{
get { return _procentMeasure; }
}

private string _sentenceOne;
private string _sentenceTwo;

public StringDistance(string sentenceOne, string sentenceTwo)
{
this._sentenceOne = sentenceOne;
this._sentenceTwo = sentenceTwo;

this.SentenceSeemsMeasure();
}

/// Вычисление меры схожести двух предложений
private void SentenceSeemsMeasure()
{
/// получение слов в предложениях
string[] sOneWords = _sentenceOne.Split(
new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
string[] sTwoWords = _sentenceTwo.Split(
new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

/// заполнение матрицы отношений между словами предложения
int[,] wordRelations = new int[sOneWords.Length, sTwoWords.Length];
// значения максимальных значений в строках матрицы
int[] maxRowElements = new int[sOneWords.Length];

try
{

for (int i = 0; i < sOneWords.Length; i++)
{
int max = 0;
for (int j = 0; j < sTwoWords.Length; j++)
{
// получение дистанции для пары слов в предлажении
wordRelations[i, j] =
StringDistance.GetWordDistance(
sOneWords[i], sTwoWords[j]);
// сравение с максимальным значением
if (max < wordRelations[i, j])
max = wordRelations[i, j];
}
maxRowElements[i] = max;
}

/// получения меры схожести между предложениями

int measure = 0;
for (int i = 0; i < maxRowElements.Length; i++)
{
int max = maxRowElements[i];
for (int j = 0; j < sTwoWords.Length; j++)
if (max < wordRelations[i, j])
max = wordRelations[i, j];

measure += max;
}

this._absoluteMeasure = measure;

// получения относительного значения схожести двух предложений
this._procentMeasure =
(int)Math.Round(
measure / (double)Math.Max(sOneWords.Length, sTwoWords.Length), 0);
}
catch (Exception ex)
{
throw new Exception("Ошибка при сравнении предложений", ex);
}
}


/// Получение дистанции для двух слов
private static int GetWordDistance(String s, String t)
{
try
{
/// шаг 1

if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(t))
throw new Exception("Одно из слов не задано.");

s = s.ToLower();
t = t.ToLower();

int n = s.Length; // длина строки s
int m = t.Length; // длина строки t

int[,] d =
new int[n + 1, m + 1]; // матрица для хранения вычислений

/// шаг 2

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

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

/// шаг 3

for (int i = 1; i <= n; i++)
{
int s_i = s[i - 1];

for (int j = 1; j <= m; j++)
{
int t_j = t[j - 1];
int cost = 0;

// определение оценки
if (s_i != t_j)
cost = 1;

// получить минимум для ячейки матрцы
d[i, j] = Minimum(
d[i - 1, j] + 1,
d[i, j - 1] + 1,
d[i - 1, j - 1] + cost);
}
}

int dist = d[n, m]; // дистанция редактирования

/// получение относительного числа похожести
int procent = (int)Math.Round(
(1 - dist / (double)System.Math.Max(s.Length, t.Length)) * 100, 0);

return procent;
}
catch (Exception ex)
{
throw new Exception("Ошибка при сравнении слов", ex);
}
}


/// Минимум из трех значений
private static int Minimum(int a, int b, int c)
{
int min = a;

if (b < min)
min = b;

if (c < min)
min = c;

return min;
}

}

Комментариев нет: