督學(xué)習(xí)的Web入侵檢測畢設(shè)源碼:從數(shù)據(jù)到模型全流程解析)
簡介這份資源是面向計(jì)算機(jī)相關(guān)專業(yè)學(xué)生與從業(yè)者的高分畢業(yè)設(shè)計(jì)源碼包主題為基于監(jiān)督學(xué)習(xí)的Web入侵檢測系統(tǒng)采用Python實(shí)現(xiàn)評(píng)審得分達(dá)97分可直接用于畢業(yè)設(shè)計(jì)、期末課程設(shè)計(jì)或課程大作業(yè)等場景。壓縮包共60個(gè)文件約2.25MB以18個(gè)ipynb實(shí)驗(yàn)筆記、14個(gè)txt樣本與詞表、14個(gè)html頁面樣本、8個(gè)py腳本為主另含pkl與pickle模型文件、md說明文檔等覆蓋數(shù)據(jù)采集、字符處理、去重、特征提取與模型保存等完整流程。內(nèi)容預(yù)覽顯示項(xiàng)目包含爬蟲腳本、正常與惡意請求樣本、關(guān)鍵詞表及多份Jupyter實(shí)驗(yàn)記錄便于理解監(jiān)督學(xué)習(xí)在Web入侵檢測中的特征工程與建模思路。目前已有188人學(xué)習(xí)下載適合需要完整項(xiàng)目方案、可運(yùn)行代碼與排錯(cuò)參考的讀者借鑒使用。1. 從一份 97 分畢設(shè)源碼說起監(jiān)督學(xué)習(xí)做 Web 入侵檢測到底靠不靠譜很多同學(xué)做畢設(shè)時(shí)都會(huì)卡在同一個(gè)地方題目選好了方向也定了但真正動(dòng)手時(shí)發(fā)現(xiàn)要么數(shù)據(jù)找不到要么模型跑不通要么代碼寫完自己都不知道對(duì)不對(duì)。這份基于監(jiān)督學(xué)習(xí)的 Web 入侵檢測系統(tǒng) Python 源碼就是沖著這個(gè)痛點(diǎn)來的——它是一套完整可運(yùn)行的畢設(shè)級(jí)項(xiàng)目從 HTTP 請求日志的采集、payload 參數(shù)提取、字符級(jí)特征處理到監(jiān)督學(xué)習(xí)模型訓(xùn)練和檢測整條鏈路都有對(duì)應(yīng)的腳本和 notebook。它解決的核心問題是把原始 Web 訪問日志變成模型能吃的特征向量再用監(jiān)督學(xué)習(xí)算法判斷某條請求是正常訪問還是惡意攻擊。適合計(jì)算機(jī)相關(guān)專業(yè)的本科生做畢業(yè)設(shè)計(jì)、期末大作業(yè)也適合剛?cè)胄邪踩较颉⑾雱?dòng)手跑一遍入侵檢測流程的從業(yè)者。源碼里包含了爬蟲腳本、字符處理腳本、去重腳本、參數(shù)提取 notebook、模型核心代碼以及多個(gè) pickle/joblib 序列化文件結(jié)構(gòu)上覆蓋了從數(shù)據(jù)到模型的全流程。下面我按實(shí)際拆包的順序把這份資源怎么用、參數(shù)怎么調(diào)、哪里容易翻車講清楚。2. 拆開源碼包reptile.py 到 core.py 的數(shù)據(jù)鏈路與模塊職責(zé)2.1 從 reptile.py 到 payload.txt原始請求怎么變成可訓(xùn)練數(shù)據(jù)拿到源碼包后第一件事不是急著跑模型而是先理清數(shù)據(jù)從哪來、經(jīng)過哪些腳本、最終變成什么格式。這份資源的根目錄下有幾個(gè)關(guān)鍵文件reptile.py負(fù)責(zé)爬取或采集原始 HTTP 請求數(shù)據(jù)wordProcess.py做字符級(jí)處理removeRepeat.py去重makeChar.py生成字符集core.py是模型訓(xùn)練和檢測的核心邏輯。src目錄下存放的是原始素材包括大量ff_*.html、ff_*.txt以及access_log_payload*.txt、payload.txt、normal_require.txt、safe_key.txt、normal-use1.txt等文件。這些文件的分工大致是這樣的ff_*.html和ff_*.txt是原始請求樣本access_log_payload*.txt是從訪問日志中提取出的 payload 片段payload.txt是匯總后的惡意 payload 集合normal_require.txt和normal-use1.txt是正常請求樣本safe_key.txt是安全關(guān)鍵詞白名單。整個(gè)數(shù)據(jù)鏈路可以概括為原始日志 → payload 提取 → 字符處理 → 去重 → 特征向量 → 模型訓(xùn)練。我一般會(huì)先打開README.md確認(rèn)作者標(biāo)注的運(yùn)行順序然后用count.py統(tǒng)計(jì)一下各類樣本的數(shù)量分布。這一步很關(guān)鍵因?yàn)楸O(jiān)督學(xué)習(xí)最怕的就是正負(fù)樣本嚴(yán)重不均衡。如果惡意樣本只有幾十條而正常樣本有幾千條后面訓(xùn)練出來的模型大概率會(huì)偏向多數(shù)類檢測效果會(huì)很難看。# 先看目錄結(jié)構(gòu)和文件數(shù)量心里有個(gè)底 ls -la find . -name *.py | head -20 find . -name *.txt | wc -l find . -name *.html | wc -l # 統(tǒng)計(jì)關(guān)鍵樣本文件的行數(shù)判斷正負(fù)樣本比例 wc -l src/payload.txt wc -l src/normal_require.txt wc -l src/normal-use1.txt wc -l src/safe_key.txt上面這幾條命令的作用是快速摸清數(shù)據(jù)規(guī)模。find . -name *.py列出所有 Python 腳本確認(rèn)核心文件是否齊全wc -l統(tǒng)計(jì)樣本行數(shù)如果payload.txt只有幾十行而normal_require.txt有上千行那后面就必須做樣本均衡處理否則模型會(huì)嚴(yán)重偏斜。常見做法是用欠采樣把正常樣本降到和惡意樣本同一量級(jí)或者用 SMOTE 做過采樣但這份源碼里沒有內(nèi)置均衡邏輯需要自己補(bǔ)。2.2 wordProcess.py 與 removeRepeat.py字符級(jí)特征處理的兩個(gè)關(guān)鍵腳本wordProcess.py是整個(gè)特征工程的核心入口。它的作用是把原始請求字符串拆成字符序列再做歸一化處理。Web 入侵檢測和自然語言處理有個(gè)相似點(diǎn)請求 payload 本身就是一串字符SQL 注入、XSS、命令注入這些攻擊在字符層面有比較明顯的模式比如大量單引號(hào)、尖括號(hào)、分號(hào)、union select、../等。所以用字符級(jí)特征做監(jiān)督學(xué)習(xí)是合理的不一定非要上詞向量。removeRepeat.py負(fù)責(zé)去重避免同一條 payload 在訓(xùn)練集里反復(fù)出現(xiàn)導(dǎo)致模型過擬合。這個(gè)腳本通常會(huì)讀取payload.txt和normal_require.txt對(duì)每一行做哈?;蜃址葘?duì)輸出去重后的文件。makeChar.py則是生成字符集字典把所有出現(xiàn)過的字符映射成整數(shù)索引供模型輸入使用。# wordProcess.py 的典型處理邏輯根據(jù)源碼結(jié)構(gòu)還原 import re def normalize_payload(payload: str) - str: 對(duì)原始 payload 做歸一化轉(zhuǎn)小寫、URL 解碼、去除多余空白 payload payload.strip().lower() # URL 解碼把 %27 還原成單引號(hào)等 payload re.sub(r%([0-9a-fA-F]{2}), lambda m: chr(int(m.group(1), 16)), payload) # 把連續(xù)空白壓成一個(gè)空格 payload re.sub(r\s, , payload) return payload def char_tokenize(payload: str, char2idx: dict, max_len: int 200): 把字符串轉(zhuǎn)成整數(shù)索引序列超長截?cái)嗖蛔阊a(bǔ)零 ids [char2idx.get(ch, char2idx.get(UNK, 0)) for ch in payload[:max_len]] ids [0] * (max_len - len(ids)) return ids這段代碼的邏輯說明normalize_payload先做小寫化和 URL 解碼因?yàn)楣粽呓?jīng)常用編碼繞過簡單規(guī)則char_tokenize把字符映射成整數(shù)max_len控制序列長度太短會(huì)丟信息太長會(huì)增加計(jì)算量。參數(shù)方面max_len200是一個(gè)經(jīng)驗(yàn)值Web 請求的 payload 通常不會(huì)超過這個(gè)長度如果數(shù)據(jù)集里有很多超長請求可以調(diào)到 500 甚至 1000但要注意顯存或內(nèi)存占用。UNK是未知字符的兜底索引防止測試時(shí)遇到訓(xùn)練集沒出現(xiàn)過的字符直接報(bào)錯(cuò)。提示wordProcess.py和wordProcess.pyc同時(shí)存在說明作者可能用py_compile編譯過。直接跑.py就行.pyc是緩存不用管。2.3 core.py 與 pickle/joblib 文件模型訓(xùn)練與持久化的實(shí)際流程core.py是模型訓(xùn)練和推理的主入口。從目錄里的save_with_pickle.ipynb、save_with_joblib.ipynb、test.pickle、jpblib.pkl、joblib.pkl可以看出作者用了 pickle 和 joblib 兩種方式做模型持久化。core.ipynb和core.py內(nèi)容應(yīng)該基本一致notebook 方便調(diào)試.py方便直接運(yùn)行。監(jiān)督學(xué)習(xí)部分常見做法是用 scikit-learn 里的分類器比如樸素貝葉斯、邏輯回歸、隨機(jī)森林或 SVM??紤]到字符級(jí)特征維度較高樸素貝葉斯和邏輯回歸比較輕量隨機(jī)森林效果通常更穩(wěn)但訓(xùn)練慢一些。源碼里沒有明確寫用哪個(gè)算法但從core.py的命名和getNormalPara.py、getPayloadPrarmaters.ipynb這些文件來看作者應(yīng)該是先提取正常請求和惡意請求的參數(shù)特征再喂給分類器。# core.py 的典型訓(xùn)練流程根據(jù)源碼結(jié)構(gòu)還原 import joblib import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report # 假設(shè) X 是字符索引矩陣y 是標(biāo)簽0 正常1 惡意 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) clf RandomForestClassifier( n_estimators100, # 樹的數(shù)量越多越穩(wěn)但越慢 max_depth20, # 控制過擬合太深會(huì)記住訓(xùn)練集 min_samples_leaf2, # 葉子節(jié)點(diǎn)最少樣本數(shù)防止噪聲影響 random_state42, n_jobs-1 # 用滿所有 CPU 核心 ) clf.fit(X_train, y_train) # 輸出評(píng)估報(bào)告重點(diǎn)看惡意類的 recall y_pred clf.predict(X_test) print(classification_report(y_test, y_pred, target_names[normal, malicious])) # 持久化模型后面檢測時(shí)直接加載 joblib.dump(clf, web_ids_rf.joblib)參數(shù)說明n_estimators100是隨機(jī)森林的默認(rèn)起點(diǎn)如果訓(xùn)練集很大可以加到 200 或 300max_depth20是為了防止樹長得太深導(dǎo)致過擬合實(shí)際調(diào)參時(shí)可以用交叉驗(yàn)證選stratifyy保證訓(xùn)練集和測試集里正負(fù)樣本比例一致這個(gè)在樣本不均衡時(shí)特別重要。評(píng)估時(shí)不要只看 accuracy因?yàn)槿绻麗阂鈽颖局徽?5%全預(yù)測成正常也有 95% 的準(zhǔn)確率但實(shí)際毫無用處。重點(diǎn)看 malicious 類的 recall 和 F1-score。save_with_pickle.ipynb和save_with_joblib.ipynb的區(qū)別在于序列化方式。pickle 是 Python 標(biāo)準(zhǔn)庫通用但跨版本兼容性差joblib 對(duì) numpy 數(shù)組優(yōu)化更好文件更小、加載更快。我一般優(yōu)先用 joblib尤其是模型里包含大量數(shù)組參數(shù)時(shí)。3. 把源碼跑起來環(huán)境配置、notebook 執(zhí)行順序與參數(shù)調(diào)整3.1 Python 環(huán)境與依賴安裝numpy、scikit-learn、joblib 一個(gè)都不能少這份源碼是純 Python 項(xiàng)目沒有復(fù)雜的深度學(xué)習(xí)框架依賴所以環(huán)境配置不算麻煩。但有幾個(gè)庫是必須的numpy做數(shù)值計(jì)算scikit-learn做模型訓(xùn)練和評(píng)估joblib做模型持久化pandas可能在 notebook 里用于數(shù)據(jù)查看。如果reptile.py里用了 requests 或 scrapy還需要裝對(duì)應(yīng)的爬蟲庫。# 建議用虛擬環(huán)境避免污染系統(tǒng) Python python -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows # 安裝核心依賴 pip install numpy scikit-learn joblib pandas pip install requests beautifulsoup4 # reptile.py 可能需要 # 確認(rèn)版本避免 scikit-learn 版本差異導(dǎo)致模型加載失敗 python -c import sklearn; print(sklearn.__version__) python -c import numpy; print(numpy.__version__)這里有個(gè)血淚經(jīng)驗(yàn)scikit-learn 不同版本之間pickle/joblib 文件的兼容性可能有問題。如果加載test.pickle時(shí)報(bào)AttributeError或ModuleNotFoundError大概率是版本不匹配。解決辦法是看README.md里有沒有標(biāo)注版本或者用pip install scikit-learn1.x.x裝一個(gè)接近的版本。如果實(shí)在加載不了就重新跑一遍core.py訓(xùn)練不要死磕舊模型文件。注意jpblib.pkl這個(gè)文件名看起來像是joblib.pkl的拼寫變體加載時(shí)先確認(rèn)實(shí)際文件名不要直接照抄代碼里的路徑。3.2 notebook 執(zhí)行順序從 firstTry 到 core 的推薦路徑源碼包里有一堆.ipynb文件firstTry.ipynb、justTest.ipynb、some test.ipynb、getPayloadPrarmaters.ipynb、getNormalParamaters.ipynb、core.ipynb、save_with_pickle.ipynb、save_with_joblib.ipynb。這些 notebook 不是隨便放的它們反映了作者的開發(fā)順序。我建議按以下順序執(zhí)行第一步打開firstTry.ipynb看看作者最初怎么讀取數(shù)據(jù)、怎么定義標(biāo)簽。這個(gè)文件通常比較粗糙但能幫你快速理解數(shù)據(jù)格式。第二步跑getPayloadPrarmaters.ipynb和getNormalParamaters.ipynb這兩個(gè)負(fù)責(zé)從惡意和正常樣本中提取參數(shù)特征。第三步跑wordProcess.py和removeRepeat.py生成去重后的字符序列。第四步跑core.ipynb或core.py訓(xùn)練模型并輸出評(píng)估結(jié)果。最后用save_with_joblib.ipynb保存模型方便后續(xù)檢測調(diào)用。# 在 notebook 里檢查數(shù)據(jù)加載是否正常 import pandas as pd # 讀取 payload 和正常請求注意編碼問題 with open(src/payload.txt, r, encodingutf-8, errorsignore) as f: malicious [line.strip() for line in f if line.strip()] with open(src/normal_require.txt, r, encodingutf-8, errorsignore) as f: normal [line.strip() for line in f if line.strip()] print(f惡意樣本數(shù): {len(malicious)}) print(f正常樣本數(shù): {len(normal)}) print(f正負(fù)比: 1:{len(normal)/max(len(malicious),1):.1f}) # 看幾條樣本確認(rèn)數(shù)據(jù)質(zhì)量 for s in malicious[:3]: print(MAL:, s[:120]) for s in normal[:3]: print(NOR:, s[:120])這段代碼的關(guān)鍵是errorsignore因?yàn)樵既罩纠锟赡苡蟹?UTF-8 字符不加這個(gè)參數(shù)會(huì)直接報(bào)UnicodeDecodeError。打印正負(fù)比是為了判斷要不要做樣本均衡。如果比例超過 1:10建議先欠采樣正常樣本再訓(xùn)練。查看前幾條樣本可以直觀感受數(shù)據(jù)質(zhì)量如果惡意樣本里混了大量正常請求說明數(shù)據(jù)標(biāo)注有問題需要手動(dòng)清洗。3.3 關(guān)鍵參數(shù)怎么調(diào)max_len、n_estimators 與 test_size 的取舍這份源碼里沒有集中的配置文件參數(shù)散落在各個(gè)腳本和 notebook 里。根據(jù)我的經(jīng)驗(yàn)有三個(gè)參數(shù)對(duì)結(jié)果影響最大字符序列長度max_len、隨機(jī)森林的n_estimators、以及訓(xùn)練集劃分的test_size。max_len決定每條請求保留多少字符。設(shè)得太小比如 50長 payload 的關(guān)鍵攻擊特征會(huì)被截掉設(shè)得太大比如 1000特征維度爆炸訓(xùn)練慢且容易過擬合。Web 請求的 payload 大部分在 100 到 300 字符之間所以max_len200到300是比較穩(wěn)的選擇??梢栽?notebook 里畫一下 payload 長度分布選覆蓋 90% 樣本的長度作為max_len。n_estimators是隨機(jī)森林的樹數(shù)量。樹越多模型越穩(wěn)定但訓(xùn)練和推理時(shí)間線性增長。100 棵樹在幾千條樣本上通常夠用如果樣本上萬可以加到 200。但不要盲目加到 1000收益遞減很明顯而且模型文件會(huì)變大。test_size一般設(shè) 0.2 到 0.3。如果樣本量很小比如總共只有幾百條可以設(shè) 0.3 讓測試集更有代表性如果樣本上萬0.2 就夠了。關(guān)鍵是加stratifyy保證正負(fù)樣本在訓(xùn)練集和測試集里比例一致。# 畫 payload 長度分布輔助選擇 max_len import matplotlib.pyplot as plt lengths [len(s) for s in malicious normal] plt.hist(lengths, bins50) plt.xlabel(payload length) plt.ylabel(count) plt.title(Payload Length Distribution) plt.axvline(x200, colorr, linestyle--, labelmax_len200) plt.legend() plt.show() # 輸出 90 分位數(shù)作為 max_len 參考 import numpy as np print(f90% 分位數(shù): {np.percentile(lengths, 90):.0f}) print(f95% 分位數(shù): {np.percentile(lengths, 95):.0f})這段代碼幫你用數(shù)據(jù)說話而不是拍腦袋定max_len。如果 90 分位數(shù)是 180那max_len200就能覆蓋絕大多數(shù)樣本如果 90 分位數(shù)是 500那就要考慮調(diào)大或者對(duì)長 payload 做特殊處理。plt.axvline畫出參考線直觀看到截?cái)辔恢谩?. 避坑與排查這份源碼跑不起來時(shí)先查這五件事4.1 現(xiàn)象加載 pickle/joblib 文件報(bào)版本不兼容 → 原因scikit-learn 版本差異 → 解決重訓(xùn)或降版本這是最常見的問題。test.pickle、jpblib.pkl、joblib.pkl這些文件是在作者的環(huán)境里序列化的如果你本地的 scikit-learn 版本和作者不一致加載時(shí)就會(huì)報(bào)AttributeError: module sklearn.ensemble has no attribute ...或者ValueError: node array from the pickle has an incompatible dtype。解決辦法有兩個(gè)一是看README.md里有沒有寫版本號(hào)裝一個(gè)接近的版本二是直接刪掉舊模型文件重新跑core.py訓(xùn)練一遍。我一般選第二種因?yàn)橹赜?xùn)雖然花幾分鐘但能保證環(huán)境和代碼完全匹配后面調(diào)試也省心。4.2 現(xiàn)象notebook 里中文注釋亂碼或讀取文件報(bào) UnicodeDecodeError → 原因編碼不一致 → 解決統(tǒng)一用 utf-8 errorsignore原始日志和 HTML 文件可能來自不同系統(tǒng)編碼格式不統(tǒng)一。Windows 下可能是 GBKLinux 下可能是 UTF-8混在一起就會(huì)報(bào)UnicodeDecodeError。解決辦法是在所有open()調(diào)用里加encodingutf-8, errorsignore。如果確認(rèn)是 GBK 文件就單獨(dú)用encodinggbk讀。notebook 里如果中文注釋顯示亂碼檢查文件本身的編碼用 VS Code 或 Notepad 轉(zhuǎn)成 UTF-8。4.3 現(xiàn)象模型評(píng)估 accuracy 很高但實(shí)際檢測效果差 → 原因樣本不均衡導(dǎo)致模型偏向多數(shù)類 → 解決看 recall 和 F1做欠采樣或過采樣如果正常樣本有 5000 條惡意樣本只有 200 條模型全預(yù)測成正常就能拿到 96% 的 accuracy但惡意請求一條都抓不到。這是監(jiān)督學(xué)習(xí)在入侵檢測里最典型的翻車場景。解決辦法是不要只看 accuracy重點(diǎn)看classification_report里 malicious 類的 recall 和 F1-score。如果 recall 低于 0.8就要做樣本均衡欠采樣正常樣本到和惡意樣本同一量級(jí)或者用 SMOTE 生成合成惡意樣本。這份源碼里沒有內(nèi)置均衡邏輯需要自己在core.py里加。4.4 現(xiàn)象reptile.py 跑不動(dòng)或爬取超時(shí) → 原因目標(biāo)站點(diǎn)反爬或網(wǎng)絡(luò)環(huán)境變化 → 解決跳過爬蟲直接用 src 目錄里的現(xiàn)成數(shù)據(jù)reptile.py是爬蟲腳本依賴外部站點(diǎn)的可用性。如果目標(biāo)站點(diǎn)改了結(jié)構(gòu)、加了反爬或者你的網(wǎng)絡(luò)環(huán)境訪問不了這個(gè)腳本就跑不通。但好消息是src目錄里已經(jīng)包含了大量現(xiàn)成的ff_*.html、ff_*.txt和access_log_payload*.txt完全可以直接用這些數(shù)據(jù)做訓(xùn)練跳過爬蟲步驟。我一般會(huì)先檢查src目錄的數(shù)據(jù)量如果夠用就不跑reptile.py省得折騰。4.5 現(xiàn)象joblib.dump 保存的模型文件特別大 → 原因隨機(jī)森林樹太多或 max_depth 太大 → 解決限制樹數(shù)量和深度或改用邏輯回歸隨機(jī)森林的模型大小和樹的數(shù)量、深度成正比。如果n_estimators500且max_depthNone模型文件可能幾百 MB加載慢、傳輸也不方便。解決辦法是把n_estimators降到 100 到 200max_depth限制在 20 到 30。如果對(duì)模型大小有嚴(yán)格要求可以改用邏輯回歸或樸素貝葉斯模型文件通常只有幾 KB 到幾十 KB雖然效果可能略差但部署方便很多。5. 從能跑到好用用交叉驗(yàn)證和混淆矩陣把檢測效果壓榨出來5.1 用交叉驗(yàn)證替代單次 train_test_split結(jié)果更可信單次train_test_split的結(jié)果受隨機(jī)種子影響很大換一個(gè)random_state可能 F1 差好幾個(gè)百分點(diǎn)。更穩(wěn)的做法是做 5 折或 10 折交叉驗(yàn)證看平均 F1 和標(biāo)準(zhǔn)差。如果標(biāo)準(zhǔn)差很大說明模型不穩(wěn)定需要調(diào)參或增加數(shù)據(jù)。from sklearn.model_selection import cross_val_score from sklearn.ensemble import RandomForestClassifier clf RandomForestClassifier(n_estimators100, max_depth20, random_state42, n_jobs-1) scores cross_val_score(clf, X, y, cv5, scoringf1) print(f5 折 F1: {scores}) print(f平均 F1: {scores.mean():.4f} (/- {scores.std():.4f}))cv5表示 5 折交叉驗(yàn)證scoringf1直接優(yōu)化 F1 而不是 accuracy。如果平均 F1 在 0.9 以上且標(biāo)準(zhǔn)差小于 0.03說明模型比較穩(wěn)如果標(biāo)準(zhǔn)差超過 0.05就要檢查數(shù)據(jù)里是不是有噪聲樣本或者分布不均。5.2 混淆矩陣告訴你模型到底錯(cuò)在哪classification_report給的是匯總指標(biāo)混淆矩陣能讓你看到具體有多少正常請求被誤判成惡意、多少惡意請求被漏掉。在入侵檢測場景里漏報(bào)惡意判正常通常比誤報(bào)正常判惡意更嚴(yán)重所以要根據(jù)業(yè)務(wù)需求調(diào)整分類閾值。from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay import matplotlib.pyplot as plt cm confusion_matrix(y_test, y_pred) disp ConfusionMatrixDisplay(confusion_matrixcm, display_labels[normal, malicious]) disp.plot(cmapBlues) plt.title(Confusion Matrix) plt.show() # 手動(dòng)計(jì)算漏報(bào)率和誤報(bào)率 tn, fp, fn, tp cm.ravel() print(f漏報(bào)率惡意判正常: {fn/(fntp):.4f}) print(f誤報(bào)率正常判惡意: {fp/(fptn):.4f})cm.ravel()按[tn, fp, fn, tp]順序展開。漏報(bào)率是fn/(fntp)誤報(bào)率是fp/(fptn)。如果漏報(bào)率太高可以降低判定為惡意的閾值犧牲一點(diǎn)誤報(bào)率來換取更低的漏報(bào)。如果誤報(bào)率太高就提高閾值。這個(gè)權(quán)衡沒有標(biāo)準(zhǔn)答案取決于你的系統(tǒng)能承受多少誤報(bào)。5.3 一個(gè)實(shí)用技巧把模型預(yù)測概率存下來方便后續(xù)調(diào)閾值默認(rèn)的clf.predict()直接輸出 0 或 1但很多時(shí)候我們需要根據(jù)業(yè)務(wù)調(diào)整閾值。用clf.predict_proba()拿到惡意類的概率存成 CSV后面想改閾值不用重新訓(xùn)練。import pandas as pd proba clf.predict_proba(X_test)[:, 1] # 惡意類的概率 result pd.DataFrame({ true_label: y_test, malicious_proba: proba, pred_label: (proba 0.5).astype(int) }) result.to_csv(detection_scores.csv, indexFalse) # 試幾個(gè)閾值看漏報(bào)和誤報(bào)怎么變 for thresh in [0.3, 0.4, 0.5, 0.6, 0.7]: pred (proba thresh).astype(int) tn, fp, fn, tp confusion_matrix(y_test, pred).ravel() print(f閾值 {thresh}: 漏報(bào)率{fn/(fntp):.4f}, 誤報(bào)率{fp/(fptn):.4f})這段代碼把預(yù)測概率和真實(shí)標(biāo)簽一起存成 CSV后面不管是用 Excel 分析還是寫腳本調(diào)閾值都很方便。for thresh in [...]循環(huán)試了五個(gè)閾值輸出對(duì)應(yīng)的漏報(bào)率和誤報(bào)率幫你找到業(yè)務(wù)上最能接受的平衡點(diǎn)。我一般會(huì)把這個(gè) CSV 留著答辯時(shí)直接展示不同閾值下的效果對(duì)比比只報(bào)一個(gè) accuracy 有說服力得多。從那以后我每次跑完入侵檢測模型都會(huì)強(qiáng)制走一遍混淆矩陣和閾值掃描不看到漏報(bào)率和誤報(bào)率的具體數(shù)字心里就不踏實(shí)。希望這份源碼和上面的步驟能幫你少走點(diǎn)彎路順利把畢設(shè)跑通。本文還有配套的精品資源點(diǎn)擊獲取