?shù)線預(yù)測(cè)與院校推薦系統(tǒng):畢設(shè)技術(shù)方案全解析)
每年畢設(shè)季我都要幫忙看幾十個(gè)題目前往不同方向的技術(shù)方案見(jiàn)得最多的就是兩類(lèi)一類(lèi)是純管理系統(tǒng)功能單一、算法含量低答辯時(shí)很容易被評(píng)委一句話問(wèn)住另一類(lèi)是純粹的網(wǎng)頁(yè)展示看起來(lái)花哨但沒(méi)有實(shí)際業(yè)務(wù)閉環(huán)。而今天的這個(gè)題目——Django Vue.js 考研分?jǐn)?shù)線預(yù)測(cè)系統(tǒng)、考研院校推薦系統(tǒng)屬于那種“看著不復(fù)雜、實(shí)際能展開(kāi)講很多”的典型。它能做的事情很直接考生輸入自己的目標(biāo)專(zhuān)業(yè)、地區(qū)、預(yù)估分?jǐn)?shù)等條件系統(tǒng)一方面基于歷年分?jǐn)?shù)線數(shù)據(jù)預(yù)測(cè)今年的國(guó)家線、院校線另一方面從數(shù)據(jù)里篩出匹配的院校并給出推薦排序。對(duì)正在準(zhǔn)備考研的同學(xué)來(lái)說(shuō)這是一套輔助決策工具對(duì)正在做畢業(yè)設(shè)計(jì)的學(xué)生來(lái)說(shuō)這是一個(gè)橫跨數(shù)據(jù)采集、數(shù)據(jù)清洗、算法建模、前后端開(kāi)發(fā)、系統(tǒng)部署的完整項(xiàng)目。這篇文章我會(huì)把整個(gè)系統(tǒng)的設(shè)計(jì)思路、算法細(xì)節(jié)、實(shí)現(xiàn)方案和踩坑過(guò)程拆開(kāi)講適合正在選畢設(shè)題目的本科生也適合想把類(lèi)似系統(tǒng)做成求職項(xiàng)目的人參考。1. 為什么選這個(gè)題目三個(gè)核心需求點(diǎn)與畢設(shè)適配度分析1.1 分?jǐn)?shù)預(yù)測(cè)解決“夠不夠得著”的問(wèn)題考研和高考有一個(gè)很大的不同高考是先出分再填志愿而考研是先填志愿再考試而且只能填一個(gè)目標(biāo)院校。這意味著考生在報(bào)名前必須回答一個(gè)非?,F(xiàn)實(shí)的問(wèn)題——以我的水平報(bào)哪所學(xué)校更可能考上沒(méi)有人能給出標(biāo)準(zhǔn)答案但歷年分?jǐn)?shù)線一定是最重要的參考維度之一。分?jǐn)?shù)線并不是一條孤立的數(shù)字它的波動(dòng)背后有規(guī)律可循。年份、試題難度、報(bào)考人數(shù)、錄取人數(shù)、院校熱度這些因素都會(huì)影響當(dāng)年分?jǐn)?shù)線。預(yù)測(cè)模塊的核心就是把這些歷史數(shù)據(jù)收集起來(lái)提取特征訓(xùn)練出能擬合這種波動(dòng)規(guī)律的模型輸出下一年的預(yù)測(cè)值。對(duì)于畢設(shè)來(lái)說(shuō)這里天然就有算法深度可以從簡(jiǎn)單的時(shí)間序列均值預(yù)測(cè)、線性回歸一路做到隨機(jī)森林、LSTM甚至可以對(duì)比不同模型的效果差異作為論文里很有說(shuō)服力的實(shí)驗(yàn)章節(jié)。對(duì)于考生而言預(yù)測(cè)結(jié)果雖然不能替代官方信息但能提供一個(gè)相對(duì)理性的參考區(qū)間。比如系統(tǒng)預(yù)測(cè)某專(zhuān)業(yè)今年的復(fù)試線會(huì)在350到365之間考生就可以結(jié)合自己??嫉那闆r判斷“報(bào)這所學(xué)校風(fēng)險(xiǎn)是否過(guò)大”。這就是這個(gè)系統(tǒng)實(shí)用價(jià)值最直接的體現(xiàn)。1.2 院校推薦解決“選哪所”的問(wèn)題全國(guó)有幾百所院校開(kāi)設(shè)碩士點(diǎn)每個(gè)學(xué)校又有不同的專(zhuān)業(yè)方向、考試科目、招生人數(shù)、報(bào)錄比、地理位置和就業(yè)口碑??忌跊](méi)有輔助工具的情況下想快速?gòu)倪@么多信息里找出一批“和自己匹配的學(xué)?!狈浅YM(fèi)時(shí)。院校推薦模塊解決的就是信息篩選和排序的問(wèn)題??忌斎肫脳l件比如“想在江浙滬”“只要計(jì)算機(jī)相關(guān)專(zhuān)業(yè)”“不接受專(zhuān)業(yè)課考408”“希望是211及以上”系統(tǒng)先做硬性過(guò)濾把所有不滿(mǎn)足條件的院校剔除然后對(duì)剩余院校做多維度評(píng)分排序。推薦結(jié)果不是憑空來(lái)的每一項(xiàng)都落到數(shù)據(jù)上歷年分?jǐn)?shù)線匹配度、報(bào)錄比、招生規(guī)模、專(zhuān)業(yè)課科目重合度、城市發(fā)展指數(shù)等。這種“規(guī)則過(guò)濾 加權(quán)評(píng)分”的思路在工程上是成熟且可解釋的非常適合作畢設(shè)核心功能同時(shí)也很容易在答辯環(huán)節(jié)講清楚。1.3 作為畢業(yè)設(shè)計(jì)的評(píng)分彈性從哪來(lái)一個(gè)題目能不能成為好的畢設(shè)關(guān)鍵在于評(píng)分彈性也就是不同投入程度的同學(xué)分別能做到什么水平?;A(chǔ)版本只需要完成數(shù)據(jù)的展示和查詢(xún)做一個(gè)前后端分離的信息系統(tǒng)具備院校信息維護(hù)、分?jǐn)?shù)線查詢(xún)、用戶(hù)登錄注冊(cè)這些功能工作量足夠撐起一個(gè)合格的本科畢設(shè)。進(jìn)階版本加入預(yù)測(cè)算法用真實(shí)數(shù)據(jù)訓(xùn)練模型并評(píng)估效果論文就有了核心實(shí)驗(yàn)章節(jié)。高階版本進(jìn)一步強(qiáng)化推薦策略引入多因子加權(quán)或者更復(fù)雜的排序算法再配合數(shù)據(jù)可視化大屏、后臺(tái)管理系統(tǒng)、定時(shí)數(shù)據(jù)更新任務(wù)整體完成度可以直接對(duì)標(biāo)求職作品集。而且這個(gè)題目還有一個(gè)天然優(yōu)勢(shì)考研是每年都有大量真實(shí)需求的社會(huì)話題評(píng)委不會(huì)質(zhì)疑題目沒(méi)有應(yīng)用場(chǎng)景也不用擔(dān)心業(yè)務(wù)邏輯太冷門(mén)導(dǎo)致答辯時(shí)講不清楚。2. 技術(shù)棧選型Django Vue.js 怎么分工以及“大數(shù)據(jù)”怎么落地2.1 Django做后端ORM、Admin、鑒權(quán)一站解決后端選擇 Django最核心的原因是開(kāi)發(fā)效率和對(duì)數(shù)據(jù)處理的友好度。Django 自帶 ORM定義好模型類(lèi)之后數(shù)據(jù)庫(kù)建表、增刪改查都不需要寫(xiě) SQL這對(duì)不熟悉數(shù)據(jù)庫(kù)細(xì)節(jié)的同學(xué)非常友好。比如分?jǐn)?shù)線歷史表、院校信息表、用戶(hù)表只需要定義幾個(gè) Python 類(lèi)遷移命令一執(zhí)行表結(jié)構(gòu)就自動(dòng)同步到數(shù)據(jù)庫(kù)后面改字段也不需要手動(dòng)去數(shù)據(jù)庫(kù)執(zhí)行 ALTER TABLE。另一個(gè)經(jīng)常被低估的能力是 Django Admin。這個(gè)自帶的后臺(tái)管理界面在畢設(shè)里幾乎等于“白送”一個(gè)管理端。維護(hù)院校名單、批量導(dǎo)入分?jǐn)?shù)線、管理用戶(hù)反饋這些操作在 Admin 后臺(tái)配置一下就能直接用不用額外寫(xiě)前端頁(yè)面。對(duì)于需要給評(píng)委演示“系統(tǒng)具有后臺(tái)管理功能”的畢設(shè)來(lái)說(shuō)這個(gè)功能節(jié)省的時(shí)間非??捎^。Django 的認(rèn)證體系也省事。用戶(hù)注冊(cè)、登錄、會(huì)話管理、密碼加密都是現(xiàn)成的接入自定義用戶(hù)模型就可以擴(kuò)展收藏院校、查詢(xún)記錄這類(lèi)業(yè)務(wù)字段。如果從零手寫(xiě)這些功能動(dòng)輒要多消耗一周的開(kāi)發(fā)時(shí)間。2.2 Vue.js做前端組件化與交互體驗(yàn)前端選擇 Vue.js主要看中它組件化的組織方式和成熟的生態(tài)。頁(yè)面拆成頭部導(dǎo)航、院校列表卡片、分?jǐn)?shù)線趨勢(shì)圖表、推薦結(jié)果面板這些獨(dú)立的 .vue 組件之后各組件只負(fù)責(zé)自己那一塊邏輯不會(huì)出現(xiàn)一個(gè)文件幾千行的問(wèn)題后期調(diào)試和維護(hù)的難度會(huì)低很多。Vue 的數(shù)據(jù)綁定非常適合這類(lèi)信息類(lèi)系統(tǒng)。以推薦結(jié)果頁(yè)為例用戶(hù)調(diào)整篩選條件后前端把條件參數(shù)發(fā)給后端接口拿到新的推薦列表之后通過(guò)數(shù)據(jù)響應(yīng)式機(jī)制自動(dòng)刷新頁(yè)面渲染。整個(gè)鏈路不需要手動(dòng)去操作 DOM代碼寫(xiě)起來(lái)更像是在描述“頁(yè)面上應(yīng)該顯示什么數(shù)據(jù)”而不是“一步步怎么操作頁(yè)面”。生態(tài)方面配套的 UI 組件庫(kù)、狀態(tài)管理工具、路由管理器都很成熟另外還有專(zhuān)門(mén)的圖表庫(kù)可以承接分?jǐn)?shù)線趨勢(shì)圖、預(yù)測(cè)對(duì)比圖這類(lèi)可視化需求。做畢設(shè)的時(shí)候不需要從零手寫(xiě)復(fù)雜圖表直接封裝組件即可。2.3 “大數(shù)據(jù)”標(biāo)簽怎么落地才不虛這個(gè)系統(tǒng)從數(shù)據(jù)量級(jí)來(lái)說(shuō)一年十幾萬(wàn)考生使用、數(shù)萬(wàn)條分?jǐn)?shù)線記錄確實(shí)不算是嚴(yán)格意義上的海量數(shù)據(jù)。但“大數(shù)據(jù)畢業(yè)設(shè)計(jì)”這個(gè)標(biāo)簽不是指必須上 Hadoop、Spark 集群而是指系統(tǒng)處理的數(shù)據(jù)規(guī)模、數(shù)據(jù)維度和性能優(yōu)化方式具備工程化思維。實(shí)際落地時(shí)我會(huì)從三個(gè)層面去貼這個(gè)標(biāo)簽。第一是數(shù)據(jù)層面設(shè)計(jì)合理的數(shù)據(jù)表結(jié)構(gòu)建立索引用 MySQL 存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù)用 Redis 做熱點(diǎn)數(shù)據(jù)緩存例如高頻訪問(wèn)的歷年分?jǐn)?shù)線匯總和推薦結(jié)果緩存。第二是接口性能層面列表分頁(yè)、ORM 查詢(xún)優(yōu)化、JSON 序列化優(yōu)化這些手段寫(xiě)進(jìn)論文里會(huì)是非常實(shí)際的性能分析章節(jié)。第三是任務(wù)調(diào)度層面設(shè)計(jì)一個(gè)定時(shí)更新的數(shù)據(jù)同步任務(wù)定時(shí)抓取最新的招生政策和分?jǐn)?shù)線數(shù)據(jù)讓系統(tǒng)具有持續(xù)更新的能力。這套組合拳寫(xiě)進(jìn)論文既能展示對(duì)數(shù)據(jù)鏈路的理解又不會(huì)把自己逼上非要搭分布式集群的絕路。畢設(shè)的重心是證明“我理解數(shù)據(jù)規(guī)模上來(lái)之后會(huì)有什么問(wèn)題以及怎么解決”而不是非要跑到多大規(guī)模才叫大數(shù)據(jù)。3. 分?jǐn)?shù)線預(yù)測(cè)模塊數(shù)據(jù)形態(tài)、模型選型與誤差控制3.1 預(yù)測(cè)三級(jí)別國(guó)家線、院校線、專(zhuān)業(yè)線分?jǐn)?shù)線預(yù)測(cè)不能籠統(tǒng)地說(shuō)“預(yù)測(cè)考研分?jǐn)?shù)線”因?yàn)榉謹(jǐn)?shù)線本身分了好幾個(gè)層級(jí)預(yù)測(cè)的目標(biāo)不同數(shù)據(jù)形態(tài)完全不一樣。最上層是考研國(guó)家線這是考生進(jìn)入復(fù)試的基本分?jǐn)?shù)要求分學(xué)術(shù)學(xué)位和專(zhuān)業(yè)學(xué)位又分 A 類(lèi)考生和 B 類(lèi)考生等不同類(lèi)別。國(guó)家線數(shù)據(jù)每年每個(gè)類(lèi)別只有一條時(shí)間跨度可能只有十幾條樣本這種數(shù)據(jù)量適合做長(zhǎng)期趨勢(shì)分析用移動(dòng)平均、線性回歸這類(lèi)簡(jiǎn)單模型即可強(qiáng)行上深度學(xué)習(xí)只會(huì)過(guò)擬合。中間層是院校線即院校在國(guó)家線基礎(chǔ)上劃定的復(fù)試分?jǐn)?shù)線。這部分?jǐn)?shù)據(jù)覆蓋的學(xué)校多、專(zhuān)業(yè)多樣本量相對(duì)充足是預(yù)測(cè)模塊的主戰(zhàn)場(chǎng)。比如某高校計(jì)算機(jī)學(xué)院的學(xué)碩復(fù)試線過(guò)去十年每年一條附加上當(dāng)年的報(bào)考人數(shù)、招生人數(shù)、試題難度等特征之后可以訓(xùn)練一個(gè)簡(jiǎn)單的回歸模型。最底層是專(zhuān)業(yè)線具體到某個(gè)學(xué)院某個(gè)專(zhuān)業(yè)的錄取最低分。這個(gè)層級(jí)最容易出現(xiàn)數(shù)據(jù)缺失很多院校只公布復(fù)試名單或擬錄取名單需要手動(dòng)整理才能得到完整的時(shí)間序列。因此專(zhuān)業(yè)線的預(yù)測(cè)通常只對(duì)數(shù)據(jù)條件好的重點(diǎn)專(zhuān)業(yè)做。預(yù)測(cè)時(shí)要特別注意“分?jǐn)?shù)線不是一個(gè)孤立時(shí)間序列”這件事。國(guó)家線、院校線、專(zhuān)業(yè)線之間有強(qiáng)關(guān)聯(lián)關(guān)系而且當(dāng)年的報(bào)考熱度、招生規(guī)模、試題難度都會(huì)導(dǎo)致分?jǐn)?shù)線異常波動(dòng)。把預(yù)測(cè)單純當(dāng)成“用過(guò)去幾年分?jǐn)?shù)線預(yù)測(cè)下一年”就太簡(jiǎn)單了會(huì)讓模型在數(shù)據(jù)波動(dòng)大的年份產(chǎn)生明顯偏差。3.2 特征工程怎么做我見(jiàn)過(guò)不少同學(xué)一上來(lái)就訓(xùn)練模型結(jié)果效果很差然后開(kāi)始懷疑算法選錯(cuò)了。實(shí)際上問(wèn)題往往出在特征上。分?jǐn)?shù)線預(yù)測(cè)的特征可以從三類(lèi)數(shù)據(jù)里去提取趨勢(shì)類(lèi)特征最近 N 年的分?jǐn)?shù)線值、移動(dòng)平均、同比增長(zhǎng)率、波動(dòng)幅度。這類(lèi)特征反映的是分?jǐn)?shù)線自身的變化慣性。競(jìng)爭(zhēng)類(lèi)特征報(bào)考人數(shù)、錄取人數(shù)、報(bào)錄比、推免比例。這類(lèi)特征反映供需關(guān)系對(duì)分?jǐn)?shù)線的壓力。背景類(lèi)特征當(dāng)年的試題難度評(píng)估、院校熱度排名、地區(qū)經(jīng)濟(jì)指數(shù)、政策變動(dòng)標(biāo)記。舉個(gè)例子某專(zhuān)業(yè)過(guò)去五年招生人數(shù)逐年減少報(bào)考人數(shù)卻在增加報(bào)錄比從 5:1 漲到 9:1那么即便分?jǐn)?shù)線歷史曲線平穩(wěn)模型也應(yīng)該給出更高的預(yù)測(cè)值。這就是競(jìng)爭(zhēng)類(lèi)特征存在的意義。特征構(gòu)造的具體操作上常用滑動(dòng)窗口的方式把時(shí)間序列轉(zhuǎn)成監(jiān)督學(xué)習(xí)數(shù)據(jù)集。比如用前三年的數(shù)據(jù)預(yù)測(cè)第四年那么每一條訓(xùn)練樣本就由長(zhǎng)度為 3 的窗口特征加上一個(gè)目標(biāo)值構(gòu)成。窗口大小一般取 3 到 5太小了模型學(xué)不到長(zhǎng)期趨勢(shì)太大了樣本量會(huì)被嚴(yán)重削減。3.3 模型對(duì)比線性回歸、隨機(jī)森林、LSTM哪家強(qiáng)這里直接給結(jié)論畢設(shè)階段不要只做一個(gè)模型而是做一組對(duì)比實(shí)驗(yàn)最后用實(shí)驗(yàn)數(shù)據(jù)說(shuō)明為什么選某個(gè)模型作為最終方案。這套對(duì)比本身就是論文的核心實(shí)驗(yàn)章節(jié)。線性回歸是最穩(wěn)的 baseline它的優(yōu)勢(shì)在于可解釋性強(qiáng)。訓(xùn)練完之后可以明確看到“報(bào)考人數(shù)每增加一萬(wàn)人分?jǐn)?shù)線大約會(huì)上升多少分”這種結(jié)論寫(xiě)進(jìn)論文非常直觀而且評(píng)委很容易聽(tīng)懂。隨機(jī)森林適合處理特征和目標(biāo)之間存在非線性關(guān)系的情況對(duì)異常值不像線性回歸那么敏感不需要做特別精細(xì)的特征縮放屬于“省心但不太好解釋”的選手。LSTM 是深度學(xué)習(xí)的代表理論上能捕捉時(shí)間序列中的長(zhǎng)期依賴(lài)。但這類(lèi)數(shù)據(jù)通常只有十幾到幾十條樣本LSTM 非常容易過(guò)擬合訓(xùn)練出來(lái)的效果往往還不如隨機(jī)森林。這不是 LSTM 本身的問(wèn)題而是樣本量撐不起模型的復(fù)雜度。實(shí)際對(duì)比下來(lái)經(jīng)常會(huì)出現(xiàn)“LSTM 在訓(xùn)練集上效果很好在測(cè)試集上一塌糊涂”的典型場(chǎng)景。推薦的做法是用線性回歸和隨機(jī)森林作為主要預(yù)測(cè)模型做參數(shù)調(diào)優(yōu)LSTM 作為深度學(xué)習(xí)方法做對(duì)照實(shí)驗(yàn)論文里明確寫(xiě)出“由于樣本量限制LSTM 未能穩(wěn)定超越集成模型”這個(gè)結(jié)論。這反而是數(shù)據(jù)量不夠大的項(xiàng)目中最誠(chéng)實(shí)也最有說(shuō)服力的實(shí)驗(yàn)設(shè)計(jì)。模型訓(xùn)練過(guò)程要格外注意數(shù)據(jù)泄露問(wèn)題。特征里如果有“今年的報(bào)考人數(shù)”和“今年的分?jǐn)?shù)線”同時(shí)出現(xiàn)在同一條樣本里測(cè)試階段又用未來(lái)數(shù)據(jù)去預(yù)測(cè)過(guò)去評(píng)估結(jié)果就會(huì)虛高。按時(shí)間順序分割訓(xùn)練集和測(cè)試集是這類(lèi)項(xiàng)目的基本紀(jì)律比如用前 80% 的時(shí)間段訓(xùn)練、后 20% 的時(shí)間段驗(yàn)證。模型適合的數(shù)據(jù)量可解釋性實(shí)現(xiàn)難度畢設(shè)推薦度線性回歸15條以上可用強(qiáng)低必做baseline隨機(jī)森林30條以上效果較好中低主力模型LSTM通常需要數(shù)百條弱高對(duì)照實(shí)驗(yàn)ARIMA20條以上可用中中可做時(shí)序?qū)Ρ?.4 模型評(píng)估與結(jié)果可視化預(yù)測(cè)結(jié)果不能只丟一個(gè)數(shù)字一定要帶上置信區(qū)間或波動(dòng)范圍。原因很簡(jiǎn)單考生需要知道“預(yù)測(cè)線是 350”更需要知道“這個(gè)預(yù)測(cè)有多可靠”。如果歷史數(shù)據(jù)波動(dòng)較大模型給出的區(qū)間自然就寬如果歷年數(shù)據(jù)很穩(wěn)定區(qū)間就窄。這種表達(dá)方式比單一數(shù)值更有參考價(jià)值。評(píng)估指標(biāo)用 MAE平均絕對(duì)誤差和 RMSE均方根誤差就夠了。MAE 的直觀含義是“平均預(yù)測(cè)偏差多少分”比如 MAE 為 6.5 分可以理解為預(yù)測(cè)線和實(shí)際線平均差 6.5 分左右。RMSE 對(duì)大誤差更敏感如果預(yù)測(cè)偶爾出現(xiàn)了一次超過(guò) 20 分的偏差RMSE 會(huì)拉得很高這也是一個(gè)很重要的參考信號(hào)??梢暬矫媲岸丝梢杂谜劬€圖展示歷史分?jǐn)?shù)線曲線與預(yù)測(cè)點(diǎn)的對(duì)比用柱狀圖展示不同院校預(yù)測(cè)難度的對(duì)比用散點(diǎn)圖展示實(shí)際值與預(yù)測(cè)值的貼合程度。圖表的意義不只是好看更是答辯時(shí)最直觀的“證據(jù)”。我見(jiàn)過(guò)很多學(xué)生算法講得不清不楚但圖表一亮出來(lái)評(píng)委馬上就能看懂你做了什么、效果怎么樣。4. 院校推薦模塊硬性篩選 多維加權(quán)評(píng)分4.1 推薦流程分兩步不要混在一起做推薦系統(tǒng)最容易犯的錯(cuò)誤是把所有的篩選和排序條件揉在一起最后用戶(hù)和評(píng)委都搞不清楚結(jié)果是怎么來(lái)的。正確做法是把推薦流程明確拆成前后兩個(gè)階段。第一階段是硬性條件過(guò)濾也叫“一票否決”。比如用戶(hù)要求只接收統(tǒng)考數(shù)學(xué)的專(zhuān)業(yè)那所有考數(shù)學(xué)二或自命題的專(zhuān)業(yè)直接排除用戶(hù)要求不想去偏遠(yuǎn)地區(qū)那不符合地區(qū)條件的院校直接排除。這個(gè)階段不做任何打分條件不滿(mǎn)足就出局。硬性條件通常來(lái)自用戶(hù)表單里的下拉選項(xiàng)字段設(shè)計(jì)得越明確過(guò)濾越干凈。第二階段是對(duì)剩余院校做多維加權(quán)評(píng)分。每一所院校先分別計(jì)算各個(gè)子維度的得分再按權(quán)重加權(quán)求和得到綜合評(píng)分最后按綜合評(píng)分降序排列。排序結(jié)果可以按“沖、穩(wěn)、?!比龣n標(biāo)注出來(lái)對(duì)應(yīng)預(yù)測(cè)錄取概率的高中低這樣考生一眼就能看出哪些學(xué)校值得沖一下哪些學(xué)校是穩(wěn)妥選擇哪些是保底選擇。4.2 評(píng)分維度與權(quán)重設(shè)計(jì)評(píng)分維度是推薦系統(tǒng)的靈魂。維度設(shè)計(jì)不合理后面的權(quán)重全是白調(diào)。以這個(gè)系統(tǒng)為例我通常會(huì)設(shè)計(jì)五個(gè)核心維度分?jǐn)?shù)匹配度用戶(hù)預(yù)估分?jǐn)?shù)與院校預(yù)測(cè)線之間的差值差值越接近零且略微超過(guò)匹配度越高。這個(gè)維度直接決定了“能不能考上的可能性”。報(bào)錄比競(jìng)爭(zhēng)度報(bào)錄比越高說(shuō)明競(jìng)爭(zhēng)越激烈得分越低。如果報(bào)錄比數(shù)據(jù)缺失就退而求其次用“錄取人數(shù)”做替代指標(biāo)。招生規(guī)模友好度招生人數(shù)多的院校容錯(cuò)空間更大得分適當(dāng)提升。專(zhuān)業(yè)課契合度用戶(hù)的本科課程和該校考試科目重疊度越高備考成本越低得分越高。發(fā)展資源指數(shù)包括院校層次、學(xué)科評(píng)估檔次、所在城市發(fā)展水平。這部分?jǐn)?shù)據(jù)相對(duì)穩(wěn)定可以維護(hù)成基礎(chǔ)字典表。權(quán)重的設(shè)置優(yōu)先用層次分析法或者熵權(quán)法來(lái)確定而不是拍腦袋定數(shù)字。簡(jiǎn)單做法是設(shè)計(jì)一張專(zhuān)家打分問(wèn)卷讓幾位有經(jīng)驗(yàn)的學(xué)長(zhǎng)學(xué)姐對(duì)維度重要性打分然后構(gòu)造成對(duì)比較矩陣計(jì)算權(quán)重。這一段寫(xiě)進(jìn)論文能讓推薦算法顯得科學(xué)很多。評(píng)分公式可以簡(jiǎn)化成綜合評(píng)分 各項(xiàng)子分?jǐn)?shù)乘以對(duì)應(yīng)權(quán)重后求和再把結(jié)果縮放映射到 0 到 100 分的區(qū)間。子分?jǐn)?shù)的計(jì)算邏輯要做到能夠解釋清楚每一步尤其要避免“黑盒推薦”。提示推薦結(jié)果一定要提供“為什么推薦這所學(xué)?!钡恼f(shuō)明比如顯示“這所學(xué)校近三年分?jǐn)?shù)線與你的預(yù)估分?jǐn)?shù)高度匹配且招生人數(shù)近年呈擴(kuò)招趨勢(shì)”。透明的推薦邏輯比黑盒高分更容易取信用戶(hù)。4.3 預(yù)測(cè)和推薦怎么聯(lián)動(dòng)分?jǐn)?shù)線預(yù)測(cè)模塊和院校推薦模塊不是兩個(gè)獨(dú)立的功能而應(yīng)該是一條完整鏈路里的兩個(gè)環(huán)節(jié)先預(yù)測(cè)各目標(biāo)院校的專(zhuān)業(yè)分?jǐn)?shù)線再把這些預(yù)測(cè)結(jié)果作為推薦評(píng)分的關(guān)鍵輸入。具體的聯(lián)動(dòng)方式是這樣的用戶(hù)輸入預(yù)估分?jǐn)?shù)后系統(tǒng)先調(diào)預(yù)測(cè)模塊計(jì)算該用戶(hù)所有候選院校的預(yù)測(cè)分?jǐn)?shù)線然后計(jì)算差距。比如某校預(yù)測(cè)線是 355用戶(hù)估分是 360兩者差距只有 5 分分?jǐn)?shù)匹配度得分就高另一所學(xué)校預(yù)測(cè)線是 380差距 20 分分?jǐn)?shù)匹配度得分就低。預(yù)測(cè)結(jié)果直接參與推薦評(píng)分用戶(hù)在推薦頁(yè)看到的不只是“往年的分?jǐn)?shù)線”而是“基于模型預(yù)測(cè)的今年分?jǐn)?shù)線”這個(gè)體驗(yàn)比靜態(tài)查詢(xún)歷史數(shù)據(jù)要高一個(gè)層次。反過(guò)來(lái)推薦模塊的使用行為也能為預(yù)測(cè)提供反饋數(shù)據(jù)。用戶(hù)頻繁查看但最終沒(méi)有選擇的院校可能意味著它們熱度偏高這個(gè)熱度信號(hào)經(jīng)過(guò)量化后可以作為下一輪預(yù)測(cè)時(shí)的特征輸入。這種雙向閉環(huán)可以寫(xiě)進(jìn)論文的“系統(tǒng)迭代與后續(xù)展望”部分屬于很有內(nèi)容的加分項(xiàng)。5. 數(shù)據(jù)鏈路采集、清洗、對(duì)齊與入庫(kù)5.1 公開(kāi)數(shù)據(jù)源與采集策略這類(lèi)系統(tǒng)的數(shù)據(jù)來(lái)源以公開(kāi)渠道為主教育招生主管部門(mén)公示的數(shù)據(jù)、各院校研究生院官網(wǎng)公布的招生簡(jiǎn)章與歷年復(fù)試分?jǐn)?shù)線、考研信息平臺(tái)上的匯總數(shù)據(jù)等。采集方式分兩種一種是針對(duì)頁(yè)面結(jié)構(gòu)固定的網(wǎng)站寫(xiě)定向爬蟲(chóng)另一種是下載公開(kāi)的統(tǒng)計(jì)文件后做結(jié)構(gòu)化解析。做定向爬蟲(chóng)的時(shí)候要注意目標(biāo)網(wǎng)站的請(qǐng)求頻率控制設(shè)置合理的訪問(wèn)間隔避免給對(duì)方服務(wù)器造成壓力。另外有些網(wǎng)站有反爬機(jī)制驗(yàn)證碼和登錄限制會(huì)給采集帶來(lái)很大的工作量所以前期評(píng)估數(shù)據(jù)源時(shí)要優(yōu)先選結(jié)構(gòu)公開(kāi)、訪問(wèn)穩(wěn)定的站點(diǎn)。如果自身編程經(jīng)驗(yàn)有限也可以考慮手動(dòng)整理一部分核心數(shù)據(jù)??佳泻诵脑盒?shù)量控制在幾十所每所院校的重點(diǎn)專(zhuān)業(yè)分?jǐn)?shù)線手動(dòng)錄入也不是完全不能接受但前提是要有足夠的時(shí)間和耐心。折中方案是“爬蟲(chóng)采集 人工校對(duì)”機(jī)器先抓主要字段再人工抽檢修正異常值這也是企業(yè)里很多數(shù)據(jù)團(tuán)隊(duì)的日常操作方式。5.2 數(shù)據(jù)清洗和對(duì)齊的坑分?jǐn)?shù)線數(shù)據(jù)的清洗難度被很多人低估了。最常見(jiàn)的坑包括同一所學(xué)校在不同年份的數(shù)據(jù)口徑不一致有的年份公布的是復(fù)試基本分?jǐn)?shù)線有的年份公布的是擬錄取最低分兩者之間可以相差幾十分直接混在一起訓(xùn)練模型會(huì)出大問(wèn)題。還有專(zhuān)業(yè)名稱(chēng)不統(tǒng)一的問(wèn)題。同一專(zhuān)業(yè)在不同院校可能叫“電子與信息”“信息與通信工程”“電子信息”如果不做學(xué)科代碼對(duì)齊推薦系統(tǒng)匹配專(zhuān)業(yè)時(shí)就會(huì)漏掉大量應(yīng)該出現(xiàn)的院校。缺失值的處理需要分情況。如果某個(gè)院校某一年分?jǐn)?shù)線缺失但前后兩年都有數(shù)據(jù)可以用前后均值填充如果某院校近一半的數(shù)據(jù)都缺失建議直接不把該院校放到預(yù)測(cè)候選集里而不是強(qiáng)行用填充值污染模型。年份對(duì)齊也是老生常談?dòng)行┰盒S玫氖侨雽W(xué)年份口徑有些用的是招生年份口徑差一年會(huì)導(dǎo)致你的時(shí)間序列整體錯(cuò)位這是很隱蔽但影響極大的問(wèn)題。數(shù)據(jù)清洗階段我強(qiáng)烈建議寫(xiě)校驗(yàn)?zāi)_本而不是純手動(dòng)改 Excel。腳本可以維護(hù)一張“院校別名表”和“專(zhuān)業(yè)別名表”做自動(dòng)映射也可以寫(xiě)一份數(shù)據(jù)質(zhì)量報(bào)告統(tǒng)計(jì)每條記錄的缺失率、異常值數(shù)量方便反復(fù)檢查調(diào)整。5.3 數(shù)據(jù)庫(kù)表設(shè)計(jì)與更新機(jī)制表設(shè)計(jì)上我會(huì)分成五張核心表院校信息表、專(zhuān)業(yè)方向表、歷年分?jǐn)?shù)線表、招生計(jì)劃表、用戶(hù)行為表。院校信息表存學(xué)校的基礎(chǔ)屬性專(zhuān)業(yè)方向表存學(xué)校和專(zhuān)業(yè)的關(guān)聯(lián)關(guān)系歷年分?jǐn)?shù)線表存時(shí)間序列數(shù)據(jù)招生計(jì)劃表存歷年計(jì)劃招生人數(shù)和報(bào)考人數(shù)用戶(hù)行為表存收藏、查詢(xún)記錄。這五張表之間的關(guān)聯(lián)關(guān)系并不復(fù)雜重點(diǎn)是給高頻查詢(xún)字段創(chuàng)建索引。分?jǐn)?shù)線和招生計(jì)劃都是典型“按院校查、按專(zhuān)業(yè)查、按年份查”的結(jié)構(gòu)索引能明顯提升查詢(xún)速度。更新機(jī)制方面可以設(shè)計(jì)一個(gè)管理命令或定時(shí)任務(wù)。每次更新時(shí)先抓取新增的分?jǐn)?shù)線數(shù)據(jù)做差量更新而不是全量覆蓋以保留歷史數(shù)據(jù)完整性和變動(dòng)記錄。再配合 Django Admin 提供人工修正入口機(jī)器抓取和人工審核結(jié)合起來(lái)讓數(shù)據(jù)質(zhì)量可控。6. 從代碼到演示核心接口、前端頁(yè)面與本地跑通6.1 API設(shè)計(jì)請(qǐng)求與響應(yīng)約定前后端分離項(xiàng)目的關(guān)鍵是一套約定清晰的接口協(xié)議。我通常采用 RESTful 風(fēng)格統(tǒng)一響應(yīng)結(jié)構(gòu)。比如推薦接口的設(shè)計(jì)是前端 POST 用戶(hù)的篩選條件和預(yù)估分?jǐn)?shù)后端經(jīng)過(guò)過(guò)濾和評(píng)分后返回推薦院校列表每條推薦項(xiàng)包含院?;拘畔ⅰ㈩A(yù)測(cè)分?jǐn)?shù)線、各個(gè)子維度得分和綜合評(píng)分。響應(yīng)結(jié)構(gòu)固定為包含狀態(tài)碼、消息、數(shù)據(jù)和分頁(yè)信息的 JSON 格式前端通過(guò)狀態(tài)碼判斷請(qǐng)求是否成功再用消息字段展示錯(cuò)誤提示。這么做的好處是前后端可以并行開(kāi)發(fā)前端根據(jù)接口文檔 mock 數(shù)據(jù)后端按文檔實(shí)現(xiàn)邏輯最后聯(lián)調(diào)時(shí)再修正細(xì)節(jié)。注意接口文檔要寫(xiě)清楚每個(gè)字段的類(lèi)型、是否必填、取值范圍。推薦接口尤其要說(shuō)明評(píng)分字段的含義比如 score 是 0 到 100 的綜合評(píng)分rank 是 “沖穩(wěn)?!?標(biāo)記以免前端同學(xué)看著一堆數(shù)字不知道怎么展示。6.2 前端重點(diǎn)頁(yè)面拆解前端頁(yè)面不需要做得多花哨但關(guān)鍵路徑上的幾個(gè)頁(yè)面必須功能完整、邏輯清晰。核心頁(yè)面包括首頁(yè)展示系統(tǒng)核心能力入口簡(jiǎn)單放推薦流程圖和數(shù)據(jù)統(tǒng)計(jì)卡片。分?jǐn)?shù)線查詢(xún)頁(yè)支持按院校、專(zhuān)業(yè)、年份篩選用折線圖展示歷年分?jǐn)?shù)線變化趨勢(shì)。預(yù)測(cè)結(jié)果頁(yè)展示各目標(biāo)院校預(yù)測(cè)分?jǐn)?shù)線配置信區(qū)間帶和模型對(duì)比說(shuō)明。個(gè)性化推薦頁(yè)表單輸入偏好和預(yù)估分?jǐn)?shù)提交后展示推薦列表卡片式布局展示各維度得分和推薦理由。院校詳情頁(yè)展示某所學(xué)校的詳細(xì)信息、歷年分?jǐn)?shù)線表格、招生人數(shù)趨勢(shì)、相關(guān)推薦院校。后臺(tái)管理頁(yè)復(fù)用 Django Admin 定制用于維護(hù)院校數(shù)據(jù)和分?jǐn)?shù)線數(shù)據(jù)。頁(yè)面組件化之后公共部分如導(dǎo)航欄、頁(yè)腳、篩選表單、圖表卡片等都做成通用組件不同頁(yè)面復(fù)用代碼量能縮減不少。圖表組件建議統(tǒng)一封裝傳入數(shù)據(jù)格式之后自動(dòng)渲染折線圖、柱狀圖或散點(diǎn)圖保持風(fēng)格一致。6.3 本地跑通的完整步驟本地把項(xiàng)目跑起來(lái)的流程每一步都值得仔細(xì)梳理創(chuàng)建虛擬環(huán)境并激活避免依賴(lài)包和系統(tǒng)環(huán)境互相干擾。安裝 Python 依賴(lài)核心包括 Django、數(shù)據(jù)庫(kù)驅(qū)動(dòng)、數(shù)據(jù)處理庫(kù)、機(jī)器學(xué)習(xí)庫(kù)和跨域支持庫(kù)。前端在項(xiàng)目目錄下執(zhí)行 npm install 安裝依賴(lài)包。在 MySQL 中創(chuàng)建數(shù)據(jù)庫(kù)實(shí)例修改 Django 配置里的數(shù)據(jù)庫(kù)連接信息注意編碼設(shè)置成 utf8mb4否則中文數(shù)據(jù)入庫(kù)容易亂碼。執(zhí)行數(shù)據(jù)庫(kù)遷移生成表結(jié)構(gòu)導(dǎo)入初始化的院校和分?jǐn)?shù)線數(shù)據(jù)。啟動(dòng) Django 后端服務(wù)先訪問(wèn)接口文檔或直接訪問(wèn)某個(gè)查詢(xún)接口確認(rèn)后端返回正常數(shù)據(jù)。啟動(dòng) Vue 開(kāi)發(fā)服務(wù)配置本地開(kāi)發(fā)環(huán)境的接口地址代理把前端請(qǐng)求轉(zhuǎn)發(fā)到后端服務(wù)避免跨域問(wèn)題。用測(cè)試賬號(hào)登錄系統(tǒng)完整走一遍“查詢(xún)分?jǐn)?shù)線 – 查看預(yù)測(cè) – 提交推薦條件 – 查看推薦結(jié)果”的流程確認(rèn)頁(yè)面數(shù)據(jù)和后端日志都沒(méi)有報(bào)錯(cuò)。第一次跑通之后建議把整套啟動(dòng)命令和注意事項(xiàng)整理成項(xiàng)目根目錄里的 README 文件或者直接錄制一份演示視頻。答辯時(shí)如果現(xiàn)場(chǎng)環(huán)境出現(xiàn)問(wèn)題演示視頻就是最穩(wěn)妥的備份方案。7. 實(shí)戰(zhàn)中的坑性能、過(guò)擬合、聯(lián)調(diào)與部署7.1 Django ORM查詢(xún)與序列化的性能問(wèn)題Django ORM 用起來(lái)省事但默認(rèn)行為里藏著不少性能陷阱。最常見(jiàn)的是 N1 查詢(xún)問(wèn)題遍歷院校列表每訪問(wèn)一次關(guān)聯(lián)的專(zhuān)業(yè)或分?jǐn)?shù)線就額外執(zhí)行一次數(shù)據(jù)庫(kù)查詢(xún)列表長(zhǎng)度變成 100 時(shí)數(shù)據(jù)庫(kù)壓力就變成 1 100 次查詢(xún)。解決辦法是在查詢(xún)時(shí)用 select_related 和 prefetch_related 提前把關(guān)聯(lián)數(shù)據(jù)加載進(jìn)來(lái)把多次查詢(xún)合并成一次大查詢(xún)。在畢設(shè)演示階段數(shù)據(jù)量小可能看不出差別但論文里寫(xiě)出這個(gè)優(yōu)化前后的查詢(xún)時(shí)間和內(nèi)存占用對(duì)比就是一筆很扎實(shí)的性能優(yōu)化章節(jié)。序列化階段也要注意。不要把整個(gè)關(guān)聯(lián)對(duì)象鏈全部序列化比如某院校關(guān)聯(lián)了三十年的分?jǐn)?shù)線和所有招生計(jì)劃前端只需要近五年的數(shù)據(jù)后端就應(yīng)該在序列化時(shí)做字段過(guò)濾和切片而不是把全量 JSON 發(fā)給瀏覽器。過(guò)大的響應(yīng)體除了拖慢加載速度還會(huì)在演示時(shí)被評(píng)委當(dāng)場(chǎng)發(fā)現(xiàn)頁(yè)面半天轉(zhuǎn)不出來(lái)。7.2 模型過(guò)擬合數(shù)據(jù)少怎么辦時(shí)間序列預(yù)測(cè)和普通分類(lèi)任務(wù)不同樣本量天然受限很容易出現(xiàn)訓(xùn)練集效果極好、驗(yàn)證集一塌糊涂的過(guò)擬合問(wèn)題。我的經(jīng)驗(yàn)是不要硬扛著訓(xùn)練深度學(xué)習(xí)模型而是采用多種手段降低過(guò)擬合的影響。一方面是減少模型復(fù)雜度比如線性回歸加正則化項(xiàng)隨機(jī)森林限制最大深度和最小葉子節(jié)點(diǎn)數(shù)。另一方面是合理做交叉驗(yàn)證時(shí)間序列不能隨機(jī)打亂要用按時(shí)間順序前進(jìn)式的驗(yàn)證方式。還有一種很實(shí)用的思路是把相近專(zhuān)業(yè)的分?jǐn)?shù)線合并起來(lái)擴(kuò)充樣本比如同屬工科門(mén)類(lèi)的幾個(gè)專(zhuān)業(yè)分?jǐn)?shù)線走勢(shì)具有較強(qiáng)的相關(guān)性可以放在同一個(gè)數(shù)據(jù)集里訓(xùn)練讓模型學(xué)到整個(gè)門(mén)類(lèi)的共性規(guī)律。預(yù)測(cè)結(jié)果也應(yīng)該輸出區(qū)間而不是硬報(bào)一個(gè)精確值。在預(yù)測(cè)值基礎(chǔ)上加減一倍的預(yù)測(cè)標(biāo)準(zhǔn)差作為參考區(qū)間一方面能規(guī)避模型偶爾的較大偏差另一方面也讓系統(tǒng)的輸出更顯專(zhuān)業(yè)和可信。7.3 前后端聯(lián)調(diào)與部署的常見(jiàn)問(wèn)題前后端聯(lián)調(diào)階段最常見(jiàn)的坑就是跨域配置。本地開(kāi)發(fā)時(shí)后端服務(wù)運(yùn)行在 8000 端口前端開(kāi)發(fā)服務(wù)運(yùn)行在 5173 或 8080 端口瀏覽器會(huì)阻止跨源的 Ajax 請(qǐng)求。本地環(huán)境的解決方案是配置開(kāi)發(fā)代理把前端請(qǐng)求轉(zhuǎn)發(fā)到后端如果已經(jīng)部署到生產(chǎn)環(huán)境則要在后端正確配置允許的跨域來(lái)源列表并處理好預(yù)檢請(qǐng)求。部署環(huán)節(jié)需要注意的細(xì)節(jié)更多。首先是生產(chǎn)模式下的靜態(tài)文件收集Django 需要把所有前端構(gòu)建產(chǎn)物和自身靜態(tài)文件集中到一個(gè)目錄再交給服務(wù)軟件托管。其次是數(shù)據(jù)庫(kù)配置從 SQLite 切到 MySQL 后要重新執(zhí)行遷移和導(dǎo)入數(shù)據(jù)別拿著測(cè)試庫(kù)直接上生產(chǎn)。最后一個(gè)容易被忽略的問(wèn)題是環(huán)境變量管理。數(shù)據(jù)庫(kù)密碼、密鑰這類(lèi)敏感信息不要硬編碼在配置文件中用環(huán)境變量注入是一個(gè)好習(xí)慣。部署一臺(tái)最小配置的云服務(wù)器使用 Nginx 托管靜態(tài)文件、使用 Python 應(yīng)用服務(wù)器托管 Django再把前端構(gòu)建產(chǎn)物放到靜態(tài)目錄下用 Nginx 統(tǒng)一對(duì)外提供服務(wù)整個(gè)鏈路就通了。這一套部署方案在論文里寫(xiě)清楚項(xiàng)目的完整度會(huì)明顯提升。8. 我的實(shí)操體會(huì)與建議我實(shí)際帶著這類(lèi)項(xiàng)目走查過(guò)很多輪之后最大的感受是這個(gè)題目的上限比大多數(shù)人想象得高但大多數(shù)人沒(méi)能把上限做出來(lái)。原因不在于算法多難、代碼多復(fù)雜而在于很多人把精力花在了寫(xiě)代碼之外的東西上——有的同學(xué)花了太多時(shí)間糾結(jié)某一個(gè)院校的推薦權(quán)重是不是“絕對(duì)合理”其實(shí)評(píng)分權(quán)重本來(lái)就是主觀設(shè)計(jì)加客觀數(shù)據(jù)校準(zhǔn)的結(jié)果能解釋清楚邏輯就夠了還有的同學(xué)把精力花在爬全量數(shù)據(jù)上導(dǎo)致整個(gè)項(xiàng)目周期被數(shù)據(jù)采集拖垮最后核心系統(tǒng)反而沒(méi)時(shí)間完善。我的建議是把握住一個(gè)原則先讓主流程完整跑通再談細(xì)節(jié)完善。分?jǐn)?shù)線預(yù)測(cè)跑出一個(gè)可解釋的效果推薦模塊給出透明可理解的排序邏輯前后端聯(lián)調(diào)順暢這就已經(jīng)是一個(gè)合格且完整的畢設(shè)了。在此基礎(chǔ)上如果還有時(shí)間再去豐富數(shù)據(jù)維度、優(yōu)化模型效果、增加部署文檔。另外數(shù)據(jù)分析能力的展示強(qiáng)烈建議別忽略。預(yù)測(cè)模型的評(píng)估圖表、推薦結(jié)果的可解釋理由、數(shù)據(jù)庫(kù)與接口的性能優(yōu)化記錄這些內(nèi)容寫(xiě)到文檔和PPT里答辯時(shí)的說(shuō)服力會(huì)遠(yuǎn)遠(yuǎn)超過(guò)放幾張頁(yè)面截圖。做這套系統(tǒng)不只是為了畢業(yè)把數(shù)據(jù)采集到展示的每個(gè)環(huán)節(jié)打通之后這份經(jīng)驗(yàn)放到任何數(shù)據(jù)產(chǎn)品或后臺(tái)系統(tǒng)的項(xiàng)目里都能遷移。