文章目录
- KNN
- KNN算法
- KNN in practice
- 推荐系统
- 我们想回答什么问题?
- 探索、清理和准备数据
- 使用算法
- Summary
- 参考文献
KNN
监督学习是一种依赖输入数据来学习函数的算法,该函数在给定新的未标记数据时可以产生适当的输出。
监督学习用于解决分类或回归问题。
分类问题的输出是离散值。例如,“喜欢披萨上的菠萝”和“不喜欢披萨上菠萝”是离散的,没有中间立场。
回归问题的输出是实数(带小数点的数字)。例如,我们可以使用下表中的数据来估计给定身高的人的体重。
我们有一个自变量(或一组自变量)和一个因变量(给定自变量,我们试图猜测的事情)。例如,我们可以说身高是自变量,体重是因变量。
无监督的机器学习算法使用没有任何标签的输入数据——换句话说,没有老师(标签)告诉孩子(计算机)什么时候是正确的,什么时候犯了错误。
监督学习试图学习一个函数,该函数将允许我们在给定一些新的未标记数据的情况下进行预测;无监督学习试图学习数据的基本结构,让我们对数据有更多的了解。
KNN算法
KNN算法假设相似的事物存在于非常接近的地方,换句话说,相似的事物彼此接近。
“Birds of a feather flock together.”
在上图中,大多数情况下,相似的数据点彼此接近。KNN算法取决于这个假设是否足够真实,从而使算法有用。
**直线距离(Euclidean Distance)**是一个流行且熟悉的选择。
The KNN Algorithm:
- Load the data
- Initialize K to your chosen number of neighbors
- For each example in the data: Calculate the distance between the query example and the current example from the data; Add the distance and the index of the example to an ordered collection.
- Sort the ordered collection of distances and indices from smallest to largest (in ascending order) by the distances.
- Pick the first K entries from the sorted collection.
- Get the labels of the selected K entries.
- If regression, return the mean of the K labels.
- If classification, return the mode of the K labels.
# --*-- coding:utf-8 --*--
# @Author : 一只楚楚猫
# @File : 03KNN.py
# @Software : PyCharm
from collections import Counter
import mathdef knn(data, query, k, distance_fn, choice_fn):""":param data: Regression Data:param query: Query Data:param k: K Neighbours:param distance_fn: Euclidean Distance:param choice_fn::return:"""neighbor_distances_and_indices = []# 3. For each example in the datafor index, example in enumerate(data):# 3.1 Calculate the distance between the query example and the current# example from the data.distance = distance_fn(example[:-1], query)# 3.2 Add the distance and the index of the example to an ordered collectionneighbor_distances_and_indices.append((distance, index))# 4. Sort the ordered collection of distances and indices from# smallest to largest (in ascending order) by the distancessorted_neighbor_distances_and_indices = sorted(neighbor_distances_and_indices)# 5. Pick the first K entries from the sorted collectionk_nearest_distances_and_indices = sorted_neighbor_distances_and_indices[:k]# 6. Get the labels of the selected K entriesk_nearest_labels = [data[i][-1] for distance, i in k_nearest_distances_and_indices]# 7. If regression (choice_fn = mean), return the average of the K labels# 8. If classification (choice_fn = mode), return the mode of the K labelsreturn k_nearest_distances_and_indices, choice_fn(k_nearest_labels)def mean(labels):return sum(labels) / len(labels)def mode(labels):"""most_common是Counter类的方法,用于返回出现频率最高的元素及其计数。在这里,most_common(1)返回一个包含一个元组的列表,元组的第一个元素是出现频率最高的元素,第二个元素是该元素出现的次数。由于我们指定参数1,因此它返回出现频率最高的1个元素。"""return Counter(labels).most_common(1)[0][0]def euclidean_distance(point1, point2):sum_squared_distance = 0for i in range(len(point1)):sum_squared_distance += math.pow(point1[i] - point2[i], 2)return math.sqrt(sum_squared_distance)def main():'''# Regression Data## Column 0: height (inches)# Column 1: weight (pounds)'''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],]# Question:# Given the data we have, what's the best-guess at someone's weight if they are 60 inches tall?reg_query = [60]reg_k_nearest_neighbors, reg_prediction = knn(reg_data, reg_query, k=3, distance_fn=euclidean_distance, choice_fn=mean)print(f"reg_prediction: {reg_prediction}")'''# Classification Data# # Column 0: age# Column 1: likes pineapple'''clf_data = [[22, 1],[23, 1],[21, 1],[18, 1],[19, 1],[25, 0],[27, 0],[29, 0],[31, 0],[45, 0],]# Question:# Given the data we have, does a 33 year old like pineapples on their pizza?clf_query = [33]clf_k_nearest_neighbors, clf_prediction = knn(clf_data, clf_query, k=3, distance_fn=euclidean_distance, choice_fn=mode)print(f"cls_prediction: {clf_prediction}")if __name__ == '__main__':main()
Advantages:
- 该算法简单,易于实现。
- 无需构建模型、调整多个参数或做出额外的假设。
- 该算法具有通用性。它可用于分类、回归和搜索。
Disadvantages:
- 随着自变量的增加,算法会明显变慢
KNN in practice
KNN 的主要缺点是随着数据量的增加而明显变慢,这使得它在需要快速做出预测的环境中成为不切实际的选择。
在推荐系统中可以使用KNN算法
推荐系统
我们想回答什么问题?
给定我们的电影数据集,与电影查询最相似的 5 部电影是什么?
探索、清理和准备数据
我们上面的 KNN 实现依赖于结构化数据。它需要采用表格格式。此外,该实现假设所有列都包含数字数据,并且数据的最后一列具有可以执行某些功能的标签。因此,无论我们从哪里获取数据,我们都需要使其符合这些约束。
该数据包含 30 部电影,包括七种类型的每部电影的数据及其 IMDB 评级。标签列全为零,因为我们不使用该数据集进行分类或回归。
此外,在使用 KNN 算法时,电影之间的关系(例如演员、导演和主题)不会被考虑在内,因为捕获这些关系的数据在数据集中丢失了。因此,当我们对数据运行 KNN 算法时,相似性将仅基于所包含的类型和电影的 IMDB 评级。
使用算法
想象一下。我们正在浏览 MoviesXb 网站(一个虚构的 IMDb 衍生产品),然后遇到了《华盛顿邮报》。我们不确定我们是否想看它,但它的类型引起了我们的兴趣;我们对其他类似的电影感到好奇。我们向下滚动到 “更多类似内容” 部分,看看 MoviesXb 会提出什么建议,算法齿轮开始转动。
MoviesXb 网站向其后端发送请求,获取与《华盛顿邮报》最相似的 5 部电影。后端有一个和我们一模一样的推荐数据集。它首先为《华盛顿邮报》创建行表示(更广为人知的名称是特征向量),然后运行类似于下面的程序来搜索与《华盛顿邮报》最相似的 5 部电影,最后将结果发送回 MoviesXb 网站。
import sys"""
python import模块时, 是在sys.path里按顺序查找的。
sys.path是一个列表,里面以字符串的形式存储了许多路径。
使用KNN.py文件中的函数需要先将它的文件路径放到sys.path中
"""
sys.path.append(r"E:\楚楚猫\code\python\02NLP\01文本分析")from KNN import knn, euclidean_distancedef recommend_movies(movie_query, k_recommendations):raw_movies_data = []with open('./data/movies_recommendation_data.csv', 'r') as md:# Discard the first line (headings)next(md)# Read the data into memoryfor line in md.readlines():data_row = line.strip().split(',')raw_movies_data.append(data_row)# Prepare the data for use in the knn algorithm by picking# the relevant columns and converting the numeric columns# to numbers since they were read in as stringsmovies_recommendation_data = []for row in raw_movies_data:data_row = list(map(float, row[2:]))movies_recommendation_data.append(data_row)# Use the KNN algorithm to get the 5 movies that are most# similar to The Post.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_recommendationsif __name__ == '__main__':the_post = [7.2, 1, 1, 0, 0, 0, 0, 1, 0] # feature vector for The Postrecommended_movies = recommend_movies(movie_query=the_post, k_recommendations=5)# Print recommended movie titlesfor recommendation in recommended_movies:print(recommendation[1])
movies_recommendation_data.csv数据获取链接
Summary
KNN算法是一种简单的监督学习算法,用于解决分类问题和回归问题。它很容易实现和理解,但有一个主要缺点,随着数据大小的增长,速度会明显变慢。
KNN的工作原理是查询Query与数据中所有示例之间的距离,选择最接近查询的指定数量(K)。然后投票选出最频繁的标签(在分类的情况下)或对标签进行平均(在回归的情况)。
参考文献
[1]Machine Learning Basics with the K-Nearest Neighbors Algorithm
[2]在一个.py文件中调用另一个py文件中的类或函数
[3]一篇文章入门python基础