探索 K 近邻分类器:代码演示与工作原理

2024年08月23日 由 alex 发表 64 0

想象一下,有一种方法可以通过查看以前见过的最相似的例子来进行预测。这就是近邻分类器的精髓--一种简单而直观的算法,为机器学习带来了现实世界的逻辑。


虚拟分类器设定了最低的性能标准,而近邻分类器则模仿了我们在日常生活中经常做出决策的方式:回忆过去类似的经历。这就像通过询问邻居今天的天气如何,来决定自己应该穿什么衣服一样。在数据科学领域,这种分类器会检查最接近的数据点来进行预测。


定义

K 近邻分类器是一种机器学习模型,它根据特征空间中 K 个最近数据点的多数类别进行预测。KNN 算法假定相似的事物存在于近处,因此直观易懂。


2


使用的数据集

在本文中,我们将以这个简单的人工高尔夫数据集为例。该数据集根据天气条件预测一个人是否会打高尔夫。它包括前景、温度、湿度和风力等特征,目标变量是是否打高尔夫球。


3


# Import libraries
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import pandas as pd
import numpy as np
# Make the dataset
dataset_dict = {
    'Outlook': ['sunny', 'sunny', 'overcast', 'rainy', 'rainy', 'rainy', 'overcast', 'sunny', 'sunny', 'rainy', 'sunny', 'overcast', 'overcast', 'rainy', 'sunny', 'overcast', 'rainy', 'sunny', 'sunny', 'rainy', 'overcast', 'rainy', 'sunny', 'overcast', 'sunny', 'overcast', 'rainy', 'overcast'],
    'Temperature': [85.0, 80.0, 83.0, 70.0, 68.0, 65.0, 64.0, 72.0, 69.0, 75.0, 75.0, 72.0, 81.0, 71.0, 81.0, 74.0, 76.0, 78.0, 82.0, 67.0, 85.0, 73.0, 88.0, 77.0, 79.0, 80.0, 66.0, 84.0],
    'Humidity': [85.0, 90.0, 78.0, 96.0, 80.0, 70.0, 65.0, 95.0, 70.0, 80.0, 70.0, 90.0, 75.0, 80.0, 88.0, 92.0, 85.0, 75.0, 92.0, 90.0, 85.0, 88.0, 65.0, 70.0, 60.0, 95.0, 70.0, 78.0],
    'Wind': [False, True, False, False, False, True, True, False, False, False, True, True, False, True, True, False, False, True, False, True, True, False, True, False, False, True, False, False],
    'Play': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'No', 'No', 'Yes', 'Yes', 'No', 'No', 'No', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'No', 'Yes']
}
original_df = pd.DataFrame(dataset_dict)
print(original_df)


KNN 算法要求首先对数据进行缩放。将分类列转换为 0 和 1,并对数字特征进行缩放,这样就不会有单一特征主导距离度量。


4


from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# Preprocess data
df = pd.get_dummies(original_df, columns=['Outlook'], prefix='', prefix_sep='', dtype=int)
df['Wind'] = df['Wind'].astype(int)
df['Play'] = (df['Play'] == 'Yes').astype(int)
df = df[['sunny','rainy','overcast','Temperature','Humidity','Wind','Play']]
# Split data and standardize features
X, y = df.drop(columns='Play'), df['Play']
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.5, shuffle=False)
scaler = StandardScaler()
float_cols = X_train.select_dtypes(include=['float64']).columns
X_train[float_cols] = scaler.fit_transform(X_train[float_cols])
X_test[float_cols] = scaler.transform(X_test[float_cols])
# Print results
print(pd.concat([X_train, y_train], axis=1).round(2), '\n')
print(pd.concat([X_test, y_test], axis=1).round(2), '\n')


主要机制

KNN 分类器的工作原理是找到新数据点的 K 个近邻,然后投票选出这些近邻中最常见的类别。工作原理如下:

  1. 计算新数据点与训练集中所有点之间的距离。
  2. 根据这些距离选择 K 个最近的邻居。
  3. 对这 K 个邻居的类别进行多数表决。
  4. 将多数人的类别分配给新数据点。


5


训练步骤

与许多其他算法不同,KNN 没有明显的训练阶段。相反,它会记忆整个训练数据集。具体过程如下:


1. 为 K(需要考虑的邻居数量)选择一个值。


6


from sklearn.neighbors import KNeighborsClassifier
# Select the Number of Neighbors ('k')
k = 5


2. 选择一个距离度量(如欧氏距离、曼哈顿距离)。


7


import numpy as np
# Choose a Distance Metric
distance_metric = 'euclidean'
# Trying to calculate distance between ID 0 and ID 1
print(np.linalg.norm(X_train.loc[0].values - X_train.loc[1].values))


3. 存储/记忆所有训练数据点及其相应标签)。


# Initialize the k-NN Classifier
knn_clf = KNeighborsClassifier(n_neighbors=k, metric=distance_metric)
# "Train" the kNN (although no real training happens)
knn_clf.fit(X_train, y_train)


分类步骤

近邻分类器一旦经过 “训练”(即存储了训练数据),就会对新实例进行预测:


1. 距离计算: 对于新实例,使用所选的距离度量计算其与所有已存储的训练实例的距离。


8


from scipy.spatial import distance
# Compute the distances from the first row of X_test to all rows in X_train
distances = distance.cdist(X_test.iloc[0:1], X_train, metric='euclidean')
# Create a DataFrame to display the distances
distance_df = pd.DataFrame({
    'Train_ID': X_train.index,
    'Distance': distances[0].round(2),
    'Label': y_train
}).set_index('Train_ID')
print(distance_df.sort_values(by='Distance'))


