KNN概述
测量不同特征值之间的距离来进行分类
优点: 精度高、对异常值不敏感、无数据输入设定
缺点: 计算复杂度高、空间复杂度高
1.样本集中的每个数据都有分类标签
2.输入一个新数据
3.分别计算新数据和样本集中所有的数据之间的距离
4.取前K个距离最近的样本的标签作为新数据的标签
有如下二维平面,其中红点代表A类,绿点代表B类,现在有一个蓝点,如果要预测这个蓝点的类别,那么就要算出这个蓝点和所有点的距离,然后选其中前K个距离最小的点的类别作为这个蓝点的类别
假设数据集中某个点为
[
x
i
,
y
i
]
[x_i, y_i]
[xi,yi],蓝点坐标为
[
x
,
y
]
[x, y]
[x,y],那么距离计算公式:
d
=
(
x
−
x
i
)
2
+
(
y
−
y
i
)
2
d=\sqrt{(x-x_i)^2+(y-y_i)^2}
d=(x−xi)2+(y−yi)2
如果是在三维立体空间中呢?其实也就是对二维的扩展,在
x
,
y
x, y
x,y 的基础上,再加上了个
z
z
z,距离由平面距离变成了空间距离
假设数据集中某个点为
[
x
i
,
y
i
,
z
i
]
[x_i, y_i, z_i]
[xi,yi,zi],蓝点坐标为
[
x
,
y
,
z
]
[x, y, z]
[x,y,z],那么距离计算公式为:
d
=
(
x
−
x
i
)
2
+
(
y
−
y
i
)
2
+
(
z
−
z
i
)
2
d=\sqrt{(x-x_i)^2+(y-y_i)^2+(z-z_i)^2}
d=(x−xi)2+(y−yi)2+(z−zi)2
机器学习中,一个数据一般由多个特征组成,上面的二维平面的数据存在2个特征值,
x
x
x 和
y
y
y,三维立体空间的数据存在三个特征值
x
、
y
、
z
x、y、z
x、y、z,那么如果一个数据有4个、5个、6个…
N
N
N 个特征呢?这个维度人就没法理解了,但是公式可以按规律推导:
d
=
(
x
−
x
i
)
2
+
(
y
−
y
i
)
2
+
(
z
−
z
i
)
2
+
.
.
.
+
(
n
−
n
i
)
2
d=\sqrt{(x-x_i)^2+(y-y_i)^2+(z-z_i)^2+...+(n-n_i)^2}
d=(x−xi)2+(y−yi)2+(z−zi)2+...+(n−ni)2
即,计算 n n n个特征值之间的差的平方和,然后再开根号,这个 距离 就比较抽象了,不过我们的确可以根据这个距离,预测出一个样本最合适的分类
KNN实战:糖尿病预测
下面来用Python来实现一个KNN算法,来对印第安人的糖尿病进行预测,数据集下载地址为:https://www.kaggle.com/uciml/pima-indians-diabetes-database
def classify(inx, train_matrix, train_labels, k):
row = train_matrix.shape[0]
inx = np.tile(inx, (row, 1))
diff_matrix = inx - train_matrix
sq_diff_mat = diff_matrix ** 2
sq_distances = sq_diff_mat.sum(axis=1)
distances = sq_distances ** 0.5
sorted_dist_index = distances.argsort()
class_count = {}
for i in range(k): # 选择距离最小的K个点
vote_label = train_labels[sorted_dist_index[i]]
class_count[vote_label] = class_count.get(vote_label, 0) + 1
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
return sorted_class_count[0][0]
上面这段代码输入参数为预测样本向量 inx,训练样本数据 train_matrix,训练样本标签 train_labels,以及选择的邻居数 k,上面这段代码实现了计算一个输入样本与所有已标记样本之间的距离,然后求取距离最近的 k 个邻居中,代表率最高的标签,然后将这个标签返回
def create_dataset(x, y, index_list):
num = len(index_list)
matrix = np.zeros((num, 8))
labels = np.zeros(num)
for i in range(num):
matrix[i] = x[index_list[i]]
labels[i] = y[index_list[i]]
return matrix, labels
def diabetes_classify():
data = pd.read_csv('pima-indians-diabetes/diabetes.csv')
x = data.iloc[:, 0:8].values # 取前8个特征
y = data.iloc[:, 8].values # 取第8个即标签
train_index_list = list(range(len(x)))
test_index_list = random.sample(train_index_list, 200) # 随机选取200个作为测试数据
for index in test_index_list:
train_index_list.remove(index)
train_matrix, train_labels = create_dataset(x, y, train_index_list)
test_matrix, test_labels = create_dataset(x, y, test_index_list)
error_count = 0.0
for test_vec, test_label in zip(test_matrix, test_labels):
pred_label = classify(test_vec, train_matrix, train_labels, 3)
print("the classifier came back with: %d, the real answer is: %d" % (pred_label, test_label))
if pred_label != test_label:
error_count += 1.0
print("===================prediction error====================")
print("the total number of errors is: %d" % error_count)
print("the total error rate is: %f" % (error_count / len(test_index_list)))
上面这段代码是将糖尿病数据集做了读取与划分,随机创建了训练数据集和测试数据集,该数据集共有768条数据,这里随机抽取了200条作为测试数据,然后用调用KNN算法分类器classify来进行预测,运行代码,可以得到输出如下:
the total number of errors is: 53
the total error rate is: 0.265000
可以看到,错误率为0.265000,即准确率为73.5%,这个结果还是比较令人满意的