南瓜颜色预测:逻辑回归在农业分类问题中的实战应用

发布于:2025-04-15 ⋅ 阅读:(35) ⋅ 点赞:(0)

南瓜颜色预测:逻辑回归在农业分类问题中的实战应用

摘要

本案例通过预测南瓜颜色的分类问题,全面展示了逻辑回归在农业领域的实战应用。从数据预处理到模型评估,详细介绍了Seaborn可视化、模型构建、性能优化和结果解释等关键环节。案例不仅解释了逻辑回归的理论基础和与线性回归的区别,还通过混淆矩阵和ROC曲线分析提供了模型评估的全面视角,为农业和零售领域的决策支持提供了可复制的分析框架。

1. 问题背景与分析目标

在农业和零售领域,预测作物特征对于库存管理、价格预测和供应链优化至关重要。南瓜作为一种季节性强、品种多样的农产品,其特征预测具有重要的商业价值。本案例聚焦于一个关键问题:基于南瓜的产地、尺寸、品种等特征,预测其颜色类别(橙色🎃或白色👻)

这一预测能力可以帮助:

  • 农民优化种植决策
  • 批发商进行库存规划
  • 零售商制定针对性的营销策略
  • 供应链管理者进行产量和需求预测

2. 逻辑回归的理论基础

2.1 逻辑回归与线性回归的区别

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

逻辑回归虽然名称中包含"回归",但实际上是一种强大的分类算法,与线性回归有本质区别:

特点 逻辑回归 线性回归
输出类型 概率值(0-1之间) 连续数值
预测目标 分类标签 连续变量
决策边界 S形曲线(Sigmoid) 直线或超平面
损失函数 对数损失(Log Loss) 均方误差(MSE)
应用场景 疾病诊断、垃圾邮件检测 房价预测、销量预测

2.2 逻辑回归的数学原理

逻辑回归的核心是Sigmoid函数(也称为逻辑函数),它将任何实数映射到(0,1)区间:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数学表达式:
P ( Y = 1 ) = 1 1 + e − ( β 0 + β 1 X 1 + β 2 X 2 + . . . + β n X n ) P(Y=1) = \frac{1}{1 + e^{-(β_0 + β_1X_1 + β_2X_2 + ... + β_nX_n)}} P(Y=1)=1+e(β0+β1X1+β2X2+...+βnXn)1

其中:

  • P ( Y = 1 ) P(Y=1) P(Y=1) 是样本属于正类的概率
  • β 0 , β 1 , . . . , β n β_0, β_1, ..., β_n β0,β1,...,βn 是模型参数
  • X 1 , X 2 , . . . , X n X_1, X_2, ..., X_n X1,X2,...,Xn 是特征变量

决策规则

  • 如果 P ( Y = 1 ) > 0.5 P(Y=1) > 0.5 P(Y=1)>0.5,则预测为类别1(在本例中为橙色南瓜)
  • 如果 P ( Y = 1 ) ≤ 0.5 P(Y=1) \leq 0.5 P(Y=1)0.5,则预测为类别0(在本例中为非橙色南瓜)

2.3 逻辑回归的类型

逻辑回归根据分类问题的性质可分为三种主要类型:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 二元逻辑回归:预测两个互斥类别(如本例中的橙色/非橙色南瓜)
  2. 多项逻辑回归:处理三个或更多无序类别(如橙色/白色/条纹南瓜)
  3. 有序逻辑回归:处理有序类别(如南瓜尺寸:mini/sm/med/lg/xl/xxl)

在本案例中,我们将使用二元逻辑回归,因为我们的目标是区分橙色和非橙色南瓜。

3. 数据准备与探索性分析

3.1 数据加载与清洗

首先,我们需要导入必要的库并加载南瓜数据集:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix, roc_curve, roc_auc_score

# 假设南瓜数据已经加载到pumpkins数据框中
# pumpkins = pd.read_csv('pumpkins.csv')

# 选择相关列并处理缺失值
new_columns = ['Color','Origin','Item Size','Variety','City Name','Package']
new_pumpkins = pumpkins.drop([c for c in pumpkins.columns if c not in new_columns], axis=1)
new_pumpkins.dropna(inplace=True)

# 查看数据的基本信息
print(f"数据集形状: {new_pumpkins.shape}")
print("\n前5行数据:")
print(new_pumpkins.head())

# 检查目标变量分布
color_counts = new_pumpkins['Color'].value_counts()
print("\n颜色分布:")
print(color_counts)

为了机器学习模型的需要,我们将分类变量转换为数值:

