幾率回歸實戰(zhàn):西瓜鳶尾花分類期末大作業(yè)避坑指南)
簡介這份資源是面向計算機相關專業(yè)在校學生、教師及企業(yè)員工的期末大作業(yè)與課程設計資料包圍繞對數(shù)幾率回歸模型實現(xiàn)西瓜與鳶尾花數(shù)據(jù)集的識別分類任務展開適合作為機器學習入門進階練習也可直接用于畢設、課程設計或初期項目立項演示。壓縮包共30個文件約544KB包含6個Python源碼文件、4個Jupyter Notebook、2份Word作業(yè)報告、2份Markdown項目說明以及xml、iml等IDE配置文件和pyc緩存文件源碼附帶詳細注釋便于理解算法實現(xiàn)與調試過程。目前已有296人學習下載。讀者可獲得完整的對數(shù)幾率回歸建模流程、數(shù)據(jù)預處理與分類評估代碼、可直接提交的作業(yè)報告模板以及清晰的目錄結構既能對照復現(xiàn)實驗也方便在此基礎上進行二次開發(fā)與功能拓展。1. 對數(shù)幾率回歸做西瓜鳶尾花分類期末大作業(yè)里最容易被低估的一行代碼很多人拿到「基于對數(shù)幾率回歸模型實現(xiàn)西瓜鳶尾花識別分類」這個題目第一反應是邏輯回歸太簡單了sklearn 三行代碼就能跑完期末大作業(yè)寫這個是不是顯得沒水平我當年也這么想直到幫學弟調他的作業(yè)報告才發(fā)現(xiàn)真正翻車的地方根本不在模型本身——他把西瓜數(shù)據(jù)集和鳶尾花數(shù)據(jù)集混在一起讀特征列對不上準確率一直在 0.33 附近晃他還以為是邏輯回歸不適合多分類。對數(shù)幾率回歸Logistic Regression本質是線性分類器套一個 Sigmoid 映射二分類是它的主場多分類要靠 One-vs-Rest 或 Softmax 擴展。西瓜數(shù)據(jù)集是二分類好瓜/壞瓜鳶尾花是三分類三種花兩個任務放在一份作業(yè)里恰好覆蓋了從二分類到多分類的完整鏈路。這篇筆記面向正在做這個期末大作業(yè)、或者想拿它當 Python 入門練手項目的人把數(shù)據(jù)讀取、模型訓練、參數(shù)調節(jié)、報告撰寫和注釋規(guī)范整條路徑講清楚讓你交上去的東西經(jīng)得起追問。2. 先搞清楚兩個數(shù)據(jù)集的結構差異西瓜二分類和鳶尾花三分類不是一回事2.1 西瓜數(shù)據(jù)集 3.0 的字段含義與標簽編碼西瓜數(shù)據(jù)集 3.0 是周志華《機器學習》里的經(jīng)典數(shù)據(jù)共 17 個樣本每個樣本有 8 個特征色澤、根蒂、敲聲、紋理、臍部、觸感、密度、含糖率。前 6 個是離散字符串后 2 個是連續(xù)數(shù)值。標簽是「好瓜」和「壞瓜」。很多人直接把這個數(shù)據(jù)集丟給邏輯回歸會報could not convert string to float的錯誤因為 sklearn 不接受字符串特征。常見做法是先用 pandas 讀入然后對離散列做映射編碼。注意不要用 OneHotEncoder 無腦展開17 個樣本展開成幾十維反而容易過擬合。我一般用簡單的字典映射把「青綠/烏黑/淺白」映射成 0/1/2這樣既保留了序關系又不會維度爆炸。import pandas as pd import numpy as np # 讀取西瓜數(shù)據(jù)集假設文件為 watermelon3.0.csv df pd.read_csv(watermelon3.0.csv, encodingutf-8) # 離散特征映射字典按語義順序編碼 color_map {青綠: 0, 烏黑: 1, 淺白: 2} root_map {蜷縮: 0, 稍蜷: 1, 硬挺: 2} sound_map {濁響: 0, 沉悶: 1, 清脆: 2} texture_map {清晰: 0, 稍糊: 1, 模糊: 2} umbilicus_map {凹陷: 0, 稍凹: 1, 平坦: 2} touch_map {硬滑: 0, 軟粘: 1} df[色澤] df[色澤].map(color_map) df[根蒂] df[根蒂].map(root_map) df[敲聲] df[敲聲].map(sound_map) df[紋理] df[紋理].map(texture_map) df[臍部] df[臍部].map(umbilicus_map) df[觸感] df[觸感].map(touch_map) # 標簽編碼好瓜1壞瓜0 df[好瓜] df[好瓜].map({是: 1, 否: 0}) # 檢查缺失值 print(df.isnull().sum())這段代碼的關鍵在于映射字典的順序要和數(shù)據(jù)集里的類別一一對應如果映射錯了模型學到的就是錯的序關系。參數(shù)方面encodingutf-8是為了防止中文列名讀取亂碼如果你在 Windows 上遇到UnicodeDecodeError可以換成gbk試試。isnull().sum()用來確認映射過程中有沒有產(chǎn)生 NaN因為如果某個類別沒在字典里map 會返回 NaN后續(xù)訓練直接報錯。2.2 鳶尾花數(shù)據(jù)集的加載與特征標準化鳶尾花數(shù)據(jù)集在 sklearn 里自帶150 個樣本4 個連續(xù)特征花萼長度、花萼寬度、花瓣長度、花瓣寬度3 個類別各 50 個樣本。這個數(shù)據(jù)集干凈得多但有一個坑三個類別的特征分布范圍不同花瓣長度和花萼寬度的量綱差異會導致邏輯回歸的梯度下降收斂慢。我一般會做標準化把均值歸到 0、方差歸到 1。from sklearn.datasets import load_iris from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split # 加載鳶尾花數(shù)據(jù)集 iris load_iris() X, y iris.data, iris.target # 標準化邏輯回歸對特征尺度敏感標準化能加速收斂 scaler StandardScaler() X_scaled scaler.fit_transform(X) # 劃分訓練集和測試集stratify 保證類別比例一致 X_train, X_test, y_train, y_test train_test_split( X_scaled, y, test_size0.3, random_state42, stratifyy ) print(f訓練集樣本數(shù): {X_train.shape[0]}, 測試集樣本數(shù): {X_test.shape[0]}) print(f類別分布: {np.bincount(y_train)})StandardScaler的fit_transform只能在訓練集上做測試集要用訓練集的均值和方差來transform否則就是數(shù)據(jù)泄露。stratifyy保證劃分后每個類別的比例和原始一致150 個樣本按 7:3 劃分后訓練集每類 35 個測試集每類 15 個。random_state42固定隨機種子保證你每次跑出來的結果一樣報告里寫準確率才有意義。提示西瓜數(shù)據(jù)集樣本太少標準化后反而可能放大噪聲建議只對連續(xù)特征「密度」和「含糖率」做標準化離散特征保持原樣。3. 對數(shù)幾率回歸的兩種實現(xiàn)路徑手寫梯度下降和 sklearn 調包3.1 手寫二分類邏輯回歸的梯度下降期末大作業(yè)如果只調包報告里沒什么可寫的。我建議至少手寫一遍二分類的邏輯回歸把 Sigmoid、交叉熵損失、梯度更新這三個核心公式落到代碼里。這樣報告里可以畫損失曲線老師一看就知道你真懂了。def sigmoid(z): # 防止 exp 溢出對 z 做截斷 z np.clip(z, -500, 500) return 1.0 / (1.0 np.exp(-z)) def train_logistic_regression(X, y, lr0.1, epochs1000): 手寫二分類邏輯回歸訓練 X: 特征矩陣 (n_samples, n_features) y: 標簽向量 (n_samples,) lr: 學習率 epochs: 迭代次數(shù) 返回: 權重 w, 偏置 b, 損失歷史 n_samples, n_features X.shape w np.zeros(n_features) b 0.0 loss_history [] for i in range(epochs): # 前向傳播 z np.dot(X, w) b y_pred sigmoid(z) # 交叉熵損失加 1e-9 防止 log(0) loss -np.mean(y * np.log(y_pred 1e-9) (1 - y) * np.log(1 - y_pred 1e-9)) loss_history.append(loss) # 梯度計算 dw np.dot(X.T, (y_pred - y)) / n_samples db np.mean(y_pred - y) # 參數(shù)更新 w - lr * dw b - lr * db return w, b, loss_history學習率lr是最關鍵的參數(shù)設 0.1 在標準化后的數(shù)據(jù)上一般能收斂如果損失曲線震蕩就降到 0.01如果下降太慢就升到 0.5 試試。epochs設 1000 通常夠用你可以畫loss_history看它什么時候趨于平穩(wěn)。np.clip(z, -500, 500)是防止np.exp溢出這是血淚經(jīng)驗不加上去在某些樣本上會直接報RuntimeWarning: overflow。3.2 sklearn 的 LogisticRegression 多分類參數(shù)鳶尾花是三分類sklearn 的LogisticRegression默認用multi_classauto在數(shù)據(jù)量小的時候會選 OvR數(shù)據(jù)量大且類別多的時候選 Softmax。你可以顯式指定multi_classmultinomial來強制用 Softmax配合solverlbfgs或solversaga。from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score, classification_report # 多分類邏輯回歸使用 Softmax 回歸 clf LogisticRegression( multi_classmultinomial, solverlbfgs, C1.0, max_iter1000, random_state42 ) clf.fit(X_train, y_train) y_pred clf.predict(X_test) print(f準確率: {accuracy_score(y_test, y_pred):.4f}) print(classification_report(y_test, y_pred, target_namesiris.target_names))C是正則化強度的倒數(shù)默認 1.0越小正則化越強。如果報告里發(fā)現(xiàn)訓練集準確率遠高于測試集說明過擬合把C降到 0.1 或 0.01。max_iter默認 100在鳶尾花上可能不收斂設 1000 比較穩(wěn)。classification_report會輸出每個類別的精確率、召回率和 F1報告里直接貼這個表比只寫一個準確率有說服力得多。3.3 西瓜數(shù)據(jù)集上的二分類驗證西瓜數(shù)據(jù)集只有 17 個樣本用留一法交叉驗證比 train_test_split 更合理因為隨機劃分可能導致某一類在測試集里一個都沒有。from sklearn.model_selection import LeaveOneOut from sklearn.linear_model import LogisticRegression # 準備西瓜數(shù)據(jù) X_wm df[[色澤, 根蒂, 敲聲, 紋理, 臍部, 觸感, 密度, 含糖率]].values y_wm df[好瓜].values loo LeaveOneOut() acc_list [] for train_idx, test_idx in loo.split(X_wm): X_tr, X_te X_wm[train_idx], X_wm[test_idx] y_tr, y_te y_wm[train_idx], y_wm[test_idx] model LogisticRegression(max_iter500) model.fit(X_tr, y_tr) acc_list.append(model.score(X_te, y_te)) print(f留一法平均準確率: {np.mean(acc_list):.4f})留一法每次只留一個樣本做測試17 個樣本跑 17 次最終準確率是 17 次的平均。這個數(shù)字在報告里比單次劃分更可信。注意西瓜數(shù)據(jù)集樣本少準確率波動大0.7 到 0.9 之間都算正常不要為了追求高準確率去調參數(shù)調到過擬合。4. 避坑與排查邏輯回歸作業(yè)里最容易翻車的 5 個地方4.1 準確率一直上不去檢查標簽編碼是否反了現(xiàn)象模型訓練完準確率在 0.3 到 0.5 之間比隨機猜還差。原因標簽映射時把「好瓜」映射成 0、「壞瓜」映射成 1但預測時又按 1 是好瓜來解讀導致精確率和召回率對調。解決統(tǒng)一標簽編碼規(guī)范在代碼開頭用注釋寫清楚0壞瓜, 1好瓜所有評估指標都按這個約定解讀。4.2 報錯 could not convert string to float現(xiàn)象fit的時候直接拋ValueError: could not convert string to float: 青綠。原因西瓜數(shù)據(jù)集的離散列沒有做編碼直接傳給了 sklearn。解決在fit之前用df.select_dtypes(includeobject).columns檢查還有哪些字符串列逐一映射。如果懶得手動映射可以用pd.get_dummies做 OneHot 編碼但 17 個樣本展開后維度太高不推薦。4.3 損失曲線不下降或者震蕩現(xiàn)象手寫梯度下降時loss_history一直在 0.69 附近不動或者上下大幅震蕩。原因學習率設得太大導致震蕩或者特征沒有標準化導致梯度尺度差異大。解決先把學習率降到 0.01 試如果下降太慢再逐步升到 0.1、0.3。同時確認連續(xù)特征做了標準化西瓜數(shù)據(jù)集的「密度」在 0.3 到 0.8 之間「含糖率」在 0.05 到 0.45 之間量綱接近但鳶尾花的花瓣長度在 1 到 7 之間不標準化會影響收斂。4.4 多分類時 predict_proba 返回的列數(shù)不對現(xiàn)象鳶尾花三分類predict_proba返回的卻是兩列。原因multi_class參數(shù)設成了ovr且某個類別被當成正類、其余合并成負類。解決顯式設multi_classmultinomial并且確認solver支持多分類lbfgs和saga都支持liblinear不支持多分類。4.5 作業(yè)報告里注釋太少被扣分現(xiàn)象代碼能跑但報告分數(shù)不高老師評語寫「注釋不足可讀性差」。原因只寫了# 導入庫這種無意義注釋沒有解釋參數(shù)含義和設計決策。解決每個函數(shù)寫 docstring說明輸入輸出和關鍵參數(shù)每個映射字典旁邊寫清楚類別順序每個超參數(shù)寫一行注釋說明為什么選這個值。參考 Python 文檔注釋規(guī)范用寫函數(shù)說明用#寫行內說明。注意不要用# -*- coding: utf-8 -*-這種老式編碼聲明Python 3 默認就是 UTF-8寫了反而顯得不專業(yè)。5. 報告撰寫與注釋規(guī)范讓大作業(yè)從及格線拉到優(yōu)秀5.1 作業(yè)報告的結構模板期末大作業(yè)的報告一般包括問題描述、數(shù)據(jù)集說明、方法原理、實驗設置、結果分析、結論。我建議在「方法原理」部分把對數(shù)幾率回歸的公式推導寫清楚從線性回歸到 Sigmoid 映射從極大似然估計到交叉熵損失從梯度推導到參數(shù)更新。這部分不用太長一頁紙足夠但公式要自己敲不要截圖?!笇嶒炘O置」部分要寫清楚訓練集測試集劃分比例、隨機種子、標準化方法、超參數(shù)取值。這些細節(jié)決定了你的實驗能不能被復現(xiàn)。「結果分析」部分除了準確率還要放混淆矩陣和分類報告鳶尾花三分類的混淆矩陣能看出哪個類別容易混。from sklearn.metrics import confusion_matrix import seaborn as sns import matplotlib.pyplot as plt # 繪制混淆矩陣 cm confusion_matrix(y_test, y_pred) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsiris.target_names, yticklabelsiris.target_names) plt.xlabel(預測類別) plt.ylabel(真實類別) plt.title(鳶尾花分類混淆矩陣) plt.tight_layout() plt.savefig(confusion_matrix.png, dpi150)fmtd表示顯示整數(shù)cmapBlues是配色方案dpi150保證圖片清晰度夠打印。保存圖片而不是只show是因為報告里要插入圖片直接截圖會有白邊。5.2 代碼注釋的三個層次第一層是模塊級注釋在文件開頭寫清楚這個腳本做什么、依賴哪些庫、數(shù)據(jù)文件放在哪里。第二層是函數(shù)級注釋用 docstring 寫清楚輸入?yún)?shù)的類型和含義、返回值的結構。第三層是行內注釋只在對非直觀操作做解釋時寫比如「對 z 做截斷防止 exp 溢出」這種。 西瓜鳶尾花分類作業(yè) 依賴: pandas, numpy, sklearn, matplotlib, seaborn 數(shù)據(jù): watermelon3.0.csv 放在同目錄下 運行: python classification.py 這種模塊級注釋看起來簡單但很多同學交上來的代碼連文件名和運行方式都沒寫老師想跑都跑不起來。加上這三行印象分直接拉滿。5.3 參數(shù)調優(yōu)的記錄方式報告里不要只寫「最終準確率 0.95」要寫「在 C1.0 時準確率 0.93C0.1 時 0.95C0.01 時 0.91最終選 C0.1」。用一個表格記錄不同參數(shù)下的結果比一段文字描述清楚得多。C 值訓練集準確率測試集準確率備注0.010.900.91正則化過強欠擬合0.10.960.95最佳1.00.990.93輕微過擬合10.01.000.91過擬合明顯這張表放在報告里老師一眼就能看出你做了調參實驗而不是隨便跑了一次就交。注意訓練集準確率和測試集準確率的差距差距越大過擬合越嚴重。5.4 用交叉驗證替代單次劃分如果想讓結果更穩(wěn)可以用cross_val_score做 5 折交叉驗證報告里寫「5 折交叉驗證平均準確率 0.95±0.03」比單次劃分的 0.95 更有說服力。from sklearn.model_selection import cross_val_score clf_cv LogisticRegression(multi_classmultinomial, solverlbfgs, C0.1, max_iter1000, random_state42) scores cross_val_score(clf_cv, X_scaled, y, cv5, scoringaccuracy) print(f5折交叉驗證: {scores.mean():.4f} ± {scores.std():.4f})cv5表示 5 折scoringaccuracy表示用準確率評估。scores.std()是標準差越小說明模型越穩(wěn)定。如果標準差超過 0.05說明數(shù)據(jù)劃分對結果影響大報告里要說明這一點。5.5 最后檢查一遍這些細節(jié)交作業(yè)之前我一般會過一遍這個清單代碼能不能在干凈環(huán)境里跑通把__pycache__刪掉重跑、數(shù)據(jù)文件路徑是不是相對路徑、有沒有硬編碼的絕對路徑、圖片有沒有保存到正確目錄、報告里的數(shù)字和代碼輸出是否一致。這些細節(jié)看起來瑣碎但每年都有同學因為路徑寫死在自己電腦上老師一跑就報FileNotFoundError直接扣分。我自己的習慣是在項目根目錄放一個requirements.txt寫清楚依賴庫和版本雖然期末大作業(yè)不一定要求但加上去顯得規(guī)范。另外代碼里不要出現(xiàn)print調試語句殘留交之前全局搜一下print該刪的刪該改成日志的改成日志。希望幫到你。本文還有配套的精品資源點擊獲取