À la meilleure manière de mettre en œuvre des K-plus proches voisins en C# pour un grand nombre de dimensions?

Je suis la mise en œuvre de la K-plus proches voisins algorithme de classification en C# pour une formation et un jeu de test d'environ 20 000 échantillons de chacun, et 25 dimensions.

Il y a seulement deux classes, représentées par des '0' et '1' dans ma mise en œuvre. Pour l'instant, j'ai l', après simple mise en œuvre :

//testSamples and trainSamples consists of about 20k vectors each with 25 dimensions
//trainClasses contains 0 or 1 signifying the corresponding class for each sample in trainSamples
static int[] TestKnnCase(IList<double[]> trainSamples, IList<double[]> testSamples, IList<int[]> trainClasses, int K)
{
Console.WriteLine("Performing KNN with K = "+K);
var testResults = new int[testSamples.Count()]; 
var testNumber = testSamples.Count();
var trainNumber = trainSamples.Count();
//Declaring these here so that I don't have to 'new' them over and over again in the main loop, 
//just to save some overhead
var distances = new double[trainNumber][]; 
for (var i = 0; i < trainNumber; i++)
{
distances[i] = new double[2]; //Will store both distance and index in here
}
//Performing KNN ...
for (var tst = 0; tst < testNumber; tst++)
{
//For every test sample, calculate distance from every training sample
Parallel.For(0, trainNumber, trn =>
{
var dist = GetDistance(testSamples[tst], trainSamples[trn]);
//Storing distance as well as index 
distances[trn][0] = dist;
distances[trn][1] = trn;
});
//Sort distances and take top K (?What happens in case of multiple points at the same distance?)
var votingDistances = distances.AsParallel().OrderBy(t => t[0]).Take(K);
//Do a 'majority vote' to classify test sample
var yea = 0.0;
var nay = 0.0;
foreach (var voter in votingDistances)
{
if (trainClasses[(int)voter[1]] == 1)  
yea++;
else
nay++;
}
if (yea > nay)
testResults[tst] = 1;
else
testResults[tst] = 0;
}
return testResults;
}
//Calculates and returns square of Euclidean distance between two vectors
static double GetDistance(IList<double> sample1, IList<double> sample2)
{
var distance = 0.0;
//assume sample1 and sample2 are valid i.e. same length 
for (var i = 0; i < sample1.Count; i++)
{   
var temp = sample1[i] - sample2[i];
distance += temp * temp;
}
return distance;
}

Cela prend un peu de temps à s'exécuter. Sur mon système, il faut environ 80 secondes. Comment puis-je optimiser ce, tout en assurant qu'elle serait aussi à l'échelle au plus grand nombre d'échantillons de données? Comme vous pouvez le voir, j'ai essayé d'utiliser PLINQ et parallèle pour les boucles, ce qui ne l'aide (sans cela, il prenait environ 120 secondes). Que puis-je faire?

J'ai lu sur les KD-trees être efficace pour KNN en général, mais à chaque source j'ai lu a déclaré qu'ils ne sont pas efficaces pour les dimensions supérieures.

J'ai aussi trouvé cette discussion stackoverflow à ce sujet, mais il semble que c'est 3 ans, et j'espérais que quelqu'un puisse savoir à propos de les meilleures solutions à ce problème maintenant.

J'ai regardé l'apprentissage de la machine bibliothèques en C#, mais pour diverses raisons je ne veux pas l'appeler R ou C code de mon programme C#, et quelques autres bibliothèques que j'ai vu n'étaient pas plus efficaces que le code que j'ai écrit. Maintenant, je suis juste essayer de comprendre comment j'ai pu écrire plus de code optimisé pour moi-même.

Édité pour ajouter - je ne peux pas réduire le nombre de dimensions à l'aide de l'APC ou de quelque chose. Pour ce modèle spécifique, 25 dimensions sont requises.

  • Il semble que votre code fonctionne actuellement, et vous êtes à la recherche pour l'améliorer. En général, ces questions sont trop opiniâtre pour ce site, mais vous pourriez trouver plus de chance dans le CodeReview.SE. N'oubliez pas de lire leurs exigences comme ils sont un peu plus strictes que ce site.
  • Je ne savais pas à ce sujet, merci @gunr2171, je vais essayer là aussi. Cependant, je pense toujours que est une question valable, pour ce site, car j'espérais obtenir une discussion sur peut-être en utilisant une autre structure de données (comme les KD-trees) pour ce problème, comme dans le stackoverflow post, je suis lié.
  • programmers.stackexchange.com peut-être mieux. À la recherche d'autres algorithmes est limite "trop large" de la SORTE. Découvrez liés à des questions - parfois, la solution est déjà là pour une autre langue.
  • Vont essayer de trop @AlexeiLevenkov, merci. Je suis toujours à la recherche d'un bon up-to-date de discussion à ce propos.
  • double possible de plus proches voisins en haute-dimensions données?
  • merci pour les liens, je l'ai vu. La discussion est de 3 ans sur la question, alors j'espérais que quelqu'un a plus d'informations sur cette question depuis lors. Aussi la question se concentre sur des solutions qui ne sont pas pertinentes pour moi, comme la réduction de dimensionnalité ou de rapprochement.
  • Pour l'enregistrement, j'ai eu un tas de suggestions utiles here
  • Je suis actuellement en train de travailler sur un C# module pour optimiser les K-plus proche voisin recherches en haute dimensions des problèmes (de 10 à 1000 dimensions). Je suis la présence d'un excellent succès à l'aide de Courbes de Hilbert. Pour K=50 voisins, 200 dimensions, 10 000 points, j'obtiens 40 fois plus rapide sur l'analyse linéaire. La carte n-D à 1-D Hilbert index, effectuer une recherche binaire, puis trier la liste restreinte à l'aide de la fonction de distance. Voir cet article: J. Berger, X. Zhu, et N. Megiddo. “Une Indexation Rapide Méthode pour Multidimensionnelle du Voisin le plus Proche de la Recherche”.

InformationsquelleAutor ubuntunoob | 2014-07-07