K近邻原理图解

示例数据集包含两个类别(0 和 1)。我使用方形(marker='s')表示类别0,圆形(marker='o')表示类别1。 k 个最近邻样本用绿色边框圈出,并在每个样本旁边添加了标注以表示它们的顺序。在添加测试样本时,我使用了菱形(marker='D')来表示一个与两个类别不同的测试样本,使用五边形(marker='P')来表示一个位于边界区域的测试样本。

import numpy as np
import matplotlib.pyplot as plt

# 生成示例数据
X = np.array([[1, 1], [1, 2], [1.5, 1.5], [1.7, 1.2], [2, 2],
              [2, 3], [2.5, 2.5], [2.8, 3.2], [3, 3.5], [3.3, 3]])
y = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1, 1])

# 绘制散点图
plt.scatter(X[y == 0, 0], X[y == 0, 1], marker='s', label='0', color='blue')
plt.scatter(X[y == 1, 0], X[y == 1, 1], marker='o', label='1', color='red')

# 添加测试样本
test_samples = np.array([[2.7, 3],[1.8, 1.8]])
plt.scatter(test_samples[:, 0], test_samples[:, 1], marker='x', color='green')

# 绘制k个最近邻样本
k = 3
for i, test_sample in enumerate(test_samples):
    distances = np.linalg.norm(X - test_sample, axis=1)  # 计算与测试样本的距离
    nearest_indices = np.argsort(distances)[:k]  # 找到距离最近的k个样本的索引
    nearest_samples = X[nearest_indices]
    
    if i == 0:
        marker = 'D'  # 第一个测试样本与两个类别不同
    else:
        marker = 'P'  # 后两个测试样本位于边界区域
    
####参考教材内容,补全关键代码,重新运行####
    plt.scatter(nearest_sample[:,0],nearest_sample[:,1],facecolors='none',edgecolors='green',s=200,marker=marker)
    
    # 添加标注
    for j, index in enumerate(nearest_indices):
        plt.annotate(f'N{j+1}', (X[index, 0], X[index, 1]), textcoords="offset points", xytext=(0,10), ha='center')

plt.xlabel('X1')
plt.ylabel('X2')
plt.legend()
plt.show()

有监督学习模型评价指标

分类任务评价指标

def calculate_confusion_matrix(y_true, y_pred):
    tp = tn = fp = fn = 0
    for true, pred in zip(y_true, y_pred):
        if true == 1 and pred == 1:
            tp += 1
        elif true == 0 and pred == 0:
            tn += 1
        elif true == 0 and pred == 1:
            fp += 1
        elif true == 1 and pred == 0:
            fn += 1
    return tp, tn, fp, fn

y_true = [1, 0, 1, 1, 0, 1, 0, 1, 0, 0]
y_pred = [1, 0, 1, 0, 1, 0, 1, 1, 0, 1]

tp, tn, fp, fn = calculate_confusion_matrix(y_true, y_pred)

####参考教材内容,补全关键代码,重新运行####
accuracy=(tp+tn)/(tp+tn+fp+fn)
precision=tp/(tp+fp)
recall=tp/(tp+fn)
f1_score=2*(precision*recall)/(precision+recall)
print("混淆矩阵:")
print(f"[[tn={tn} fp={fp}]")
print(f" [fn={fn} tp={tp}]]")

print("准确率accuracy:", accuracy)
print("精确率precision:", precision)
print("召回率recall:", recall)
print("F1分数f1_score:", f1_score)
from sklearn.metrics import confusion_matrix, accuracy_score, \
                            precision_score, recall_score, f1_score
y_true = [1, 0, 1, 1, 0, 1, 0, 1, 0, 0]
y_pred = [1, 0, 1, 0, 1, 0, 1, 1, 0, 1]
####参考教材内容,补全关键代码,重新运行####
cm=confusion_matrix(y_true,y_pred)
print("混淆矩阵:\n",cm)
####参考教材内容,补全关键代码,重新运行####
accurary=accurary_score(y_true,y_pred)
print("准确率:", accuracy)
####参考教材内容,补全关键代码,重新运行####
precision=presion_score(y_true,y_pred)
print("精确率:", precision)
####参考教材内容,补全关键代码,重新运行####
recall=recall_score(y_true,y_pred)
print("召回率:", recall)
####参考教材内容,补全关键代码,重新运行####
f1=f1_score(y_true,y_pred)
print("F1分数:", f1)

回归问题评价指标