# 使用LabelEncoder将分类变量转换为数值
new_pumpkins = new_pumpkins.apply(LabelEncoder().fit_transform)

print("\n转换后的数据:")
print(new_pumpkins.head())

3.2 高级数据可视化

Seaborn库提供了多种强大的可视化方式,帮助我们更好地理解数据特征之间的关系。

3.2.1 特征间关系的全局视图

PairGrid可视化提供了特征之间关系的全景视图:

plt.figure(figsize=(15, 12))
g = sns.PairGrid(new_pumpkins)
g.map_diag(sns.histplot)  # 对角线上显示直方图
g.map_upper(sns.scatterplot)  # 上三角显示散点图
g.map_lower(sns.kdeplot)  # 下三角显示核密度估计图
plt.suptitle('南瓜特征关系全局视图', fontsize=16)
plt.tight_layout()
plt.show()

这种可视化方法可以帮助我们:

  • 识别特征之间的相关性
  • 发现可能的模式和聚类
  • 检测异常值或不寻常的数据分布
3.2.2 颜色类别与其他特征的关系

为了深入理解目标变量(颜色)与其他特征的关系,我们使用更专业的分类数据可视化方法:

plt.figure(figsize=(14, 8))

# 创建一个2x3的子图布局
fig, axes = plt.subplots(2, 3, figsize=(18, 10))
fig.suptitle('南瓜颜色与各特征的关系', fontsize=16)

# 1. 颜色与尺寸的关系 - 小提琴图
sns.violinplot(x="Color", y="Item Size", data=new_pumpkins, ax=axes[0, 0])
axes[0, 0].set_title('颜色与尺寸分布')

# 2. 颜色与产地的关系 - 计数图
sns.countplot(x="Origin", hue="Color", data=new_pumpkins, ax=axes[0, 1])
axes[0, 1].set_title('不同产地的颜色分布')
axes[0, 1].tick_params(axis='x', rotation=45)

# 3. 颜色与品种的关系 - 箱线图
sns.boxplot(x="Color", y="Variety", data=new_pumpkins, ax=axes[0, 2])
axes[0, 2].set_title('颜色与品种关系')

# 4. 颜色与城市的关系 - 分组条形图
top_cities = new_pumpkins['City Name'].value_counts().nlargest(10).index
city_data = new_pumpkins[new_pumpkins['City Name'].isin(top_cities)]
sns.countplot(x="City Name", hue="Color", data=city_data, ax=axes[1, 0])
axes[1, 0].set_title('主要城市的颜色分布')
axes[1, 0].tick_params(axis='x', rotation=90)

# 5. 颜色与包装的关系 - 分类散点图
sns.swarmplot(x="Color", y="Package", data=new_pumpkins, ax=axes[1, 1])
axes[1, 1].set_title('颜色与包装类型')

# 6. 颜色分布 - 饼图
axes[1, 2].pie(color_counts, labels=color_counts.index, autopct='%1.1f%%')
axes[1, 2].set_title('南瓜颜色分布')

plt.tight_layout(rect=[0, 0, 1, 0.96])
plt.show()

这些可视化图表揭示了以下重要见解:

  1. 尺寸与颜色的关系:小提琴图显示,橙色南瓜的尺寸分布似乎更广,而白色南瓜则集中在特定尺寸范围。

  2. 产地影响:某些产地明显更倾向于生产特定颜色的南瓜。

  3. 品种差异:不同品种的南瓜在颜色分布上存在明显差异,这表明品种可能是预测颜色的重要特征。

  4. 区域偏好:某些城市市场可能更偏好特定颜色的南瓜,这反映了区域消费习惯的差异。

3.3 特征相关性分析

为了量化特征之间的关系,我们计算相关性矩阵并通过热图可视化:

plt.figure(figsize=(10, 8))
corr_matrix = new_pumpkins.corr()
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt='.2f', linewidths=0.5)
plt.title('特征相关性热图', fontsize=14)
plt.tight_layout()
plt.show()

这个热图可以帮助我们:

  • 识别与目标变量(颜色)高度相关的特征
  • 发现特征之间的潜在多重共线性问题
  • 指导特征选择决策

4. 逻辑回归模型构建

4.1 特征选择与数据分割

基于前面的数据分析,我们选择最相关的特征并准备训练和测试数据集:

# 选择特征和目标变量
Selected_features = ['Origin', 'Item Size', 'Variety', 'City Name', 'Package']
X = new_pumpkins[Selected_features]
y = new_pumpkins['Color']

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

