当前位置: 首页 > news >正文

用Python+Matplotlib复现数学建模A题:从数据清洗到箱线图可视化的保姆级教程

Python+Matplotlib实战:数学建模A题数据清洗与箱线图可视化全流程解析

数学建模竞赛中,数据处理与可视化是核心技能。本文将以2023年深圳杯A题为例,手把手教你用Python完整复现获奖论文的数据分析流程。不同于简单的代码翻译,我们将深入探讨如何用Pandas优雅地处理复杂条件判断,用Matplotlib绘制专业级箱线图,并分享实际项目中的优化技巧。

1. 环境准备与数据加载

工欲善其事,必先利其器。我们需要配置适合科学计算的Python环境:

# 推荐使用conda创建虚拟环境 conda create -n math_modeling python=3.9 conda activate math_modeling pip install pandas numpy matplotlib scipy scikit-learn jupyter

数据集通常以Excel格式提供,Pandas提供了多种读取方式:

import pandas as pd # 读取Excel数据,跳过前两行非数据内容 raw_data = pd.read_excel('慢性病及相关因素流调数据.xlsx', header=None, skiprows=2)

处理缺失值是数据清洗的第一步。与MATLAB不同,Python中更推荐使用fillna方法:

# 统一用0填充缺失值 cleaned_data = raw_data.fillna(0) # 检查处理结果 print(f"原始数据缺失值数量: {raw_data.isnull().sum().sum()}") print(f"处理后缺失值数量: {cleaned_data.isnull().sum().sum()}")

2. 得分计算逻辑实现

原题要求根据复杂条件计算五个维度的得分。我们将每个评分规则封装为独立函数,提高代码可维护性:

2.1 食物多样性得分计算

def calculate_food_diversity(df): """ 计算准则一:食物多样,合理搭配 参数: df: 清洗后的DataFrame 返回: 得分Series """ scores = [] for _, row in df.iterrows(): score = 0 # 条件1:主食、蔬菜、蛋白质来源同时存在 cond1 = ((row[53]>0 or row[58]>0 or row[63]>0 or row[68]>0) and (row[143]>0 or row[173]>0) and (row[78]>0 or row[83]>0 or row[88]>0 or row[93]>0 or row[98]>0 or row[103]>0 or row[108]>0 or row[113]>0)) # 条件2:食物种类丰富度 a_columns = [53,58,63,68,73,78,83,88,93,98,103,108,113,118, 123,128,133,138,143,148,153,158,163,168,173,178,183] b_columns = [c+1 for c in a_columns] # B组为A组对应列+1 a_sum = sum(row[a] for a in a_columns if row[a]>0) c_sum = sum(1 for a in a_columns if row[a]>0 or row[b]>0) cond2 = (a_sum > 12) and (c_sum > 25) and cond1 # 计算最终得分 total_conditions = 2 met_conditions = sum([cond1, cond2]) scores.append(met_conditions / total_conditions) return pd.Series(scores, name='食物多样性得分')

2.2 BMI与运动得分计算

def calculate_bmi_activity(df): """ 计算准则二:吃动平衡,健康体重 包含BMI和运动量两个指标 """ scores = [] for _, row in df.iterrows(): score = 0 # BMI计算 (身高单位:cm→m) height_m = row[221] * 0.01 bmi = row[222] / (height_m ** 2) if 18.5 <= bmi <= 24: score += 1 # 运动量检查 if row[197] != 0 and row[198] * 7 > 150: score += 1 scores.append(score / 2) # 总分为满足条件数/总条件数 return pd.Series(scores, name='BMI运动得分')

3. 数据可视化:专业箱线图绘制

Matplotlib的箱线图功能强大,但默认样式较为简单。我们可以通过以下方式提升可视化效果:

3.1 基础箱线图绘制

import matplotlib.pyplot as plt import numpy as np # 准备数据 scores = pd.DataFrame({ '食物多样': food_scores, '吃动平衡': bmi_scores, '蔬果摄入': veg_scores, '蛋白质摄入': protein_scores, '少盐少油': salt_scores }) fig, ax = plt.subplots(figsize=(12, 6)) boxprops = dict(linewidth=2, color='darkblue') whiskerprops = dict(linewidth=1.5, linestyle='--') medianprops = dict(linewidth=2.5, color='firebrick') scores.boxplot(ax=ax, boxprops=boxprops, whiskerprops=whiskerprops, medianprops=medianprops, patch_artist=True) ax.set_title('居民饮食习惯各维度得分分布', fontsize=14) ax.set_ylabel('得分', fontsize=12) ax.grid(True, linestyle=':', alpha=0.7)

3.2 高级美化技巧

要使图表达到发表水平,还需要更多细节调整:

