據(jù)分析預測系統(tǒng)實戰(zhàn):從數(shù)據(jù)清洗到XGBoost模型部署全流程)
簡介面向計算機專業(yè)正在做課程設計或期末大作業(yè)的學生以及需要項目實戰(zhàn)練習的學習者這份Python二手房數(shù)據(jù)分析預測系統(tǒng)資料提供完整可運行的實戰(zhàn)項目。內容涵蓋數(shù)據(jù)清洗、房價分析與預測建模的全流程源碼同時附帶文檔報告便于理解數(shù)據(jù)挖掘項目的整體結構并快速參考復用。壓縮包共156個文件以18個Python腳本、18個CSV數(shù)據(jù)文件、15個HTML頁面、11個JavaScript文件為主體另有大量可視化圖表圖片與配置文件等包體大小約40.03MB各類文件按用途歸類清晰。目前已有831人學習使用項目經(jīng)過嚴格調試下載解壓后即可直接運行。通過源碼與報告的對應學習讀者能夠系統(tǒng)掌握數(shù)據(jù)預處理、特征工程、模型構建與結果展示的核心思路尤其適合期末答辯、課程設計以及希望獲得高分范例的開發(fā)者作為實踐模板。1. 二手房數(shù)據(jù)分析預測系統(tǒng)數(shù)據(jù)從業(yè)者繞不開的完整實戰(zhàn)項目把一套二手房數(shù)據(jù)分析預測系統(tǒng)從零搭起來最反直覺的結論是模型挑得再好不如數(shù)據(jù)洗得干凈。我見過太多人花兩周調 XGBoost 參數(shù)最后發(fā)現(xiàn)訓練集 R2 高達 0.96、測試集只有 0.55原因只是特征里混進了帶價格的字段。這篇文章不說空泛理論只講一條能直接上手的完整流程房源數(shù)據(jù)采集清洗、特征工程、模型訓練評估再到項目落地才會遇到的坑和部署路徑。適合想獨立完成數(shù)據(jù)項目、能對每個環(huán)節(jié)講清楚取舍的從業(yè)者。文中代碼都能直接改著跑。2. 數(shù)據(jù)從哪來二手房源采集與清洗的完整鏈路無論模型多先進、特征多精巧采集和清洗決定了數(shù)據(jù)基本面。這一部分看起來沒有模型那么高級但恰恰是項目成敗的分水嶺。本節(jié)先解決數(shù)據(jù)從哪來的問題再做臟數(shù)據(jù)清洗跑完這兩步你手里就有一份能進模型的干凈表格。2.1 抓取房源信息requests BeautifulSoup 的最小采集方案采集是數(shù)據(jù)系統(tǒng)的源頭也是新手最容易卡住的環(huán)節(jié)。常見做法是用 requests 請求目標站點的列表頁再用 BeautifulSoup 解析 HTML把每套房子的標題、小區(qū)、戶型、面積、樓層、朝向、總價、單價、掛牌時間抽出來。別一上來就上 Scrapy——先跑通單頁采集確認字段能取全再談并發(fā)和框架。import requests import time import random from bs4 import BeautifulSoup # 請求頭必須帶很多站點會根據(jù) UA 特征攔截腳本 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 } def parse_list_page(html_text): 從列表頁 HTML 中提取房源字段返回字典列表 soup BeautifulSoup(html_text, html.parser) items [] for card in soup.select(.listing-card): # 選擇器以實際頁面 DOM 為準 item { house_id: card.select_one(.house-id).get_text(stripTrue), title: card.select_one(.title).get_text(stripTrue), community: card.select_one(.community).get_text(stripTrue), layout: card.select_one(.layout).get_text(stripTrue), area: card.select_one(.area).get_text(stripTrue), total_price: card.select_one(.price).get_text(stripTrue), unit_price: card.select_one(.unit-price).get_text(stripTrue), } items.append(item) return items def crawl_pages(start_page, end_page): 翻頁采集每頁之間加隨機延時 all_items [] for page in range(start_page, end_page 1): url fhttps://your-target-site.com/ershoufang/pg{page}/ resp requests.get(url, headersheaders, timeout10) if resp.status_code ! 200: print(f第{page}頁返回異常狀態(tài)碼: {resp.status_code}) continue page_items parse_list_page(resp.text) all_items.extend(page_items) time.sleep(random.uniform(2, 5)) # 隨機延時是續(xù)命關鍵 return all_items這段代碼的邏輯很直白parse_list_page 負責解析單頁crawl_pages 負責翻頁并匯總。核心有三個值得細說。第一個是 headersUser-Agent 偽裝是讓請求看起來像真實瀏覽器的基礎操作建議直接用瀏覽器開發(fā)者工具復制自己電腦上的 UA 字符串別用網(wǎng)上抄的通用值。第二個是 select 選擇器它依賴目標頁面的 DOM 結構不同站點的類名差異很大寫之前先在開發(fā)者工具里確認卡片節(jié)點的實際類名再替換。第三個是 time.sleep(random.uniform(2, 5))固定延時容易被頻率檢測識別隨機延時能顯著降低被封風險。爬蟲的目標是用最少的代碼拿到可用的數(shù)據(jù)不是把頁面全部字段都抓下來。我一般先抓標題、小區(qū)、戶型、面積、朝向、總價和單價這幾個核心字段跑通之后再按需擴展。數(shù)據(jù)量控制在 5000 到 20000 條就夠起步太多的話清洗和訓練都會變得遲鈍。頁面里有房屋 ID 的話務必抓下來這是之后去重的唯一可靠依據(jù)比用標題去重穩(wěn)得多。2.2 數(shù)據(jù)清洗把爬下來的文本變成能建模的結構化表格采集回來的數(shù)據(jù)一定是臟的。常見問題包括價格字段帶「萬」「元/㎡」等混用單位、面積是「89.5㎡」夾著中文符號、戶型寫成「3室2廳1衛(wèi)」或「三室兩廳」不統(tǒng)一、缺失值以空字符串或「暫無」出現(xiàn)、同一房源被多個頁面重復抓取。這些不洗掉后面做特征工程全是錯。import pandas as pd import re def clean_price(price_str): 把 488萬 轉成 488.04880000元 轉成 488.0 if not isinstance(price_str, str): return None if 萬 in price_str: return float(re.search(r([\d.]), price_str).group(1)) match re.search(r([\d.])元, price_str) if match: return float(match.group(1)) / 10000 # 元 - 萬元 return None def clean_area(area_str): 把 89.5㎡ 或 89.5平米 統(tǒng)一轉成 89.5 match re.search(r([\d.]), str(area_str).replace( , )) return float(match.group(1)) if match else None def clean_orientation(raw): 朝向文本歸一化南 北、南北 統(tǒng)一歸入枚舉 raw str(raw).replace( , ) if 南北 in raw: return south-north if 東南 in raw: return southeast if 西南 in raw: return southwest if 南 in raw: return south return raw df pd.DataFrame(raw_items) df[house_id] df[house_id].astype(str) df df.drop_duplicates(subset[house_id]) # 按房源 ID 去重 df[total_price] df[total_price].apply(clean_price) df[unit_price] df[unit_price].apply(clean_price) df[area] df[area_text].apply(clean_area) df[orientation] df[orientation_raw].apply(clean_orientation) # 總價或面積解析失敗的記錄無法參與建模直接刪除 df df.dropna(subset[total_price, area]) # 粗篩異常值統(tǒng)一成萬元后總價低于 10 萬基本是錄入錯誤 df df[(df[total_price] 10) (df[area] 5)]清洗代碼的取舍邏輯比代碼本身更重要。去重必須用 house_id 而不是房源標題因為同標題可能對應不同掛牌批次。clean_price 的核心是把「萬」和「元」統(tǒng)一成「萬元」這是二手房數(shù)據(jù)里最隱蔽的坑——不同板塊、不同頁面顯示的價格單位可能不一致清洗時必須顯式統(tǒng)一否則后面算特征相關性全是錯的。缺失值處理不建議一刀切刪除??們r、面積這種核心字段缺失就刪行朝向、裝修這種可選字段缺失用 unknown 填充。異常值篩選先靠 total_price 10 且 area 5 這種粗暴規(guī)則擋掉明顯錯誤更精細的做法是畫箱線圖把超出上下邊緣 1.5 倍四分位距的記錄單獨拉出來人工確認。清洗完后打印 df.info() 和 df.describe()看每列的缺失情況、數(shù)值范圍和均值是判斷清洗是否到位的快速手段。3. 特征工程與探索性分析把原始字段變成模型吃得下的數(shù)值特征數(shù)據(jù)清洗完只是第一步原始字段還不能直接進模型。朝向是文本、小區(qū)名是高基數(shù) ID、面積和價格之間有復雜關系。這一章先做探索性分析確認數(shù)據(jù)形態(tài)再做特征編碼把文本轉為模型能處理的數(shù)值結構。3.1 先做探索性分析三張圖決定模型方向建模前做 EDA 的價值是用三張圖快速搞清楚房價分布形態(tài)、面積與總價的關系、以及城區(qū)樣本是否均衡。EDA 不是走形式它直接決定后面選模型和特征的方向如果總價分布嚴重右偏線性回歸的誤差會被高價房樣本主導更合理的做法是先對目標變量做 log 變換。import math import matplotlib.pyplot as plt import seaborn as sns # 1. 總價分布右偏明顯就考慮 log1p 變換 fig, axes plt.subplots(1, 2, figsize(12, 4)) sns.histplot(df[total_price], bins60, axaxes[0]) axes[0].set_title(total_price distribution) sns.histplot(df[total_price].apply(math.log1p), bins60, axaxes[1]) axes[1].set_title(log(total_price) distribution) plt.show() # 2. 面積 vs 總價判斷變量關系是否線性 plt.figure(figsize(6, 4)) sns.scatterplot(datadf, xarea, ytotal_price, alpha0.3) plt.axhline(df[total_price].median(), colorred, linestyle--) plt.show() # 3. 城區(qū)均價驗證采集樣本是否覆蓋主要板塊 city_avg df.groupby(district)[unit_price].median().sort_values() city_avg.plot(kindbarh) plt.show()這三張圖對應三種判斷。第一張分布圖告訴你 target 要不要做 log 變換肉眼看到長尾直接選 log1p第二張散點圖看面積與總價的關系如果出現(xiàn)明顯非線性說明后續(xù)可以加面積平方項或者直接交給樹模型自行切分第三張城區(qū)均價圖用來驗證采集數(shù)據(jù)覆蓋度如果某個城區(qū)樣本極少它的統(tǒng)計數(shù)字帶不動模型泛化要么補數(shù)據(jù)要么干脆把那部分樣本從訓練集里拿掉。EDA 過程中要順手復查缺失值的性質。我之前做過一個模擬項目X清洗完發(fā)現(xiàn)朝向字段 35% 缺失但這個字段不影響核心建模后來在特征工程里設了 unknown 分類。最怕的是缺失不是隨機的——比如高價房源更不愛填裝修信息這種結構性缺失直接刪掉等于讓模型在高價區(qū)間失去重要信號。應對方法是對比缺失記錄與正常記錄的目標均值差異差異明顯就要么補全要么顯式生成一個「是否缺失」標志特征。3.2 特征編碼高基數(shù)類別特征別直接 One-Hot特征工程這一步二手房系統(tǒng)里最常用的有兩類低基數(shù)類別特征朝向、裝修、戶型和高基數(shù)類別特征小區(qū)名、行政區(qū)域。前者適合 One-Hot后者按小區(qū)做目標編碼比 One-Hot 更適合因為小區(qū)數(shù)量動輒上千One-Hot 會瞬間把維度撐爆而且絕大多數(shù)小區(qū)樣本極少獨立成列既稀疏又容易過擬合。特征類型推薦做法原因朝向、裝修、戶型One-Hot枚舉少可解釋性強行政區(qū)域目標編碼類別幾十種One-Hot 能做但編碼更穩(wěn)小區(qū)名目標編碼上千類別One-Hot 維度爆炸from sklearn.preprocessing import OneHotEncoder # 低基數(shù)特征One-Hotdrop_first 避免共線性 df pd.get_dummies(df, columns[orientation, decoration], drop_firstTrue) def target_encode(series, target, alpha10): 按類別統(tǒng)計 target 均值并用全局先驗做平滑 global_mean target.mean() grp target.groupby(series).agg([sum, count]) encoded (grp[sum] alpha * global_mean) / (grp[count] alpha) return series.map(encoded) df[community_encoded] target_encode(df[community], df[total_price]) df[log_area] df[area].apply(math.log1p)target_encode 里有兩個硬核參數(shù)。alpha 是平滑系數(shù)它解決的是小樣本類別統(tǒng)計不可靠的問題某個小區(qū)只有 1 條記錄時直接用這條記錄均價編碼會嚴重過擬合alpha 越大編碼值越趨向全局均值。實際項目里 alpha 取 5 到 20做完建議再疊加 K 折外編碼即每一折只用訓練部分統(tǒng)計編碼避免驗證集信息泄漏到特征里。get_dummies 里的 drop_firstTrue 去掉一列冗余避免和截距項共線線性模型里這一步很重要。還有幾個特征容易被忽略但實際很有用樓齡當前年份減建成年份、單價總價除以面積、樓層檔位低/中/高、近地鐵步行距離如果有坐標。這些衍生特征計算成本低對線性模型和樹模型都有實際增益。做完特征工程后跑一遍 df.shape 確認行數(shù)沒變、列數(shù)增加合理再用 df.isna().sum() 確認沒有引入新的缺失值。4. 房價預測模型從線性基線到梯度提升樹的調參路徑特征就緒之后進入建模環(huán)節(jié)。這一章先講為什么必須從線性回歸跑起再給 XGBoost 的完整參數(shù)配置和特征重要性分析方法。目標不是把參數(shù)調到極致而是讓你拿到一套可以復制、可以解釋、可以排查問題的建模流程。4.1 先跑通線性回歸基線模型是排查問題的錨點我一般會先跑線性回歸不為多好的精度而是為了驗證數(shù)據(jù)流程整體貫通。一個能跑的簡單模型配合常規(guī)評估指標能快速暴露數(shù)據(jù)泄露、異常值、單位不統(tǒng)一等問題。如果線性回歸的 MAE 小到離譜那大概率是目標變量被混進了特征別急著高興。from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score feature_cols [c for c in df.columns if c not in (total_price, house_id, title)] X df[feature_cols].select_dtypes(includenumber) y df[total_price] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) model LinearRegression() model.fit(X_train, y_train) y_pred model.predict(X_test) print(MAE:, mean_absolute_error(y_test, y_pred)) print(RMSE:, mean_squared_error(y_test, y_pred, squaredFalse)) print(R2:, r2_score(y_test, y_pred))這里有個細節(jié)feature_cols 先把明顯不該進模型的對象列排除掉再用 select_dtypes(includenumber) 兜底只保留數(shù)值列。標題和房屋 ID 不能進模型前者是文本、后者是高基數(shù) ID直接喂給線性模型會導致維度災難或無意義擬合?;€模型的 MAE 是后續(xù)對比的錨點如果后面把特征工程做扎實樹模型理應比基線明顯下降要是沒下降說明改進方向偏了。評估指標的選擇也有信息量。MAE 適合向業(yè)務方解釋平均預測差多少錢RMSE 對異常值更敏感會放大高價房預測偏離的問題。我會額外看一眼分位數(shù)誤差——只算預測價格最低 10% 和最高 10% 樣本的 MAE如果低總價樣本誤差遠小于高總價樣本說明模型在高價段位擬合不足光調參救不回來要加特征或者對目標變量做 log 變換。4.2 集成模型XGBoost 參數(shù)表與早停策略表格型回歸任務的首選不是深度學習而是梯度提升樹。隨機森林方差小但偏置高XGBoost 通過正則化和梯度提升把偏置打下來是這類項目最穩(wěn)的主模型。我直接用 XGBoost配合早??刂频啍?shù)from xgboost import XGBRegressor xgb XGBRegressor( n_estimators1000, max_depth5, learning_rate0.05, subsample0.8, colsample_bytree0.8, reg_alpha0.1, reg_lambda1.0, random_state42, early_stopping_rounds50, eval_metricmae, ) xgb.fit( X_train, y_train, eval_set[(X_test, y_test)], verboseFalse ) y_pred_xgb xgb.predict(X_test) print(XGBoost MAE:, mean_absolute_error(y_test, y_pred_xgb))關鍵參數(shù)速查表參數(shù)建議值說明max_depth5數(shù)據(jù)特征不多時 4~7 是甜點位越大越容易過擬合learning_rate0.05越小越穩(wěn)但需要更多樹配合早停使用n_estimators1000不直接決定最終輪數(shù)早停會自動截斷subsample / colsample_bytree0.8每棵樹隨機采樣比例噪聲大時可降到 0.7reg_alpha / reg_lambda0.1 / 1.0正則權重特征多時可加大early_stopping_rounds50驗證集連續(xù) 50 輪無改善就停機返回最優(yōu)輪learning_rate 設 0.05 配合 n_estimators1000 靠早停自動收斂比一次性設 100 棵樹效果好一個檔次。subsample 和 colsample_bytree 都設在 0.8給模型加一點隨機性減少方差reg_alpha 對這類噪聲不小的數(shù)據(jù)有實際幫助early_stopping_rounds50 是防止過擬合最省心的招。如果環(huán)境里沒有 XGBoost用 LightGBM 或隨機森林邏輯一樣只是參數(shù)名略有差異。樹模型訓練完我會把特征重要性打出來看一遍import pandas as pd importance pd.DataFrame({ feature: X_train.columns, importance: xgb.feature_importances_ }).sort_values(importance, ascendingFalse) print(importance.head(15))看特征重要性的目的不是挑刺而是找反向信號。如果面積、小區(qū)目標編碼、城區(qū)排在前面說明采集和特征工程做對了如果樓層、朝向這類該有效的特征重要性接近 0可能是編碼方式有問題。特征重要性排序也能幫你砍掉尾部無效特征讓最終模型更穩(wěn)。5. 常見問題與避坑二手房預測系統(tǒng)的 5 個經(jīng)典翻車現(xiàn)場這一章是整套流程里最值錢的部分。以下 5 個問題都是我在實際項目里見過、踩過、幫人排查過的按現(xiàn)象、原因、解決三步記錄。前兩個決定模型評估可信度后三個決定項目能否順利上線。5.1 數(shù)據(jù)泄露模型「太好」往往是壞消息現(xiàn)象訓練集 R2 高達 0.96測試集卻只有 0.5或者兩個集合指標都好得夸張導致你誤以為模型已經(jīng)完美。原因特征里有字段直接或間接包含目標價格的信息。最常見的元兇是小區(qū)均價列和單價字段——單價等于總價除以面積只要面積誤差不大用單價預測總價就是作弊。解決訓練之前人工過一遍特征名把所有名字里帶 price、均價、掛牌價的列全部剔除。再做一次保險驗算用留下的特征訓練決策樹看特征重要性里有沒有哪個特征貢獻異常偏高。我做過一個模擬項目X排查到最后發(fā)現(xiàn)是「近 30 天小區(qū)成交均價」這個特征它幾乎就是目標值的加噪聲版本刪掉之后測試集指標才恢復正常。特征來源審查不需要很復雜把特征列和來源寫進一個 md 文件寫不出來的特征就該懷疑。5.2 隨機切分讓評估結果虛高現(xiàn)象模型在隨機切分的測試集上表現(xiàn)很好但上線后預測新掛牌房源誤差明顯變大業(yè)務方開始質疑模型的可靠性。原因二手房價格帶時間趨勢隨機切分讓訓練集和測試集高度同分布模型相當于偷看了未來數(shù)據(jù)的分布規(guī)律評估結果虛高。解決如果數(shù)據(jù)帶掛牌時間按時間做切分——前 80% 月份訓練、后 20% 月份測試沒有時間字段時用 GroupKFold 按小區(qū)分組交叉驗證避免同一小區(qū)不同房源同時出現(xiàn)在訓練和測試里。注意時間切分的測試集指標通常比隨機切分低一些這是正常的別因此懷疑模型壞了。5.3 高基數(shù)類別字段 One-Hot 維度爆炸現(xiàn)象One-Hot 之后訓練數(shù)據(jù)從 20 列漲到 2000 多列訓練變慢且明顯過擬合模型在驗證集上的表現(xiàn)反而不如簡單模型。原因把小區(qū)名、開發(fā)商這種高基數(shù)類別字段也丟進了 get_dummies。解決小區(qū)名、區(qū)域改目標編碼或頻次編碼只有朝向、裝修、戶型這種枚舉數(shù)小于 10 的字段才 One-Hot。如果業(yè)務上必須保留小區(qū)名先做頻次過濾只保留樣本數(shù)超過一定閾值的小區(qū)剩下的歸為 other 類。5.4 爬蟲采集被識別固定延時是致命傷現(xiàn)象采集到第 50 頁后開始持續(xù)返回 403 或驗證碼頁面導致數(shù)據(jù)中斷。原因請求頭固定、請求間隔固定、訪問節(jié)奏和真實用戶差異明顯。站點風控看的是短時間內的訪問節(jié)奏不是單次請求。解決每次請求之間用 random.uniform(2, 5) 隨機延時請求頭補成真實瀏覽器的完整集合UA、Accept、Accept-Language。血的教訓別為了趕進度把延時壓到 1 秒以內被封一次等解封的時間遠超省下的時間。采集代碼上線前再加一個字段完整性校驗當解析結果為空或字段缺失時自動告警而不是悄悄產(chǎn)出臟數(shù)據(jù)。5.5 價格單位口徑不統(tǒng)一現(xiàn)象整體評估不錯但預測結果偶爾出現(xiàn)離譜價格比如面積 80 平方米、總價預測 0.08 萬元看不出是哪里出了問題。原因同一列里部分記錄是「488 萬」另一部分是「4880000 元」清洗時沒有統(tǒng)一換算模型被迫學習了不一致的目標口徑。解決清洗階段最后一個步驟加斷言檢查總價取值范圍和中位數(shù)是否落在真實量級。把元統(tǒng)一轉成萬元后跑 df[total_price].describe()看 25%、50%、75% 分位數(shù)是否符合常識。做轉換函數(shù)時優(yōu)先用正則提取數(shù)字不要用字符串切片單位字符長度在不同平臺上不可靠。提示這 5 個坑里數(shù)據(jù)泄露和訓練測試切分最容易影響模型評估可信度。建議每次訓練前都做一次特征來源審查再對比訓練集和測試集的關鍵字段分布確認沒有意外的信息泄漏。6. 進階把預測系統(tǒng)從筆記本變成可迭代的服務訓練完模型只是項目的一半另一半是讓它能持續(xù)被調用、持續(xù)被驗證。這一章用一個輕量接口解決模型部署問題再聊定期重訓練和項目文檔的沉淀方式。6.1 模型持久化與最小推理接口訓練結束后下一步是把模型從 Jupyter 里搬出來。用 joblib 保存模型和特征列再用 Flask 寫一個最小接口讓項目從「跑完結果在 notebook 里」變成「能給別人調用的服務」。import joblib from flask import Flask, request, jsonify # 把模型和特征列一起打包特征列順序是推理的關鍵 joblib.dump({model: xgb, feature_cols: feature_cols}, service.joblib) pkg joblib.load(service.joblib) model, feature_cols pkg[model], pkg[feature_cols] app Flask(__name__) app.route(/predict, methods[POST]) def predict(): data request.get_json() features [data.get(col, 0) for col in feature_cols] return jsonify({total_price_pred: float(model.predict([features])[0])}) app.run(host0.0.0.0, port5001)這段代碼里最容易被忽略的是 feature_cols 的一致性。推理時傳入服務的數(shù)據(jù)列順序必須與訓練時完全一致我習慣把特征列名單和模型打包存在同一個文件里推理端只從包里讀列名不手寫特征列表。接口用 POST JSON 比 GET 更穩(wěn)妥參數(shù)多的時候不會被 URL 長度限制卡住也方便調用方傳嵌套結構。6.2 定期重訓練與項目文檔沉淀二手房市場受供需、地段成熟度和基礎設施變化影響模型上線一個月后精度就會開始下降。常見做法是每周拉取一次新掛牌數(shù)據(jù)和舊數(shù)據(jù)合并重新訓練做時間切分驗證。指標沒有明顯下降就繼續(xù)用舊模型有明顯下降就用新模型替換。這個流程里最容易出問題的不是訓練而是新數(shù)據(jù)清洗和特征工程必須完全復用訓練時的代碼——稍有不一致模型在線上的表現(xiàn)就會靜默變差。最后聊項目文檔。完整交付通常包含采集腳本、清洗腳本、特征工程腳本、模型訓練腳本、評估實驗記錄和一份數(shù)據(jù)字典。文檔不用寫長但必須寫清數(shù)據(jù)來源、字段口徑、模型選型理由和調參記錄——不是給領導看是給三個月后的自己看的。我早期做過一個跨平臺數(shù)據(jù)項目調完模型后沒留文檔三周后再去改特征連當時為什么對朝向做四分類都記不清了最后只能重跑一遍實驗。從那以后每個項目我都先建一個數(shù)據(jù)字典文件邊做邊補踩過的坑也順手記進去。希望我的這些經(jīng)驗能幫到你少走一段彎路。本文還有配套的精品資源點擊獲取