knn算法学习

KNN算法的实现

data = pd.read_csv(r'C:\Users\86187\Desktop\iris.csv')
data_describe = data.describe().T
print(data_describe)
p = data.hist(figsize=(20, 20))
plt.show()
color_wheel = {
    "1": "red",
    "2": "blue",
    "3": "green"
}
colors = data["Species"].map(lambda x: color_wheel.get(x))
print(data.Species.value_counts())
p=data.Species.value_counts().plot(kind='bar')
plt.show()

首先,导入数据集然后显示数据并以直方图显示占比

然后对数据进行归一化


sc_X = StandardScaler()
X = pd.DataFrame(sc_X.fit_transform(data.drop(["Species"], axis=1)),
                 columns=['Sepal.Length', 'Sepal.Width', 'Petal.Length', 'Petal.Width'])
X.head()
print(X.head())

再划分测试集和训练集

from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=1/3,random_state=42, stratify=y)
train_scores = []
test_scores = []

knn的算法

def euclidean_distance(point1, point2):
    point1 = np.array(point1, dtype=float)  # 将 point1 转换为浮点数数组
    point2 = np.array(point2, dtype=float)  # 将 point2 转换为浮点数数组
    distance = np.sqrt(np.sum((point2 - point1)**2))
    return distance
class MyKNN:
    def __init__(self, k):
        self.k = k
        self.X_train = None
        self.y_train = None
        self.label_encoder = LabelEncoder()

    def fit(self, X, y):
        self.X_train = X
        self.y_train = self.label_encoder.fit_transform(y)

    def predict(self, X):
        y_pred = [self._predict(x) for x in X]
        return np.array(y_pred)

    def _predict(self, x):
        distances = [euclidean_distance(x, x_train) for x_train in self.X_train]
        k_indices = np.argsort(distances)[:self.k]
        k_nearest_labels = [self.y_train[i] for i in k_indices]
        most_common = np.bincount(k_nearest_labels).argmax()
        return most_common

    def score(self, X, y):
        y_pred = self.predict(X)
        y_encoded = self.label_encoder.transform(y)
        accuracy = np.sum(y_pred == y_encoded) / len(y)
        return accuracy

训练加评估

my_knn = MyKNN(1) 
X_train_np = X_train.values  
X_test_np = X_test.values

train_scores = []
test_scores = []

for i in range(3, 20):
    my_knn.k = i  
    my_knn.fit(X_train_np, y_train) 
    train_score = my_knn.score(X_train_np, y_train) 
    test_score = my_knn.score(X_test_np, y_test) 

    train_scores.append(train_score)  # 将训练集得分存入列表
    test_scores.append(test_score)  # 将测试集得分存入列表

max_train_score = max(train_scores)
train_scores_ind = [i for i, v in enumerate(train_scores) if v == max_train_score]
print('Max train score {} % and k = {}'.format(max_train_score * 100, list(map(lambda x: x + 1, train_scores_ind))))
max_test_score = max(test_scores)
test_scores_ind = [i for i, v in enumerate(test_scores) if v == max_test_score]
print('Max test score {} % and k = {}'.format(max_test_score*100,list(map(lambda x: x+1, test_scores_ind))))

计算出各个K值的准确率然后再画出折线图

p = sns.lineplot(x=range(3,k),y=train_scores,marker='*',label='Train Score')
p = sns.lineplot(x=range(3,k),y=test_scores,marker='o',label='Test Score')
plt.xlabel('k')
plt.ylabel('accuracy')
plt.show()

遇到的难题:

1.安装库出现的各种问题,最后选择在虚拟环境中完成实验

2.各种函数以及数据集导入出现的问题

3.绘制图像的难题

常见的分类模型评估指标

常见的分类模型评估指标包括以下几种:

准确率:模型正确预测的样本数占总样本数的比例,是最常见的评估指标之一。计算公式为:[ Accuracy = \frac{TP + TN}{TP + TN + FP + FN} ]

精确率:指模型预测为正类的样本中,实际为正类的比例。计算公式为:[ Precision = \frac{TP}{TP + FP} ]

召回率:指实际为正类的样本中,模型成功预测为正类的比例。计算公式为:[ Recall = \frac{TP}{TP + FN} ]

F1-score:综合考虑精确率和召回率,是精确率和召回率的调和平均数。计算公式为:[ F1 = \frac{2 \cdot Precision \cdot Recall}{Precision + Recall} ]