# 自定义颜色和样式 colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8'] # 重新绘制以应用自定义样式 plt.figure(figsize=(14, 7)) bp = plt.boxplot(scores.values, labels=scores.columns, patch_artist=True) # 设置箱体颜色 for patch, color in zip(bp['boxes'], colors): patch.set_facecolor(color) patch.set_alpha(0.6) # 设置其他元素样式 for element in ['whiskers', 'caps', 'medians', 'fliers']: plt.setp(bp[element], color='gray', linewidth=1.5) # 添加数据点(抖动散点图) for i, col in enumerate(scores.columns): y = scores[col] x = np.random.normal(i+1, 0.04, size=len(y)) plt.scatter(x, y, alpha=0.4, color=colors[i], s=30) # 添加参考线和注释 plt.axhline(y=0.8, color='r', linestyle='--', alpha=0.3) plt.text(5.5, 0.82, '优秀阈值', color='r') # 最终美化 plt.xticks(fontsize=12) plt.yticks(fontsize=11) plt.title('居民饮食习惯评估 - 五维度箱线图分析', fontsize=16, pad=20) plt.ylabel('标准化得分', fontsize=13, labelpad=10) plt.grid(axis='y', alpha=0.2) plt.tight_layout()

4. 分析结果解读与优化建议

通过可视化分析,我们可以得出以下关键发现:

  1. 食物多样性得分普遍较低(中位数约0.4),表明大部分居民饮食结构单一
  2. BMI指标表现最好(中位数0.75),显示居民体重管理意识较强
  3. 盐油控制得分两极分化严重,部分居民完全不符合标准

针对这些发现,可以提出以下数据优化建议:

  • 异常值处理:对极端低分样本进行个案分析
  • 数据分箱:按年龄、职业等分组比较
  • 动态可视化:添加交互式控件探索不同群体表现
# 示例:按年龄分组分析 age_bins = [0, 30, 45, 60, 100] age_labels = ['<30', '30-45', '45-60', '>60'] scores['age_group'] = pd.cut(raw_data[220], bins=age_bins, labels=age_labels) # 分组绘制箱线图 plt.figure(figsize=(15, 8)) scores.boxplot(column='食物多样', by='age_group', patch_artist=True) plt.title('不同年龄组食物多样性得分比较', fontsize=14) plt.suptitle('') # 去除自动生成的标题 plt.xlabel('年龄组', fontsize=12) plt.ylabel('得分', fontsize=12)

在实际数学建模竞赛中,这种深入的数据分析和专业的可视化呈现往往能显著提升论文质量。记得保存高分辨率图片用于报告:

plt.savefig('diet_score_analysis.png', dpi=300, bbox_inches='tight')
http://www.cnnetsun.cn/news/2649121.html

相关文章:

  • 如何实现多显示器DPI感知鼠标平滑移动:LittleBigMouse智能分辨率重载技术详解
  • 别再踩坑了!Spring中@Async注解失效的3个隐蔽场景(附自测清单)
  • 天赐范式第57天:迟来的晚饭加料——实锤不是鹤——是过来串门的东方白鹳——都是CFD的好模型——月亮爬出来前一起烩了——背景图片那叫一个——绝
  • 奇迹MU:剑与翼官网下载|独家发育技巧免费高阶资源全指南
  • Windows 11开始菜单终极修复指南:三步快速恢复消失的磁贴
  • 从Matlab到边缘设备:手把手教你将训练好的U-Net模型导出为ONNX并在OpenCV DNN中部署
  • 从‘网格终止’到‘冗余版本’:深入解读LTE Turbo码里那些容易被忽略的设计细节
  • 告别ALOS!土木/水利学生如何用大疆御系列+RTK+两步路APP,搞定小区域高精度DEM
  • Keil µVision配置恢复与优化指南
  • 别再死记硬背了!一张图搞懂CRC16的7种标准(CCITT、MODBUS、X25等)区别与应用场景
  • 告别手动改配置!CentOS 7网络管理三剑客:nmtui、nmcli与配置文件实战对比
  • 别再傻傻分不清!用SteamDB快速识别你玩的游戏是Unity还是虚幻引擎
  • 电机控制周报
  • 别再手动K帧了!用UE5的ControlRig给角色头部加个“方向盘”,5分钟搞定转头动画
  • 你的电机调速稳吗?STM32 PWM控制直流电机时,ULN2003A外围电路设计与常见问题排查
  • C16x平台内存对齐问题解析与解决方案
  • 两轮自平衡车摆机器人建模与控制方法解析【附仿真】
  • 3分钟搞定:m4s-converter让你的B站缓存视频重获新生
  • C++复习
  • 告别截图模糊:用Nvidia Ansel在UE4里捕获超清8K全景游戏画面的完整流程
  • EDEM中按outlet接触自动删颗粒并实时统计移除总质量
  • 二维雷达场景下机动目标EKF跟踪MATLAB实现(含轨迹对比与误差统计图)
  • 论文查重总踩坑?书匠策AI这个免费功能,我真后悔没早知道!
  • 别再硬扛内存了!手把手教你用Signac在服务器上搞定TF motif富集分析(附避坑指南)
  • RK3568多屏配置踩坑实录:为什么我的uboot启动失败了?
  • 别再硬编码了!用Shader Graph从零构建一个可交互的Unity URP水面(附完整节点图)
  • 告别WinForm:在麒麟V10SP1上,用Avalonia MVVM模式构建现代化C#桌面程序
  • Windows认证和安全对象的基本概念
  • 【避坑指南】架构设计中的十大常见错误
  • 别再手动解密了!.NET 6 集成微信支付V3回调,用Senparc SDK和OSS.PayCenter两种方式搞定Native支付通知