Косинусное подобие каждой строки в матрице

У меня есть матрица с именем vectors [i] [j]. Я хотел бы вычислить косинусное сходство между каждой строкой. Например для этой матрицы

    1 0 1 0 1 0 0
v=  0 0 1 1 1 0 1
    1 1 0 0 1 0 1

Я хочу иметь расчет сходства между строкой 1 и строкой 2, строкой 1 и строкой 3, строкой 2 и строкой 3. Более того, если сходство между строкой 1 и строкой 2 равно = 0,6 и другим 0,5 и 0,4 соответственно. Я хотел бы добавить это значение для каждого элемента (e =! 0) из них в строки и получить окончательную матрицу, подобную этой.

    2.1    0    2.1   0   2.1    0    0
v=  0      0     2    2    2     0    2
    1.9   1.9    0    0   1.9    0   1.9

Вот часть кода, в которой я определил и заполнил свою матрицу;

string text = Request.Form["TextBox1"]; ; // text
            string[] textInArray = text.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
            int[,] vectors = new int[textInArray.Length, keywords.Length];

            for (int i = 0; i < textInArray.Length; i++)
            {
                string[] words = textInArray[i].Split(' ');
                for (int j = 0; j < keywords.Length; j++)
                {
                    foreach (var word in words)
                    {
                        if (word.Contains(keywords[j]))
                        {
                            vectors[i, j]++;
                        }
                    }
                }
            }

и вот мой код для вычисления сходства, но я думаю, что он не завершен, где-то у меня есть ошибки, и я понятия не имею, как я могу добавить это значение в элементы двух текущих строк.

for(i=1 i<matrix.GetLength(0) i++){
   for(j=1 j<matrix.GetLength(0) j++){
            dot += vectors[i] * vectors[j];
            mag1 += Math.Pow(vectors[i], 2);
            mag2 += Math.Pow(vectors[j], 2);
        }

        float M= dot / (Math.Sqrt(mag1) * Math.Sqrt(mag2));  

}
}

person dpointttt    schedule 12.05.2016    source источник
comment
Удален тег asp.net, поскольку вопрос, похоже, никак не относится к asp.net, добавлен C #   -  person Andrei    schedule 12.05.2016


Ответы (1)


Разложите свой раствор! Извлечь Similarity метод

private static double Similarity(double[] left, double[] right) {
  double ab = 0.0;
  double aa = 0.0;
  double bb = 0.0;

  for (int i = 0; i < left.length; ++i) {
    aa += left[i] * left[i];
    ab += left[i] * right[i];
    bb += right[i] * right[i]; 
  }

  // do not forget degenerated cases: all-zeroes vectors 
  if (aa == 0) 
    return bb == 0 ? 1.0 : 0.0;
  else if (bb == 0) 
    return 0.0;
  else
    return ab / Math.Sqrt(aa) / Math.Sqrt(bb);
}

А затем поставьте простую логику

// vectors[][] is an array of array, so we can get lines easily by vectors[0] etc.
double sim12 = Similarity(vectors[0], vectors[1]);
double sim23 = Similarity(vectors[1], vectors[2]);
double sim13 = Similarity(vectors[0], vectors[2]);

// compare double with tolerance
if ((Math.Abs(sim12 - 0.6) < 1e-10) &&
    (Math.Abs(sim13 - 0.5) < 1e-10) &&
    (Math.Abs(sim23 - 0.4) < 1e-10)) {
  //TODO: update the matrix
}

Изменить: поскольку на самом деле vectors - это double[,] (2d массив)

private static double Similarity(double[,] matrix, int left, int right) {
  double ab = 0.0;
  double aa = 0.0;
  double bb = 0.0;

  for (int i = 0; i < matrix.GetLength(1); ++i) {
    aa += matrix[left, i] * matrix[left, i];
    ab += matrix[left, i] * matrix[right, i];
    bb += matrix[right, i] * matrix[right, i]; 
  }

  if (aa == 0) 
    return bb == 0 ? 1.0 : 0.0;
  else if (bb == 0) 
    return 0.0;
  else
    return ab / Math.Sqrt(aa) / Math.Sqrt(bb);
}

....

double sim12 = Similarity(vectors, 0, 1);
double sim23 = Similarity(vectors, 1, 2);
double sim13 = Similarity(vectors, 0, 2);
person Dmitry Bychenko    schedule 12.05.2016
comment
Я получаю эту ошибку Неправильное количество индексов внутри []; ожидается 2 для linedouble sim12 = Similarity (....) Как вы думаете, это потому, что я определил свою матрицу в начале вот так? int [,] векторы = новый int [textInArray.Length, keywords.Length]; - person dpointttt; 12.05.2016
comment
@: dpointttt: это так. Если у вас есть матрица, как в вопрос vectors[i][j], т.е. массив массива, мой код подойдет; но если вы действительно поместили его int[,] vectors, т.е. 2D-массив, мой код не годится. Массивы массивов (a.k.a jugged array) намного более гибкие, чем 2D-массивы. - person Dmitry Bychenko; 12.05.2016
comment
@: dpointttt: однако основной принцип тот же: метод извлечения независимо от того, какое представление матрицы у вас есть. - person Dmitry Bychenko; 12.05.2016
comment
спасибо за ваш быстрый ответ, как я могу изменить свою матрицу, если она будет работать с методом, который у вас есть. Я пробовал это, но не работал; int [] [] векторы = новый int [textInArray.Length, keywords.Length]; или двойной [] [] векторы = новый двойной [textInArray.Length] [keywords.Length]; - person dpointttt; 12.05.2016
comment
Я добавил часть кода, в которой я определяю свою матрицу, для первого сообщения - person dpointttt; 12.05.2016
comment
@dpointttt: все, что вам нужно сделать, это немного изменить метод Similarity (см. мою правку) - person Dmitry Bychenko; 12.05.2016
comment
@dpointttt: пожалуйста! В следующий раз, пожалуйста, не пытайтесь втиснуть все в один метод - person Dmitry Bychenko; 12.05.2016