NumPy实现最近邻分类算法以完全相同的方式对所有内容进行分类

我的作业是使用K-最近邻算法,通过NumPy来根据花的各种特征(例如,茎长、花瓣长度等)判断它是什么种类的花。(顺便说一下,我以前用过Python,尽管这不是我最擅长的语言;然而,我对NumPy完全是新手)。

我的训练数据和测试数据都放在这样的CSV文件中:

4.6,3.6,1.0,0.2,Iris-setosa5.1,3.3,1.7,0.5,Iris-setosa4.8,3.4,1.9,0.2,Iris-setosa7.0,3.2,4.7,1.4,Iris-versicolor6.4,3.2,4.5,1.5,Iris-versicolor6.9,3.1,4.9,1.5,Iris-versicolor5.5,2.3,4.0,1.3,Iris-versicolor

我知道如何实现基本算法。以下是我用C#编写的代码:

namespace Project_3_Prototype{    public class FourD    {        public double f1, f2, f3, f4;        public string name;        public static double Distance(FourD a, FourD b)        {            double squared = Math.Pow(a.f1 - b.f1, 2) + Math.Pow(a.f2 - b.f2, 2) + Math.Pow(a.f3 - b.f3, 2) + Math.Pow(a.f4 - b.f4, 2);            return Math.Sqrt(squared);        }    }    class Program    {        static void Main(string[] args)        {            List<FourD> distances = new List<FourD>();            using (var parser = new TextFieldParser("iris-training-data.csv"))            {                parser.SetDelimiters(",");                while (!parser.EndOfData)                {                    string[] fields = parser.ReadFields();                    var curr = new FourD                    {                        f1 = double.Parse(fields[0]),                        f2 = double.Parse(fields[1]),                        f3 = double.Parse(fields[2]),                        f4 = double.Parse(fields[3]),                        name = fields[4]                    };                    distances.Add(curr);                }            }            double correct = 0, total = 0;            using (var parser = new TextFieldParser("iris-testing-data.csv"))            {                parser.SetDelimiters(",");                int i = 1;                while (!parser.EndOfData)                {                    total++;                    string[] fields = parser.ReadFields();                    var curr = new FourD                    {                        f1 = double.Parse(fields[0]),                        f2 = double.Parse(fields[1]),                        f3 = double.Parse(fields[2]),                        f4 = double.Parse(fields[3]),                        name = fields[4]                    };                    FourD min = distances[0];                    foreach (FourD comp in distances)                    {                        if (FourD.Distance(comp, curr) < FourD.Distance(min, curr))                        {                            min = comp;                        }                    }                    if (min.name == curr.name)                    {                        correct++;                    }                    Console.WriteLine(string.Format("{0},{1},{2}", i, curr.name, min.name));                    i++;                }            }            Console.WriteLine("Accuracy: " + correct / total);            Console.ReadLine();        }    }}

这个程序运行得非常好,输出如下:

# 格式为编号,正确标签,预测标签1,Iris-setosa,Iris-setosa2,Iris-setosa,Iris-setosa3,Iris-setosa,Iris-setosa4,Iris-setosa,Iris-setosa5,Iris-setosa,Iris-setosa6,Iris-setosa,Iris-setosa7,Iris-setosa,Iris-setosa8,Iris-setosa,Iris-setosa9,Iris-setosa,Iris-setosa10,Iris-setosa,Iris-setosa11,Iris-setosa,Iris-setosa12,Iris-setosa,Iris-setosa...Accuracy: 0.946666666666667

我正在尝试在NumPy中做同样的事情。然而,作业不允许我使用for循环,只能使用矢量化函数。

所以,基本上我想做的是:对于测试数据中的每一行,获取训练数据中与之最接近的行的索引(即具有最小欧几里得距离的行)。

以下是我在Python中尝试的代码:

