部分代码用法

ndarray数组采用的是广播式运算,即可以一个数组加减一组数组,示例如下:

1
2
3
m = np.array([1,2,3])
n = np.array([[4,5,6],[7,8,9]])
m-n

结果如下:

1
2
array([[-3, -3, -3],
[-6, -6, -6]])

对结果分别平方求和可用代码:

1
2
x= np.sum((m-n)**2, axis=1)
x

结果如下:

1
array([ 27, 108], dtype=int32)

KNN分类

1. 读取数据

1
2
import numpy as np
import pandas as pd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 读取鸢尾花数据集,header参数来指定标题的行,默认为0,如果没有则使用None

data = pd.read_csv(r"iris.csv", header = 0)

# 显示前n行记录,默认为5
# data.head(10)
# 随机显示记录,默认值为1
# data.sample(10)

# 将类别文本映射成为数值类型

data["Species"] = data["Species"].map({"versicolor": 0,"setosa": 1,"virginica": 2 })

# 删除不需要的第1列

data.drop("Unnamed: 0", axis=1,inplace=True)

# 删除重复的数据

data.drop_duplicates(inplace=True)

# 查看各个类别鸢尾花有多少条记录

data["Species"].value_counts()

数据显示如下:

1
2
3
4
0    50
1 50
2 49
Name: Species, dtype: int64

2. 创建KNN对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class KNN:
"""用python语言实现K邻近算法"""
def __init__(self,k):
"""
初始化方法
k:int,邻居的个数
"""
self.k = k

def fit(self, X, y):
"""
训练方法
X:类数组类型,形状为:[样本数量,特征数量]
待训练的样本特征(属性)

y:类数组类型,形状为:[样本数量]
每个样本的目标值(标签)
"""
# 将X转化成ndarray类型

self.X = np.asarray(X)
self.y = np.asarray(y)

def predict(self, X):
"""
根据参数传递的样本,对样本数据进行预测

X:类数组类型,形状为:[样本数量,特征数量]
待训练的样本特征(属性)

result:数组类型
预测的结果

"""
X = np.asarray(X)
result = []
# 对ndarray数组进行遍历,每次取其中一行
for x in X:
dis = np.sqrt(np.sum((x-self.X)**2, axis=1))
# 返回数组排列后每个元素在原数组(排序前的数组)中的索引
index = dis.argsort()
# 进行截断,只取前k个元素 (取最近的k个元素的索引)
index = index[:self.k]
# 返回数组中每个元素出现的次数,元素必须是非负数
count = np.bincount(self.y[index])
# 返回ndarray数组中值最大的元素对应的索引
# 最大元素索引就是出现次数最多的元素
result.append(count.argmax())
return np.asarray(result)

3. 训练和测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 提取每个类别的鸢尾花数据

t0 = data[data["Species"] == 0]
t1 = data[data["Species"] == 1]
t2 = data[data["Species"] == 2]

# 对每个类别的数据进行洗牌

t0 = t0.sample(len(t0), random_state=0)
t1 = t1.sample(len(t1), random_state=0)
t2 = t2.sample(len(t2), random_state=0)

# 构建训练集和测试集

train_X = pd.concat([t0.iloc[:40, :-1], t1.iloc[:40, :-1], t2.iloc[:40, :-1]], axis=0)
train_y = pd.concat([t0.iloc[:40, -1], t1.iloc[:40, -1], t2.iloc[:40, -1]], axis=0)
test_X = pd.concat([t0.iloc[40:, :-1], t1.iloc[40:, :-1], t2.iloc[40:, :-1]], axis=0)
test_y = pd.concat([t0.iloc[40:, -1], t1.iloc[40:, -1], t2.iloc[40:, -1]], axis=0)

# 创建KNN对象,进行训练和测试

knn = KNN(k=3)

# 进行训练

knn.fit(train_X, train_y)

# 进行测试,获得测试的结果

result = knn.predict(test_X)
# display(result)
display(np.sum(result==test_y))
display(np.sum(result==test_y)/len(result))

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
28
0.9655172413793104
86 True
71 True
69 True
59 True
89 True
96 True
53 True
50 True
97 True
94 True
36 True
21 True
19 True
9 True
39 True
46 True
3 True
0 True
47 True
44 True
121 True
119 False
109 True
139 True
146 True
103 True
100 True
148 True
145 True
Name: Species, dtype: bool

4. 可视化

1
2
import matplotlib as mpl
import matplotlib.pyplot as plt
1
2
3
4
5
# 默认情况下matplotlib不支持中文显示,我们需要进行一下设置
# 设置字体为黑体
mpl.rcParams["font.family"] = "SimHei"
# 设置在中文字体时,能够正确显示负号(-)
mpl.rcParams["axes.unicode_minus"] = False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# {"versicolor": 0,"setosa": 1,"virginica": 2 }
# 设置画布的大小
plt.figure(figsize=(10,10))
# 绘制训练集数据
plt.scatter(x=t0["Sepal.Length"][:40], y=t0["Petal.Length"][:40], color = "r", label = "versicolor")
plt.scatter(x=t1["Sepal.Length"][:40], y=t1["Petal.Length"][:40], color = "g", label = "setosa")
plt.scatter(x=t2["Sepal.Length"][:40], y=t2["Petal.Length"][:40], color = "b", label = "virginica")

# 绘制测试集数据
right = test_X[result == test_y]
wrong = test_X[result != test_y]
plt.scatter(x=right["Sepal.Length"], y=right["Petal.Length"], color = "c", marker="x", label="right")
plt.scatter(x=wrong["Sepal.Length"], y=wrong["Petal.Length"], color = "m", marker=">", label="wrong")
plt.xlabel("花萼长度")
plt.ylabel("花瓣长度")
plt.title("KNN分类结果显示")
plt.legend(loc="best")
plt.show()

image-20220908190059814