Косинус связи представлением в C#


Я использую 2 вложенных SortedDictionaries для построения разреженных матриц

Здесь-это функция пользовательской связи(SIM-карты) я писал . Сейчас он работает за o(н^2) сложности. Я ищу предложения по улучшению надежности и эффективности.Спасибо за любую помощь.

       double 
            a = 0, b = 0,
            sqrta = 0,
            sqrtb = 0,
            sim = 0; 

        foreach (var word_i in dict)
        {
            foreach (var word_j in dict)                   
            {
                if (word_i.Key == word_j.Key) continue;

                sim=a=b=sqrta=sqrtb=0;                                   
                foreach (var term in word_j.Value.Keys)
                {
                    if (word_i.Value.ContainsKey(term))
                    {
                        word_i.Value.TryGetValue(term,out a);
                        word_j.Value.TryGetValue(term,out b);
                        sim += a * b;
                        sqrta += Math.Pow(a,2);                                
                        sqrtb += Math.Pow(b,2);
                    }

                }

                sim /= Math.Sqrt(sqrta) * Math.Sqrt(sqrtb);              

            }
        }


1629
4
задан 14 октября 2011 в 08:10 Источник Поделиться
Комментарии
2 ответа

Как вы делаете расчеты на все значения, где результат зависит от обеих петель, тут мало что можно сделать по поводу сложности, по крайней мере, не зная, что делать с результатом (который, кажется, быть просто отброшены в коде показано).

Есть некоторые вещи, которые вы можете сделать в самый внутренний цикл:

Вместо того, чтобы сначала через содержится , а затем получить значение, вы можете использовать TryGetValue напрямую.

Вы знаете, что термин существует в другой коллекции, поэтому вам не нужно TryGetValue для этого.

Квадратура это сделать намного быстрее, просто умножив вместо того, чтобы использовать математику.Пау.

if (word_i.Value.TryGetValue(term,out a)) {
b = word_j.Value[term];
sim += a * b;
sqrta += a * a;
sqrtb += b * b;
}

2
ответ дан 14 октября 2011 в 11:10 Источник Поделиться

Вы можете попробовать это

public class Term
{
public string Value { get; set; }
public Dictionary<string, double> Definitions { get; set; }

public Term(string value, Dictionary<string, double> definitions)
{
this.Value = value;
this.Definitions = definitions;
}
}

public class TermPair
{
public Term Left { get; private set; }
public Term Right { get; private set; }
public double Similarity { get; private set; }

public TermPair(Term left, Term right)
{
this.Left = left;
this.Right = right;
}

public void CalculateSimilarity()
{
var sim = 0D;
var sqrta = 0D;
var sqrtb = 0D;

var leftDefinitions = this.Left.Definitions;
var rightDefinitions = this.Right.Definitions;

foreach (var kv in leftDefinitions)
{
double a;
var term = kv.Key;
if (rightDefinitions.TryGetValue(term, out a))
{
var b = kv.Value;
sim += a * b;
sqrta += a * a;
sqrtb += b * b;
}
}

sim /= Math.Sqrt(sqrta) * Math.Sqrt(sqrtb);

this.Similarity = sim;
}
}

Использовать эти классы так:

List<Term> terms = ...

var idx = 0;
var totalTerms = terms.Count;
var pairs = new TermPair[((totalTerms - 1) * (totalTerms)) / 2];
for (var i = 0; i < totalTerms; i++)
{
for (var j = 0; j < totalTerms; j++)
{
if (i > j)
{
pairs[idx++] = new TermPair(terms[i], terms[j]);
}
}
}

foreach (var pair in pairs.AsParallel())
{
pair.CalculateSimilarity();
}

Я не знаю вашу ситуацию, но я надеюсь, что это поможет. Вы можете экспериментировать с словаре sorteddictionary и словарь. Кстати я не совсем уверен, если TryGetValue является потокобезопасным для чтения из нескольких потоков.

1
ответ дан 21 октября 2011 в 04:10 Источник Поделиться