2. 邻居选择和预测: 根据计算出的距离找出 K 个最近的邻居,然后将这些邻居中最常见的类别作为新实例的预测类别。


9


# Use the k-NN Classifier to make predictions
y_pred = knn_clf.predict(X_test)
print("Label     :",list(y_test))
print("Prediction:",list(y_pred))


评估步骤


10


from sklearn.metrics import accuracy_score
# Evaluation Phase
accuracy = accuracy_score(y_test, y_pred)
print(f'Accuracy: {accuracy.round(4)*100}%')


关键参数

虽然 KNN 在概念上很简单,但它确实有几个重要参数:


1. K:要考虑的邻居数量。较小的 K 会导致对噪声敏感的结果,而较大的 K 则会使决策边界变得平滑。


11


labels, predictions, accuracies = list(y_test), [], []
k_list = [3, 5, 7]
for k in k_list:
    knn_clf = KNeighborsClassifier(n_neighbors=k)
    knn_clf.fit(X_train, y_train)
    y_pred = knn_clf.predict(X_test)
    predictions.append(list(y_pred))
    accuracies.append(accuracy_score(y_test, y_pred).round(4)*100)
df_predictions = pd.DataFrame({'Label': labels})
for k, pred in zip(k_list, predictions):
    df_predictions[f'k = {k}'] = pred
df_accuracies = pd.DataFrame({'Accuracy ': accuracies}, index=[f'k = {k}' for k in k_list]).T
print(df_predictions)
print(df_accuracies)


2. 距离度量:决定点间相似度的计算方式。常见选项包括:

  • 欧氏距离(直线距离)
  • 曼哈顿距离(绝对差值之和)
  • 闵科夫斯基距离(欧氏距离和曼哈顿距离的概括)


3. 加权函数: 这决定了如何对每个邻居的贡献进行加权。选项包括

  • 统一: 所有邻居的权重相同。
  • 距离: 距离较近的邻居比距离较远的邻居影响更大。


总结

K-Nearest Neighbors (KNN) 分类器是机器学习的基本算法,为分类任务提供了直观有效的方法。它的简单性使其成为初学者的理想起点,而它的多功能性则确保了其对经验丰富的数据科学家的价值。KNN 的强大之处在于它能够根据数据点的接近程度进行预测,而无需复杂的训练过程。


不过,重要的是要记住,KNN 只是庞大的机器学习工具包中的一个工具。当你在数据科学之旅中取得进步时,请将 KNN 作为了解更复杂算法的垫脚石,在选择模型时始终考虑你的具体数据特征和问题要求。


k 近邻分类器代码汇总


# Import libraries
import pandas as pd
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score
# Load data
dataset_dict = {
    'Outlook': ['sunny', 'sunny', 'overcast', 'rainy', 'rainy', 'rainy', 'overcast', 'sunny', 'sunny', 'rainy', 'sunny', 'overcast', 'overcast', 'rainy', 'sunny', 'overcast', 'rainy', 'sunny', 'sunny', 'rainy', 'overcast', 'rainy', 'sunny', 'overcast', 'sunny', 'overcast', 'rainy', 'overcast'],
    'Temperature': [85.0, 80.0, 83.0, 70.0, 68.0, 65.0, 64.0, 72.0, 69.0, 75.0, 75.0, 72.0, 81.0, 71.0, 81.0, 74.0, 76.0, 78.0, 82.0, 67.0, 85.0, 73.0, 88.0, 77.0, 79.0, 80.0, 66.0, 84.0],
    'Humidity': [85.0, 90.0, 78.0, 96.0, 80.0, 70.0, 65.0, 95.0, 70.0, 80.0, 70.0, 90.0, 75.0, 80.0, 88.0, 92.0, 85.0, 75.0, 92.0, 90.0, 85.0, 88.0, 65.0, 70.0, 60.0, 95.0, 70.0, 78.0],
    'Wind': [False, True, False, False, False, True, True, False, False, False, True, True, False, True, True, False, False, True, False, True, True, False, True, False, False, True, False, False],
    'Play': ['No', 'No', 'Yes', 'Yes', 'Yes', 'No', 'Yes', 'No', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'No', 'No', 'Yes', 'Yes', 'No', 'No', 'No', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'Yes', 'No', 'Yes']
}
df = pd.DataFrame(dataset_dict)
# Preprocess data
df = pd.get_dummies(df, columns=['Outlook'], prefix='', prefix_sep='', dtype=int)
df['Wind'] = df['Wind'].astype(int)
df['Play'] = (df['Play'] == 'Yes').astype(int)
# Split data
X, y = df.drop(columns='Play'), df['Play']
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.5, shuffle=False)
# Standardize features
scaler = StandardScaler()
float_cols = X_train.select_dtypes(include=['float64']).columns
X_train[float_cols] = scaler.fit_transform(X_train[float_cols])
X_test[float_cols] = scaler.transform(X_test[float_cols])
# Train model
knn_clf = KNeighborsClassifier(n_neighbors=3, metric='euclidean')
knn_clf.fit(X_train, y_train)
# Predict and evaluate
y_pred = knn_clf.predict(X_test)
print(f"Accuracy: {accuracy_score(y_test, y_pred)}")



文章来源:https://medium.com/towards-data-science/k-nearest-neighbor-classifier-explained-a-visual-guide-with-code-examples-for-beginners-a3d85cad00e1
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消