下面是一个完整的K近邻算法(K-Nearest Neighbors, KNN)实例,用于判断电影类型。
我们假设有一组电影数据集,每部电影都有两个特征:动作场面数量和爱情场景数量。根据这些特征,我们可以通过KNN算法来判断一部新电影的类型是动作片还是爱情片。
数据集
假设我们有以下训练数据:
电影 | 动作场面数量 | 爱情场景数量 | 类型 |
---|---|---|---|
1 | 8 | 3 | 动作片 |
2 | 1 | 10 | 爱情片 |
3 | 5 | 2 | 动作片 |
4 | 2 | 8 | 爱情片 |
5 | 6 | 1 | 动作片 |
6 | 1 | 9 | 爱情片 |
新电影
我们有一部新电影,动作场面数量为4,爱情场景数量为5。我们需要预测这部新电影的类型。
KNN算法步骤
- 计算距离:计算新电影与训练集中所有电影之间的距离(通常使用欧氏距离)。
- 选择K值:选择最近的K个邻居。
- 投票:K个邻居中最多的类型即为新电影的预测类型。
手写实现
以下是一个使用Python实现KNN算法的完整实例:
import math
from collections import Counter
# 定义电影数据集
movies = [
{"features": (8, 3), "label": "动作片"},
{"features": (1, 10), "label": "爱情片"},
{"features": (5, 2), "label": "动作片"},
{"features": (2, 8), "label": "爱情片"},
{"features": (6, 1), "label": "动作片"},
{"features": (1, 9), "label": "爱情片"},
]
# 新电影的特征
new_movie = (4, 5)
# 计算欧氏距离的函数
def euclidean_distance(point1, point2):
return math.sqrt(sum((x - y) ** 2 for x, y in zip(point1, point2)))
# KNN算法
def knn(movies, new_movie, k):
# 计算所有电影与新电影的距离
distances = [(movie, euclidean_distance(movie["features"], new_movie)) for movie in movies]
# 按距离排序并选择前K个邻居
k_nearest_neighbors = sorted(distances, key=lambda x: x[1])[:k]
# 获取K个邻居的类型
k_labels = [neighbor[0]["label"] for neighbor in k_nearest_neighbors]
# 统计每个类型的数量,返回出现最多的类型
most_common_label = Counter(k_labels).most_common(1)[0][0]
return most_common_label
# 使用KNN算法预测新电影的类型
k = 3 # 选择K值
predicted_label = knn(movies, new_movie, k)
print(f"新电影的预测类型是: {predicted_label}")
运行结果
运行上述代码,将输出:
新电影的预测类型是: 动作片
解释
- 计算距离:我们计算新电影(4, 5)与所有训练电影的欧氏距离。
- 选择K值:选择距离最近的3部电影(K=3)。
- 投票:在这3部电影中,动作片的数量最多(假设为2部),所以预测新电影的类型为动作片。
代码解析
# 统计每个类型的数量,返回出现最多的类型
most_common_label = Counter(k_labels).most_common(1)[0][0]
1. Counter(k_labels)
Counter
是 Python 的 collections
模块中的一个类,用于计数可迭代对象中的元素。k_labels
是一个包含K个最近邻样本的标签列表,Counter(k_labels)
会生成一个字典,键为标签,值为该标签在 k_labels
中出现的次数。
例如,如果 k_labels = ['a', 'b', 'a', 'a', 'c', 'b']
,则 Counter(k_labels)
结果为 Counter({'a': 3, 'b': 2, 'c': 1})
。
2. most_common(1)
Counter
对象的 most_common
方法返回一个列表,列表中的元素是按照出现频率从高到低排序的元组 (元素, 频率)
。most_common(1)
返回一个包含频率最高的一个元素及其频率的列表。
例如,Counter({'a': 3, 'b': 2, 'c': 1}).most_common(1)
返回 [('a', 3)]
。
3. [0]
most_common(1)
返回的是一个列表,取 [0]
表示获取该列表中的第一个元素,即频率最高的那个 (元素, 频率)
元组。
例如,[('a', 3)]
的 [0]
是 ('a', 3)
。
4. [0]
最后的 [0]
表示获取元组中的第一个元素,即标签本身。
例如,('a', 3)
的 [0]
是 'a'
。
在这个例子中,k_labels
包含 6 个标签。Counter(k_labels)
会生成一个计数器 Counter({'a': 3, 'b': 2, 'c': 1})
。然后,most_common(1)
返回 [('a', 3)]
,表示标签 'a'
出现了 3 次,是最常见的标签。最后,通过 [0][0]
提取出 'a'
作为结果。
通过这个实例,我们展示了如何使用KNN算法来判断新电影的类型。这个过程可以扩展到更多的特征和更大的数据集,并且可以调整K值以获得更好的结果。
调用scikit-learn库的写法
以下是一个使用scikit-learn
实现KNN算法的完整实例:
from sklearn.neighbors import KNeighborsClassifier
# 定义电影数据集的特征和标签
X = [
[8, 3],
[1, 10],
[5, 2],
[2, 8],
[6, 1],
[1, 9]
]
y = ["动作片", "爱情片", "动作片", "爱情片", "动作片", "爱情片"]
# 定义新电影的特征
new_movie = [[4, 5]]
# 创建KNN分类器
k = 3 # 选择K值
knn = KNeighborsClassifier(n_neighbors=k)
# 用训练数据拟合模型
knn.fit(X, y)
# 使用模型预测新电影的类型
predicted_label = knn.predict(new_movie)
print(f"新电影的预测类型是: {predicted_label[0]}")
运行结果
运行上述代码,将输出:
新电影的预测类型是: 动作片
解释
- 定义数据集:我们将电影的数据集分为特征
X
和标签y
。 - 定义新电影的特征:
new_movie
表示新电影的特征。 - 创建KNN分类器:使用
KNeighborsClassifier
创建KNN分类器,并设定K值为3。 - 拟合模型:用训练数据拟合模型。
- 预测:使用训练好的模型预测新电影的类型。
使用scikit-learn
库,我们可以更加简洁地实现KNN算法,简化了计算距离、排序和投票的过程。