ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

如何在C#中最好地实现大量维度的K-最近邻居?

2019-06-29 00:54:10  阅读:172  来源: 互联网

标签:c optimization classification knn


我正在C#中实现K-最近邻分类算法,用于训练和测试集,每组大约20,000个样本,25个维度.

在我的实现中只有两个类,由’0’和’1’表示.现在,我有以下简单的实现:

// 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;
}

这需要相当多的时间来执行.在我的系统上完成大约需要80秒.如何优化这一点,同时确保它也可以扩展到更大数量的数据样本?正如你所看到的,我已经尝试过使用PLINQ和并行for循环,这确实有帮助(没有这些,它需要大约120秒).我还可以做些什么?

我已经读过KD树一般对KNN有效,但我读到的每一个来源都表明它们对于更高的尺寸效率不高.

我也发现了this stackoverflow discussion这个,但看起来这已经3岁了,我希望有人能够知道现在这个问题的更好解决方案.

我在C#中查看了机器学习库,但由于各种原因,我不想从我的C#程序中调用R或C代码,而我看到的其他一些库并不比我编写的代码更有效.现在我只想弄清楚如何为自己编写最优化的代码.

编辑添加 – 我无法使用PCA或其他东西减少维度.对于此特定型号,需要25个尺寸.

解决方法:

每当您尝试提高代码性能时,第一步就是分析当前的性能,以确切了解它花费时间的位置.一个好的剖析器对此至关重要.在我以前的工作中,我能够使用dotTrace profiler取得良好效果; Visual Studio也有一个built-in profiler.一个好的分析器会告诉你你的代码在哪里花费时间逐个方法甚至逐行.

话虽如此,在阅读您的实现时会想到一些事情:

>您正在并行化一些内部循环.你可以并行化外环吗?委托调用(参见herehere)可能会在“Parallel.For”回调中触及您,但会有一个很小但非零的成本.
>同样,使用IList接口索引数组会有很小的性能损失.您可以考虑明确地将数组参数声明为“GetDistance()”.
>与训练阵列的大小相比,K有多大?您完全对“距离”数组进行排序并获取顶部K,但如果K远小于数组大小,则使用partial sort/selection算法可能是有意义的,例如使用SortedSet并替换最小元素设定尺寸超过K.

标签:c,optimization,classification,knn
来源: https://codeday.me/bug/20190629/1321165.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有