K近邻(KNN)算法是一种简单、易于实现的监督机器学习方法,适用于解决分类和回归问题。我们先从一个具体的例子入手。
监督学习算法依赖于带有标签的输入数据,以学习函数。当给定新的未标记数据时,该函数会产生适当的输出。举个例子,如果我们想教会一台计算机识别猪,我们可以展示一些猪的照片和非猪的照片。通过不断地重复这个过程,计算机就能学会区分猪和其他物体。
分类与回归
分类:分类问题的输出是离散值,如“喜欢比萨上的菠萝”或“不喜欢比萨上的菠萝”。分类算法的输出通常表示为整数,如1、-1或0。
回归:回归问题的输出是一个实数,如估计某个人的体重。这类问题通常需要处理连续的数据。
KNN算法假设相似的数据点彼此靠近。也就是说,相似的事物在空间上是接近的。“物以类聚”正是这个概念的体现。
```python from collections import Counter import math
def knn(data, query, k, distancefn, choicefn): neighbordistancesand_indices = []
# 对于数据中的每个示例
for index, example in enumerate(data):
# 计算查询示例和当前示例之间的距离
distance = distance_fn(example[:-1], query)
# 将距离和索引添加到有序集合中
neighbor_distances_and_indices.append((distance, index))
# 按距离从小到大排序
sorted_neighbor_distances_and_indices = sorted(neighbor_distances_and_indices)
# 选取前K个条目
k_nearest_distances_and_indices = sorted_neighbor_distances_and_indices[:k]
# 获取所选K个条目的标签
k_nearest_labels = [data[i][1] for distance, i in k_nearest_distances_and_indices]
# 如果是回归问题,返回K个标签的平均值
if choice_fn == mean:
return k_nearest_distances_and_indices, mean(k_nearest_labels)
# 如果是分类问题,返回K个标签的众数
else:
return k_nearest_distances_and_indices, choice_fn(k_nearest_labels)
def mean(labels): return sum(labels) / len(labels)
def mode(labels): return Counter(labels).most_common(1)[0][0]
def euclideandistance(point1, point2): sumsquareddistance = 0 for i in range(len(point1)): sumsquareddistance += (point1[i] - point2[i]) ** 2 return math.sqrt(sumsquared_distance)
def main(): # 回归数据 reg_data = [ [65.75, 112.99], [71.52, 136.49], [69.40, 153.03], [68.22, 142.34], [67.79, 144.30], [68.70, 123.30], [69.80, 141.49], [70.01, 136.46], [67.90, 112.37], [66.49, 127.45], ]
# 问题:给定这些数据,如果一个人身高60英寸,预测他的体重是多少?
reg_query = [60]
reg_k_nearest_neighbors, reg_prediction = knn(
reg_data, reg_query, k=3, distance_fn=euclidean_distance, choice_fn=mean
)
# 分类数据
clf_data = [
[22, 1],
[23, 1],
[21, 1],
[18, 1],
[19, 1],
[25, 0],
[27, 0],
[29, 0],
[31, 0],
[45, 0],
]
# 问题:根据这些数据,33岁的人是否喜欢在披萨上放菠萝?
clf_query = [33]
clf_k_nearest_neighbors, clf_prediction = knn(
clf_data, clf_query, k=3, distance_fn=euclidean_distance, choice_fn=mode
)
if name == 'main': main() ```
为了选择合适的K值,我们需要多次运行KNN算法,尝试不同的K值,选择一个既能减少错误数量又能在新数据上保持高精度的K值。
注意事项 - 当K值为1时,预测可能会不稳定。 - 随着K值的增加,预测会变得更稳定,但也可能带来更多的错误。 - 如果进行多数投票(如分类问题),通常将K设为奇数,以避免平局。
尽管KNN算法在大数据量下表现不佳,但在需要识别相似对象的问题中仍然有用。例如,在推荐系统中,KNN算法可以通过找到用户可能喜欢的物品来生成推荐。
我们可以构建一个简单的电影推荐系统,通过计算电影之间的相似度来推荐与查询电影最相似的电影。
我们可以使用UCI机器学习库或IMDb数据集,也可以自己创建数据集。
我们需要确保数据符合KNN算法的要求,如将所有列转换为数值型数据,并填充缺失值。
通过运行KNN算法,我们可以找出与查询电影最相似的电影。
```python from knnfromscratch import knn, euclidean_distance
def recommendmovies(moviequery, krecommendations): rawmoviesdata = [] with open('moviesrecommendationdata.csv', 'r') as md: next(md) # 跳过标题行 for line in md.readlines(): datarow = line.strip().split(',') rawmoviesdata.append(data_row)
movies_recommendation_data = []
for row in raw_movies_data:
data_row = list(map(float, row[2:]))
movies_recommendation_data.append(data_row)
recommendation_indices, _ = knn(
movies_recommendation_data, movie_query, k=k_recommendations,
distance_fn=euclidean_distance, choice_fn=lambda x: None
)
movie_recommendations = []
for _, index in recommendation_indices:
movie_recommendations.append(raw_movies_data[index])
return movie_recommendations
if name == 'main': thepost = [7.2, 1, 1, 0, 0, 0, 0, 1, 0] # 电影《邮报》的特征向量 recommendedmovies = recommendmovies(moviequery=thepost, krecommendations=5) for recommendation in recommended_movies: print(recommendation[1]) ```
KNN算法是一种简单有效的监督学习方法,适用于分类和回归问题。虽然它在大数据量下速度较慢,但在解决识别相似对象的问题时仍然很有用。通过正确选择K值,我们可以优化算法的性能。
希望这篇改写的文章对你有所帮助。如果你有任何问题或反馈,欢迎留言交流。