收入预测一直是金融、人力资源和社会学研究领域的重要课题。传统方法往往依赖复杂的统计模型或人工经验判断,而机器学习为我们提供了一种更高效、更客观的解决方案。这个项目将展示如何利用Python生态中的数据科学工具,构建一个基于朴素贝叶斯分类器的收入预测模型。
我在银行信贷部门工作时,曾亲眼见证过不准确的收入预测如何导致信贷决策失误。这促使我深入研究各种预测方法,最终发现朴素贝叶斯算法在特定场景下展现出惊人的效果。虽然这个算法"朴素"的假设条件看似简单,但在处理分类问题时往往能取得出人意料的好成绩。
朴素贝叶斯分类器基于贝叶斯定理,其"朴素"之处在于假设所有特征之间相互独立。虽然这个假设在现实中很少完全成立,但实践证明在很多场景下这个简化依然有效。
算法公式表示为:
P(y|X) = P(X|y) * P(y) / P(X)
其中:
对于收入预测这种混合了连续变量(如年龄、工作时长)和分类变量(教育程度、职业)的问题,我们通常需要对不同特征采用不同的处理方法。
本项目使用UCI机器学习库中的Adult数据集,包含48,842条记录,14个特征变量,目标变量是二元分类(收入是否超过50K美元)。
python复制import pandas as pd
from sklearn.model_selection import train_test_split
# 加载数据
url = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data"
columns = ['age', 'workclass', 'fnlwgt', 'education', 'education-num',
'marital-status', 'occupation', 'relationship', 'race',
'sex', 'capital-gain', 'capital-loss', 'hours-per-week', 'native-country', 'income']
data = pd.read_csv(url, names=columns, na_values=" ?", skipinitialspace=True)
特别注意:income列需要转换为二元数值标签(0表示<=50K,1表示>50K)
python复制from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
# 定义预处理管道
numeric_features = ['age', 'education-num', 'capital-gain', 'capital-loss', 'hours-per-week']
categorical_features = ['workclass', 'education', 'marital-status', 'occupation',
'relationship', 'race', 'sex', 'native-country']
preprocessor = ColumnTransformer(
transformers=[
('num', StandardScaler(), numeric_features),
('cat', Pipeline([
('encoder', LabelEncoder()), # 简单起见使用LabelEncoder
]), categorical_features)
])
# 应用预处理
X = data.drop('income', axis=1)
y = LabelEncoder().fit_transform(data['income'])
X_processed = preprocessor.fit_transform(X)
python复制from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import cross_val_score
# 创建并评估基础模型
model = GaussianNB()
scores = cross_val_score(model, X_processed, y, cv=5, scoring='accuracy')
print(f"平均准确率: {scores.mean():.4f} (±{scores.std():.4f})")
由于我们的数据包含连续和离散特征,可以考虑混合使用高斯和多项式朴素贝叶斯:
python复制from sklearn.naive_bayes import GaussianNB, MultinomialNB
from sklearn.ensemble import VotingClassifier
# 创建混合模型
gaussian_nb = GaussianNB()
multinomial_nb = MultinomialNB()
# 投票集成
ensemble = VotingClassifier(
estimators=[('gaussian', gaussian_nb), ('multinomial', multinomial_nb)],
voting='soft')
虽然朴素贝叶斯参数较少,但仍有优化空间:
python复制from sklearn.model_selection import GridSearchCV
params = {
'var_smoothing': [1e-9, 1e-8, 1e-7, 1e-6, 1e-5]
}
grid_search = GridSearchCV(GaussianNB(), param_grid=params, cv=5, scoring='accuracy')
grid_search.fit(X_train, y_train)
print(f"最佳参数: {grid_search.best_params_}")
对于收入预测这种不平衡分类问题(收入>50K的样本较少),不能仅看准确率:
python复制from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred))
print(f"ROC AUC: {roc_auc_score(y_test, y_pred_proba[:, 1]):.4f}")
虽然朴素贝叶斯没有内置的特征重要性,但可以通过以下方法评估:
将模型预测转化为可理解的业务规则:
python复制# 获取各类别的先验概率
class_prior = model.class_prior_
# 获取特定特征的类条件概率
# 例如:不同教育程度对收入的影响
education_idx = preprocessor.named_transformers_['cat'].named_steps['encoder'].transform(['Bachelors'])[0]
education_probs = model.theta_[1][education_idx] # 收入>50K类别的教育特征条件概率
python复制import joblib
# 保存整个管道(包含预处理和模型)
joblib.dump({
'preprocessor': preprocessor,
'model': model
}, 'income_predictor.pkl')
使用Flask创建预测服务:
python复制from flask import Flask, request, jsonify
import joblib
app = Flask(__name__)
model_data = joblib.load('income_predictor.pkl')
@app.route('/predict', methods=['POST'])
def predict():
data = request.json
processed = model_data['preprocessor'].transform([data])
proba = model_data['model'].predict_proba(processed)[0]
return jsonify({
'probability_over_50k': float(proba[1]),
'prediction': int(proba[1] > 0.5)
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
生产环境中需要监控:
当收入>50K的样本远少于<=50K时:
朴素贝叶斯假设特征独立,但现实中常有相关性:
对于不符合高斯分布的连续变量:
在实际应用中,我发现虽然深度学习等复杂模型在某些场景下表现更好,但朴素贝叶斯凭借其训练速度快、内存占用小、解释性强的特点,仍然是很多业务场景的首选方案。特别是在需要快速原型验证或资源受限的环境中,这个"朴素"的算法往往能带来惊喜。