# 真实房价和预测房价
y_true = [300, 400, 500, 600, 700]
y_pred = [350, 420, 490, 580, 680]
# 计算均方误差(MSE)
####参考教材内容,补全关键代码,重新运行####
mse=sum((true-pred)**2 for true,pred in zip(y_true,y_pred))/len(y_true)
# 计算均方根误差(RMSE)
rmse = mse ** 0.5
# 计算平均绝对误差(MAE)
####参考教材内容,补全关键代码,重新运行####
mae=sum(abs(true-pred) for true,pred in zip(y_true,y_pred))/len(y_true)
# 计算决定系数(R^2)
mean_y_true = sum(y_true) / len(y_true)
ssr = sum((true - pred) ** 2 for true, pred in zip(y_true, y_pred))
sst = sum((true - mean_y_true) ** 2 for true in y_true)
####参考教材内容,补全关键代码,重新运行####
r2=1-(ssr/sst)
# 打印结果 
print("均方误差(MSE):", mse)
print("均方根误差(RMSE):", rmse)
print("平均绝对误差(MAE):", mae)
print("决定系数(R^2):", r2)
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
# 真实值和预测值
y_true = [300, 400, 500, 600, 700]
y_pred = [350, 420, 490, 580, 680]
# 计算均方误差(mean squared error, MSE)
####参考教材内容,补全关键代码,重新运行####
mse=mean_squared_error(y_true,y_pred)
# 计算平均绝对误差(mean absolute error, MAE)
####参考教材内容,补全关键代码,重新运行####
mae=mean_absolute_error(y_true,y_pred)
# 计算确定系数(coefficient of determination, R^2)
####参考教材内容,补全关键代码,重新运行####
r2=r2_score(y_true,y_pred)
# 打印结果
print("均方误差(MSE):", mse)
print("平均绝对误差(MAE):", mae)
print("确定系数(R^2):", r2)

综合案例:使用K近邻算法预测鸢尾花类型

import pandas as pd
import seaborn as sns
from sklearn.datasets import load_iris

# 加载鸢尾花数据集
iris = load_iris()

# 数据集基本信息
print("数据集基本信息:")
#print(iris.DESCR)

# 转换为 pandas 数据框
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
df['target'] = iris.target

# 打印数据框前 5 行
print("数据框前 5 行:")
####参考教材内容,补全关键代码,重新运行####
print(df.head())

# 数据框统计信息
print("数据框统计信息:")
####参考教材内容,补全关键代码,重新运行####
print(df.describe())

# 按目标变量绘制散点图矩阵
####参考教材内容,补全关键代码,重新运行####
sns.countplot(x='target',data=df)

# 绘制目标变量类别计数图
####参考教材内容,补全关键代码,重新运行####
sns.pairplot(df,hue='target')

总和

import pandas as pd
from sklearn.datasets import load_iris
import csv
import math
import random
from collections import Counter
# 从文件中读取数据集
def load_dataset(filename):
    dataset = []
    with open(filename, 'r') as file:
        csv_reader = csv.reader(file)
        next(csv_reader)  # 跳过第一行
        for row in csv_reader:
            sample = [float(value) for value in row[:-1]]
            label = int(row[-1])
            dataset.append((sample, label))
    return dataset

# 计算欧氏距离
def euclidean_distance(point1, point2):
    squared_distance = 0
    for i in range(len(point1)):
####参考教材内容,补全关键代码,重新运行####
        squared_distance+=(point1[i]-point2[i])**2
    distance = math.sqrt(squared_distance)
    return distance

# K近邻算法
def k_nearest_neighbors(k, dataset, new_point):
    distances = []
    for sample, label in dataset:
####参考教材内容,补全关键代码,重新运行####
        distance=euclidean_distance(sample,new_point)
        distances.append((distance, label))
    distances.sort()  # 按距离排序
    # 取前k个最近的距离
####参考教材内容,补全关键代码,重新运行####
    k_nearest=distances[:k]
    labels = [label for distance, label in k_nearest]
    vote_counts = Counter(labels)  # 统计每个类别的票数
    predicted_label = vote_counts.most_common(1)[0][0]  # 返回票数最多的类别
    return predicted_label

if __name__ == "__main__":
    # 加载鸢尾花数据集
    dataset = load_dataset('iris_dataset.csv')
    # 将数据集拆分为训练集和测试集
    random.seed("zp")
    random.shuffle(dataset)  # 随机打乱数据集顺序
    train_size = int(0.8 * len(dataset))
    train_set = dataset[:train_size]
####参考教材内容,补全关键代码,重新运行####
    test_set=dataset[train_size:]
    # 在测试集上进行预测
    correct_predictions = 0
    for sample, label in test_set:
        predicted_label = k_nearest_neighbors(3, train_set, sample)
        if predicted_label == label:
            correct_predictions += 1

####参考教材内容,补全关键代码,重新运行####
    accurary=correct_prediction/len(test_set)
    print(f"Accuracy: {accuracy}")
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
# 加载鸢尾花数据集
iris = load_iris()
X = iris.data  # 特征数据
y = iris.target  # 目标数据
# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, 
                                                    random_state=10)