import numpy as npdef main():        # 将CSV的每一行分割成属性和标签的列表    data = [x.split(',') for x in open("iris-training-data.csv")]    # 最后一项是标签    labels = np.array([x[-1].rstrip() for x in data])    # 将前三项转换为二维浮点数数组    floats = np.array([x[0:3] for x in data]).astype(float)    classifyTrainingExamples(labels, floats)def classifyTrainingExamples(labels, floats):    # 我们对测试数据做与训练数据相同的事情    testingData = [x.split(',') for x in open("iris-testing-data.csv")]    testingLabels = np.array([x[-1].rstrip() for x in testingData])    testingFloats = np.array([x[0:3] for x in testingData]).astype(float)    res = np.apply_along_axis(lambda x: closest(floats, x), 1, testingFloats)    correct = 0    for number, index in enumerate(res):            if labels[index] == testingLabels[number]:            correct += 1        print("{},{},{}".format(number + 1, testingLabels[number], labels[index]))        number += 1    print(correct / len(list(res)))def closest(otherArray, item):    res = np.apply_along_axis(lambda x: distance(x, item), 1, otherArray)    i = np.argmin(res)    return i# 获取两个“平面”列表之间的欧几里得距离(即某一特定行)def distance(a, b):    # 逐元素相减,然后每个元素都平方    lst = (a - b) ** 2    # 将所有元素相加,然后取平方根    result = np.sqrt(lst.sum())    return resultmain()

不幸的是,输出看起来像这样

1,Iris-setosa,Iris-setosa2,Iris-setosa,Iris-setosa3,Iris-setosa,Iris-setosa4,Iris-setosa,Iris-setosa....74,Iris-setosa,Iris-setosa75,Iris-setosa,Iris-setosa0.93333333

每行都只有Iris-setosa作为标签,准确率为0.93333333。

我尝试使用调试器逐步检查,发现if语句认为个项目都是正确的(但正确率仍然显示为0.93333333)。

所以,基本上:

  • 它显示每个结果都是“正确”的(显然不是这样的)。
  • 它对每个值都显示Iris-setosa
  • 我的百分比显示为93%。正确值实际上大约是94%,但考虑到每个结果都被认为是“正确”的,我期望这个显示为100%。

有人能帮我看看我遗漏了什么吗?

在任何人问之前,顺便说一下,是的,我确实尝试使用调试器逐步检查了:) 顺便说一下,是的,这是作业。


回答:

如果你真的想在一行中完成,这里是你可以做的(我从scikit-learn下载了数据集):

import numpy as npfrom sklearn import datasetsfrom sklearn.model_selection import train_test_split# 加载数据集iris = datasets.load_iris()X = iris.datay = iris.target# 分割训练和测试集Xtrain, Xtest, ytrain, ytest = train_test_split(X, y, test_size=0.2)# 1-最近邻居    ypred = np.array([ytrain[np.argmin(np.sum((x-Xtrain)**2,axis=1))] for x in Xtest])# 计算分类错误sum(ypred != ytest)/ len(ytest)

现在,这是1-最近邻居,它只查看训练集中最接近的点。对于k-最近邻居,你需要将其更改为这样:

# k-最近邻居    k = 3ypredk = np.array([np.argmax(np.bincount(ytrain[np.argsort(np.sum((x-Xtrain)**2,axis=1))[0:k]])) for x in Xtest])sum(ypredk != ytest)/ len(ytest)

用语言来说,你对距离进行排序,找到k个最低值的索引(这就是np.argsort部分),然后找到对应的标签,然后在k个标签中查找最常见的标签(这就是np.argmax(np.bincount(x))部分)。

最后,如果你想确认,可以与scikit-learn进行比较:

# scikit-learn NNfrom sklearn import neighborsknn = neighbors.KNeighborsClassifier(n_neighbors=k, algorithm='ball_tree')knn.fit(Xtrain,ytrain)ypred_sklearn = knn.predict(Xtest)sum(ypred_sklearn != ytest)/ len(ytest)

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注