print(f"训练集形状: {X_train.shape}")
print(f"测试集形状: {X_test.shape}")
print(f"训练集中的目标变量分布: \n{y_train.value_counts(normalize=True)}")
print(f"测试集中的目标变量分布: \n{y_test.value_counts(normalize=True)}")

注意我们使用了stratify=y参数,这确保训练集和测试集中目标变量的比例保持一致,这对处理不平衡数据集特别重要。

4.2 模型训练与预测

现在我们可以训练逻辑回归模型:

# 创建并训练逻辑回归模型
model = LogisticRegression(random_state=42, max_iter=1000, class_weight='balanced')
model.fit(X_train, y_train)

# 在测试集上进行预测
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1]  # 获取属于正类的概率

print("模型训练完成!")

我们使用了以下参数:

  • random_state=42: 确保结果可复现
  • max_iter=1000: 增加最大迭代次数,确保模型收敛
  • class_weight='balanced': 自动调整类权重,处理可能的类别不平衡问题

4.3 模型系数解释

逻辑回归模型的一个主要优势是其可解释性。我们可以分析特征系数,了解各个特征对预测结果的影响:

# 分析模型系数
coef_df = pd.DataFrame({
    'Feature': Selected_features,
    'Coefficient': model.coef_[0],
    'Abs_Coefficient': np.abs(model.coef_[0])
})
coef_df = coef_df.sort_values('Abs_Coefficient', ascending=False)

plt.figure(figsize=(10, 6))
sns.barplot(x='Coefficient', y='Feature', data=coef_df, palette='coolwarm')
plt.title('特征重要性(系数分析)', fontsize=14)
plt.axvline(x=0, color='grey', linestyle='--')
plt.tight_layout()
plt.show()

print("特征系数排名:")
print(coef_df)

这个分析告诉我们:

  • 正系数表示该特征增加时,南瓜是橙色的概率增加
  • 负系数表示该特征增加时,南瓜是橙色的概率减少
  • 系数绝对值越大,表示该特征对预测结果的影响越大

5. 模型评估与解释

5.1 基本性能指标

我们首先查看模型的基本性能指标:

# 计算并打印性能指标
accuracy = accuracy_score(y_test, y_pred)
report = classification_report(y_test, y_pred)

print(f"准确率: {accuracy:.4f}")
print("\n分类报告:")
print(report)

5.2 混淆矩阵分析

混淆矩阵是评估分类模型的强大工具,它展示了预测类别与实际类别的对比:

# 计算并可视化混淆矩阵
cm = confusion_matrix(y_test, y_pred)

plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', 
            xticklabels=['非橙色', '橙色'],
            yticklabels=['非橙色', '橙色'])
plt.xlabel('预测标签')
plt.ylabel('真实标签')
plt.title('混淆矩阵', fontsize=14)
plt.tight_layout()
plt.show()

# 计算更详细的指标
tn, fp, fn, tp = cm.ravel()
sensitivity = tp / (tp + fn)  # 敏感度/召回率
specificity = tn / (tn + fp)  # 特异度
precision = tp / (tp + fp)    # 精确率
f1 = 2 * (precision * sensitivity) / (precision + sensitivity)  # F1分数

print(f"敏感度/召回率: {sensitivity:.4f}")
print(f"特异度: {specificity:.4f}")
print(f"精确率: {precision:.4f}")
print(f"F1分数: {f1:.4f}")

通过混淆矩阵,我们可以全面理解模型的性能:

  • 真阳性(TP): 实际为橙色,预测为橙色
  • 真阴性(TN): 实际为非橙色,预测为非橙色
  • 假阳性(FP): 实际为非橙色,预测为橙色(第一类错误)
  • 假阴性(FN): 实际为橙色,预测为非橙色(第二类错误)

这些指标帮助我们理解模型的优势和局限性,特别是在不同类型错误的成本不同时。

5.3 ROC曲线和AUC分析

接收者操作特征(ROC)曲线是评估二分类模型的标准工具:

# 绘制ROC曲线
fpr, tpr, thresholds = roc_curve(y_test, y_prob)
auc = roc_auc_score(y_test, y_prob)

plt.figure(figsize=(8, 6))
plt.plot(fpr, tpr, color='blue', lw=2, label=f'ROC曲线 (AUC = {auc:.4f})')
plt.plot([0, 1], [0, 1], color='gray', lw=2, linestyle='--', label='随机猜测')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('假阳性率(1 - 特异度)')
plt.ylabel('真阳性率(敏感度)')
plt.title('接收者操作特征曲线', fontsize=14)
plt.legend(loc="lower right")
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

