I am working on a KNN implementation for sparse datasets (that I apply to text analysis). My points are represented by a Dictionary<string, double>
, each key represents a word of the text and the value, its count or TFIDF.
I am using index inversion to reduce the number of distances to evaluate. However, evaluating the distance remains the bottleneck. It is represented in the following method:
public static double Euclide(Dictionary<string, double> sp1, Dictionary<string, double> sp2)
{
double distance = 0;
foreach (KeyValuePair<string, double> kvp1 in sp1)
{
if (sp2.ContainsKey(kvp1.Key))
distance += Math.Pow((kvp1.Value - sp2[kvp1.Key]), 2);
else
distance += Math.Pow((kvp1.Value), 2);
}
foreach (KeyValuePair<string, double> kvp2 in sp2)
if (!sp1.ContainsKey(kvp2.Key))
distance += Math.Pow((kvp2.Value), 2);
return distance;
}
How can I make it faster? Any help would be greatly appreciated.
I think I could reduce the time of evaluation using a Dictionary<int, double>
, but I prefer to stick to strings, as it allows me to see at a glance what is going on (hashing words would compromise that).
The following yieled a 1.3~2.1x improvement (depending on the length of the input, but it is still not enough) :
public static double FastEuclide(Dictionary<string, double> sp1, Dictionary<string, double> sp2)
{
double distance = 0;
foreach (KeyValuePair<string, double> kvp1 in sp1)
{
double sp1Value = kvp1.Value;
if (sp2.ContainsKey(kvp1.Key))
{
double sp2Value = sp2[kvp1.Key],
diff = kvp1.Value - sp2[kvp1.Key];
distance += diff * diff;
}
else
distance += sp1Value * sp1Value;
}