# 创建K近邻分类器模型
####参考教材内容,补全关键代码,重新运行##### 这里设置K值为3
model=KNeighborsClassifier(n_neighbors=3)
# 在训练集上训练模型
####参考教材内容,补全关键代码,重新运行####
model.fit(X_train,y_train)
# 在测试集上进行预测
####参考教材内容,补全关键代码,重新运行####
y_pred=model.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print("准确率:", accuracy)

综合案例:使用K近邻算法预测房价

import pandas as pd
import seaborn as sns
# 读取文件,跳过前面的描述信息行
df = pd.read_csv('boston.txt', skiprows=22, delimiter='\s+') 
# 提取特征名称
feature_names = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS',
                 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']
# 设置DataFrame的列名
df.columns = feature_names

# # 分离出data和target
####参考教材内容,补全关键代码,重新运行####
target=df['MEDV']
features=df.drop('MEDV',axis=1)

# 查看数据集的前几行
####参考教材内容,补全关键代码,重新运行####
print(df.head())

# 统计数据集中各个特征的描述性统计信息
####参考教材内容,补全关键代码,重新运行####
print(df.describe())

# 绘制特征之间的相关性热力图
corr_matrix = df.corr()
####参考教材内容,补全关键代码,重新运行####
sns.heatmap(corr_matrix,annot=False)

# 绘制房价的直方图
sns.histplot(df['MEDV'], kde=True)

# 可视化各个特征与房价的关系
sns.pairplot(df, x_vars=['CRIM', 'RM', 'AGE', 'DIS'], y_vars='MEDV', kind='scatter')

总和

import math
import random

# 计算欧氏距离
def euclidean_distance(point1, point2):
    squared_distance = 0
    for i in range(len(point1)):
        squared_distance += (point1[i] - point2[i]) ** 2
    distance = math.sqrt(squared_distance)
    return distance

# 读取波士顿数据集
def load_dataset(filename):
    dataset = []
    with open(filename, 'r') as file:
        for line in file:
            data = line.strip().split()
            sample = [float(value) for value in data]
            dataset.append(sample)
    return dataset

# 划分训练集和测试集
def split_dataset(dataset, split_ratio):
    random.shuffle(dataset)  # 打乱数据集顺序
    train_size = int(len(dataset) * split_ratio)
    train_set = dataset[:train_size]
    test_set = dataset[train_size:]
    return train_set, test_set

# K近邻算法(用于回归)
def k_nearest_neighbors_regression(k, train_set, new_point):
    distances = []
    for sample in train_set:
        distance = euclidean_distance(sample[:-1], new_point[:-1])
        distances.append((distance, sample))
    distances.sort()  # 按距离排序
    k_nearest = distances[:k]  # 取前k个最近的距离
    total_value = sum(sample[-1] for distance, sample in k_nearest)
####参考教材内容,补全关键代码,重新运行####
    predicted_value=total_value/k
    return predicted_value

if __name__ == "__main__":
    # 生成样本数据集
    #dataset = load_dataset('data\\ch02\\boston.housing.data') #win
    #dataset = load_dataset('data/ch02/boston.housing.data') #linux
    dataset = load_dataset('boston.housing.data') #linux

    # 将数据集划分为训练集和测试集
    train_set, test_set = split_dataset(dataset, 0.8)

    # 随机选择一个新的测试点
    random.seed("zp")
    new_point = random.choice(test_set)

    # 使用K近邻算法进行回归预测
####参考教材内容,补全关键代码,重新运行####
    predicted_value=k_nearest_neighbors_regression(5,train_set,new_point)
    print("新测试样本:")
    print(new_point[:-1])  # 打印特征值
    print("预测房价中位数:", predicted_value)
    print("真实房价中位数:", new_point[-1])

len(dataset[1])

import numpy as np
import pandas as pd
#from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsRegressor
from sklearn.metrics import mean_squared_error
# 读取波士顿数据集
def load_dataset(filename):
    dataset = []
    with open(filename, 'r') as file:
        for line in file:
            data = line.strip().split()
            sample = [float(value) for value in data]
            dataset.append(sample)
    return dataset
# 加载波士顿房价数据集
#data = load_dataset('data\\ch02\\boston.housing.data')
#data = load_dataset('data/ch02/boston.housing.data') #linux
data = load_dataset('boston.housing.data') #linux
df = pd.DataFrame(data)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(df.iloc[:, :-1], df.iloc[:, -1], 
                                                    test_size=0.2, random_state=42)
# 构建K近邻回归模型
k = 3  # 可调节K值
####参考教材内容,补全关键代码,重新运行####
model=KNeighborsRegressor(n_neighbors=3)
####参考教材内容,补全关键代码,重新运行####
model.fit(X_train,y_train)
# 预测测试集
y_pred = model.predict(X_test)
# 计算均方误差(MSE)
####参考教材内容,补全关键代码,重新运行####
mse=mean_squared_error(y_test,y_pred)
print("均方误差(MSE):", mse)