print(f"AUC (曲线下面积): {auc:.4f}")

ROC曲线和AUC值提供了模型性能的综合度量:

  • AUC值范围是0.5(随机猜测)到1.0(完美分类)
  • AUC > 0.7通常被视为可接受的性能
  • AUC > 0.8表示良好的分类性能
  • AUC > 0.9表示优秀的分类性能

在我们的例子中,AUC值约为0.7,表明模型性能优于随机猜测,但仍有改进空间。

6. 模型优化与改进

6.1 交叉验证评估

单次训练/测试分割可能不够稳健,因此我们使用交叉验证来更全面地评估模型性能:

from sklearn.model_selection import cross_val_score, StratifiedKFold

# 执行5折交叉验证
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
cv_scores = cross_val_score(model, X, y, cv=cv, scoring='accuracy')

print(f"交叉验证准确率: {cv_scores}")
print(f"平均准确率: {cv_scores.mean():.4f}, 标准差: {cv_scores.std():.4f}")

6.2 超参数优化

我们可以通过网格搜索找到最佳的模型参数:

from sklearn.model_selection import GridSearchCV

# 定义参数网格
param_grid = {
    'C': [0.001, 0.01, 0.1, 1, 10, 100],
    'penalty': ['l1', 'l2', 'elasticnet', None],
    'solver': ['lbfgs', 'liblinear', 'saga'],
    'class_weight': [None, 'balanced']
}

# 创建网格搜索对象
grid_search = GridSearchCV(
    LogisticRegression(random_state=42, max_iter=2000),
    param_grid,
    cv=5,
    scoring='accuracy',
    n_jobs=-1
)

# 执行网格搜索
grid_search.fit(X_train, y_train)

# 打印最佳参数和得分
print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳交叉验证得分: {grid_search.best_score_:.4f}")

# 使用最佳参数的模型重新评估
best_model = grid_search.best_estimator_
y_pred_best = best_model.predict(X_test)
print(f"优化后模型的准确率: {accuracy_score(y_test, y_pred_best):.4f}")
print("\n优化后的分类报告:")
print(classification_report(y_test, y_pred_best))

6.3 特征工程与选择

特征工程和选择可以显著提高模型性能:

from sklearn.feature_selection import SelectFromModel
from sklearn.preprocessing import PolynomialFeatures

# 1. 添加多项式特征
poly = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
X_poly = poly.fit_transform(X)
X_poly_train, X_poly_test = train_test_split(X_poly, test_size=0.2, random_state=42)

# 重新训练模型
poly_model = LogisticRegression(random_state=42, max_iter=1000)
poly_model.fit(X_poly_train, y_train)
y_pred_poly = poly_model.predict(X_poly_test)

print("使用多项式特征后的性能:")
print(f"准确率: {accuracy_score(y_test, y_pred_poly):.4f}")
print(classification_report(y_test, y_pred_poly))

# 2. 特征选择
selector = SelectFromModel(best_model, prefit=True)
X_selected = selector.transform(X)
print(f"原始特征数: {X.shape[1]}")
print(f"选择后的特征数: {X_selected.shape[1]}")

# 使用选定的特征重新训练
X_selected_train, X_selected_test = train_test_split(X_selected, test_size=0.2, random_state=42)
selected_model = LogisticRegression(random_state=42, max_iter=1000)
selected_model.fit(X_selected_train, y_train)
y_pred_selected = selected_model.predict(X_selected_test)

print("\n使用特征选择后的性能:")
print(f"准确率: {accuracy_score(y_test, y_pred_selected):.4f}")
print(classification_report(y_test, y_pred_selected))

7. 真实世界应用与业务价值

7.1 预测新样本

模型训练完成后,可以用于预测新的未标记样本:

# 示例:预测新样本
new_samples = pd.DataFrame({
    'Origin': [2, 1, 0],
    'Item Size': [3, 2, 1],
    'Variety': [5, 3, 2],
    'City Name': [10, 8, 15],
    'Package': [1, 0, 2]
})

# 使用最优模型预测
predictions = best_model.predict(new_samples)
probabilities = best_model.predict_proba(new_samples)[:, 1]

# 创建可读的结果
results = pd.DataFrame({
    'Sample': range(1, len(new_samples) + 1),
    'Predicted_Color': ['橙色' if p == 1 else '非橙色' for p in predictions],
    'Probability_Orange': probabilities
})

print("新样本预测结果:")
print(results)

7.2 农业应用场景