ROC曲线和AUC值:ROC曲线是以假正例率为横轴,真正例率为纵轴的曲线,AUC(则是ROC曲线下的面积,用于衡量模型对正负样本的区分能力,AUC值越大,模型性能越好。

PR曲线和AUC值:PR曲线是以召回率为横轴,精确率为纵轴的曲线,AUC则是PR曲线下的面积,用于衡量模型在正例识别上的性能,AUC值越大,模型性能越好。

ROC曲线和PR曲线

我们主要是讨论一下ROC曲线和PR曲线,以及它们的差异

ROC曲线以假正例率为横轴,真正例率为纵轴。绘制出的曲线中,横轴代表着模型误分类为正例的概率,纵轴则表示模型正确分类为正例的概率。

ROC曲线的绘制:

对于分类模型的预测结果,根据预测概率(或得分)对样本进行排序。

从高到低依次设置不同的阈值,将预测结果划分为正例和负例。

针对每个阈值计算真正例率(TPR)和假正例率(FPR):

真正例率(TPR):计算预测为正例的样本中实际为正例的比例。

TPR= TP/(TP+ FN) TP是真正例(模型正确预测为正例的正样本数),FN是假负例(模型错误预测为负例的正样本数)。

假正例率(FPR):计算预测为正例的样本中实际为负例的比例。

FPR=FP/(FP+TN) FP是假正例(模型错误预测为正例的负样本数),TN是真负例(模型正确预测为负例的负样本数)

在不同阈值下绘制TPR-FPR对应的点,连接这些点得到ROC曲线。真正例率:

ROC曲线描述了在不同分类阈值下,模型在真正例率和假正例率之间的变化关系。当分类阈值较低时,模型将更多的样本预测为正例,这会增加假正例率,同时也增加了真正例率;反之,当分类阈值较高时,模型将更少的样本预测为正例,导致真正例率和假正例率都降低。ROC曲线的理想状态是向左上方凸起,表示模型在各个阈值下都能保持较高的真正例率和较低的假正例率。

ROC曲线的AUC值是对ROC曲线下的面积进行计算,AUC值越大,表示模型在各个阈值下的性能越好,即模型能够更好地区分正负样本。

通过分析ROC曲线和AUC值,可以直观地评估模型的整体性能,以及在不同分类阈值下的表现,选择合适的分类阈值,从而平衡模型的精确率和召回率,并根据具体需求进行调整。

不过,ROC曲线也有不少的问题,比如不适用于类别不平衡的问题,当正负样本不平衡时,ROC曲线的绘制可能会产生误导。在类别不平衡的情况下,即使模型预测结果非常差,真正例率和假正例率之间的比例关系可能也会保持不变,导致ROC曲线呈现良好的形态,但实际上模型的性能并不好。

ROC曲线绘制时考虑了所有可能的分类阈值,但并未考虑各个阈值对应的预测结果的实际意义。在某些情况下,虽然ROC曲线表现良好,但选择不同的分类阈值可能会导致不同的结果。

不能直接比较不同数据集上的模型性能:由于ROC曲线的形状受到数据集本身分布的影响,因此无法直接比较不同数据集上的ROC曲线。在比较不同模型性能时,通常会使用AUC值,但AUC值也受到数据集分布的影响。

不考虑成本敏感性:ROC曲线和AUC值不考虑不同类型错误的代价。在某些应用中,对于不同类型的错误可能有不同的成本,而ROC曲线无法直接反映这种成本敏感性。

PR曲线是以召回率为横轴,精确率为纵轴,绘制出的曲线。

PR曲线的绘制:

对于分类模型的预测结果,根据预测概率(或得分)对样本进行排序。

从高到低依次设置不同的阈值,将预测结果划分为正例和负例。

针对每个阈值计算召回率和精确率:

召回率:计算预测为正例的样本中实际为正例的比例。R=TP/(TP+FN)

精确率:计算所有被预测为正例的样本中实际为正例的比例。P=TP/(TP+FP)

在不同阈值下绘制召回率-精确率对应的点,连接这些点得到PR曲线。

PR曲线展示了在不同分类阈值下,模型的召回率和精确率之间的权衡关系。与ROC曲线不同,PR曲线更适用于类别不平衡的情况,因为它关注的是正例的预测性能,而不会受到负例数量的影响。

PR曲线越靠近右上角(高召回率和高精确率),表示模型在保持高召回率的同时,能够保持较高的精确率,是较好的模型性能。

PR曲线下面积(PR AUC)也是衡量模型性能的指标,PR AUC值越高,表示模型在各个阈值下的整体性能越好。

PR曲线与ROC曲线的比较:

PR曲线更适用于类别不平衡的情况,能更好地反映模型在正例预测上的性能。

ROC曲线更适用于平衡类别的情况,能够综合考虑正例和负例预测的性能。

加载并准备数据

iris = load_iris()
X = iris.data
y = iris.target
class_names = iris.target_names

# 将标签编码为整数
label_encoder = LabelEncoder()
y_encoded = label_encoder.fit_transform(y)

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y_encoded, test_size=0.33, random_state=42)

使用多类别分类器进行训练和预测,并生成混淆矩阵:

classifier = OneVsRestClassifier(LogisticRegression(max_iter=1000))

# 训练模型
classifier.fit(X_train, y_train)

# 预测
y_pred = classifier.predict(X_test)

# 生成混淆矩阵
conf_matrix = confusion_matrix(y_test, y_pred)
print("Confusion Matrix:")
print(conf_matrix)

对每个类别分别绘制 ROC 曲线:

fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(len(class_names)):
    fpr[i], tpr[i], _ = roc_curve(y_test == i, y_pred == i)
    roc_auc[i] = auc(fpr[i], tpr[i])

# 绘制 ROC 曲线
plt.figure(figsize=(10, 6))
colors = cycle(['aqua', 'darkorange', 'cornflowerblue'])
for i, color in zip(range(len(class_names)), colors):
    plt.plot(fpr[i], tpr[i], color=color, lw=2,
             label='ROC curve of {0} (area = {1:0.2f})'
             ''.format(class_names[i], roc_auc[i]))

plt.plot([0, 1], [0, 1], 'k--', lw=2)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve for each class')
plt.legend(loc="lower right")
plt.show()

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值