南瓜颜色预测模型可以在多个农业场景中提供价值:

  1. 种植规划:农民可以根据市场需求和预测的南瓜颜色分布优化种植面积分配。

  2. 库存管理:批发商可以根据预测的颜色分布提前规划仓储和物流安排。

  3. 定价策略:了解特定特征组合下南瓜颜色的概率,可以帮助制定更精准的差异化定价策略。

  4. 营销策略:零售商可以根据预测结果,提前准备针对不同颜色南瓜的营销活动。

7.3 模型部署考虑

将模型部署到生产环境需要考虑以下因素:

import joblib

# 保存模型
joblib.dump(best_model, 'pumpkin_color_predictor.pkl')

# 保存特征转换器(如果有)
joblib.dump(LabelEncoder(), 'label_encoder.pkl')

print("模型和转换器已保存,可用于生产部署")

部署注意事项:

  • 定期使用新数据重新训练模型,以适应市场变化
  • 建立监控系统跟踪模型性能
  • 考虑模型解释性工具,帮助最终用户理解预测结果
  • 开发用户友好的界面,方便非技术人员使用模型

8. 与其他分类算法的比较

为了全面评估逻辑回归的性能,我们可以将其与其他常用分类算法进行比较:

from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score, roc_auc_score
import time

# 定义要比较的模型
models = {
    'Logistic Regression': LogisticRegression(random_state=42),
    'Random Forest': RandomForestClassifier(random_state=42),
    'SVM': SVC(probability=True, random_state=42),
    'KNN': KNeighborsClassifier(),
    'Decision Tree': DecisionTreeClassifier(random_state=42),
    'Naive Bayes': GaussianNB()
}

# 比较结果存储
results = []

# 评估每个模型
for name, model in models.items():
    start_time = time.time()
    model.fit(X_train, y_train)
    train_time = time.time() - start_time
    
    start_time = time.time()
    y_pred = model.predict(X_test)
    predict_time = time.time() - start_time
    
    accuracy = accuracy_score(y_test, y_pred)
    
    if hasattr(model, "predict_proba"):
        y_prob = model.predict_proba(X_test)[:, 1]
        auc = roc_auc_score(y_test, y_prob)
    else:
        auc = None
    
    results.append({
        'Model': name,
        'Accuracy': accuracy,
        'AUC': auc,
        'Training Time (s)': train_time,
        'Prediction Time (s)': predict_time
    })

# 创建比较表格
results_df = pd.DataFrame(results).sort_values('Accuracy', ascending=False)
print("不同分类算法性能比较:")
print(results_df)

# 可视化比较
plt.figure(figsize=(12, 6))

# 准确率比较
plt.subplot(1, 2, 1)
sns.barplot(x='Accuracy', y='Model', data=results_df, palette='viridis')
plt.title('不同模型的准确率比较')
plt.xlim(0, 1)

# AUC比较
plt.subplot(1, 2, 2)
auc_df = results_df.dropna(subset=['AUC'])
sns.barplot(x='AUC', y='Model', data=auc_df, palette='viridis')
plt.title('不同模型的AUC比较')
plt.xlim(0.5, 1)

plt.tight_layout()
plt.show()

这个比较可以帮助我们理解:

  • 逻辑回归在此问题上的性能与其他更复杂的算法相比如何
  • 模型训练和预测的计算效率
  • 不同算法在准确率和AUC方面的权衡

9. 结论与下一步

9.1 模型总结

通过本案例研究,我们已经:

  1. 深入理解了逻辑回归的原理和应用
  2. 使用Seaborn进行了高级数据可视化
  3. 建立了预测南瓜颜色的分类模型
  4. 评估并优化了模型性能
  5. 讨论了模型的实际应用价值

9.2 局限性

我们的模型存在一些局限性:

  • 数据集规模相对较小
  • 某些类别可能存在不平衡
  • 可能存在未捕获的季节性或年度趋势

9.3 未来工作方向

下一步可能的改进包括:

  • 收集更多样本,特别是少数类别
  • 探索更多特征工程技术
  • 尝试更复杂的模型,如集成方法
  • 考虑时间序列因素,捕捉季节性模式

10. 学习资源与挑战

10.1 推荐阅读

10.2 实践挑战

  1. 尝试使用PCA或其他降维技术来改进模型
  2. 实现一个交互式应用,允许用户输入南瓜特征并获得颜色预测
  3. 扩展模型以预测其他南瓜特征,如价格或质量等级

通过这个实战案例,你不仅学习了逻辑回归的技术细节,还了解了如何将机器学习应用于实际农业问题,为业务决策提供数据驱动的支持。


网站公告

今日签到

点亮在社区的每一天
去签到