数学建模竞赛

使用 MATLAB 进行数据分析和数学建模,包括数据预处理、统计分析、多元线性回归等

项目简介

数模是一时兴起打算去打的,以前也算是有过数据分析的经验吧,打过泰迪杯啥的,但是其实数据处理当时是用 Python,这次用的是 MATLAB,发现 MATLAB 是真好用,但是从几乎是零开始也挺难的,不过面对 ChatGPT 编程就好多了,三天比赛也算是学了很多。

主要工作

1. 数据预处理

将附件二导入 MATLAB,获取销售流水明细数据,以获取每个商品的销售记录,检查数据是否包含缺失值、异常值,并进行必要的数据清洗和处理,以确保数据的质量。

%导入附件2
data = readtable('数值化.xlsx');

% 获取列名
column_names = data.Properties.VariableNames;

% 使用 renamevars 函数将列名更改为原列名
data = renamevars(data, {'x____','x______','x_____1','x_______1','x__________','x_____2','x_______2','x___'},
                  {'销售日期','扫码销售时间','单品编码','销量(千克)','销售单价(元/千克)','销售类型','是否打折销售','销售额'});

%导入附件1
data1 = readtable('附件1.xlsx');
data1 = renamevars(data1, {'x____', 'x_____1','x_____2','x_____3'},
                   {'单品编码','单品名称','分类编码','分类名称'});

%data2用于储存单品编码与单品名称的映射
data1 = data1(:, {'单品编码', '单品名称','分类名称'});

%将单品名称映射进data中
data2 = join(data, data1, 'Keys', '单品编码');

%将单品名称移到开头
data2 = data2(:, {'单品名称','销售日期','分类名称','扫码销售时间','单品编码','销量(千克)','销售单价(元/千克)','是否打折销售','销售额','销售类型'});

sales = data2.('销量(千克)');

%删除销量为负值的数据,退货不在考虑范围
valid_rows = sales >= 0;
data2 = data2(valid_rows, :);

writetable(data2, '12合并去负值.xlsx');

2. 合并品类、单品

summaryTable = groupsummary(data2, '分类名称', 'sum', '销量(千克)');
pinglei = summaryTable(:, {'分类名称', 'sum_销量(千克)'});
pinglei = renamevars(pinglei, {'分类名称', 'sum_销量(千克)'}, {'pinleimingcheng', 'Total_Sales_KG'});
writetable(pinglei, '品类与销量.xlsx');

summaryTable = groupsummary(data2, '单品名称', 'sum', '销量(千克)');
danpin = summaryTable(:, {'单品名称', 'sum_销量(千克)'});
danpin = renamevars(danpin, {'单品名称', 'sum_销量(千克)'}, {'danpinmingcheng', 'Total_Sales_KG'});
writetable(danpin, '单品与销量.xlsx');

3. 数据可视化

折线图

x = 1:length(pinglei.pinleimingcheng);
plot(x, pinglei.Total_Sales_KG, '-o', 'LineWidth', 2, 'MarkerSize', 8);
xticks(x);
xticklabels(pinglei.pinleimingcheng);
title('商品销售量');
xlabel('商品品类');
ylabel('销售量 (千克)');
legend('销售量');
set(gcf, 'Position', [100, 100, 800, 400]);

箱线图

%绘制销量的箱线图,发现销量带负值,为退货,有160kg销售鲜粽叶的特殊值
sales = data2.('销量(千克)');
boxplot(sales);
title('销量(千克)的箱线图');
ylabel('销量(千克)');

%绘制销售单价的箱线图
sales1 = data2.('销售单价(元/千克)');
boxplot(sales1);
title('销售单价(元/千克)的箱线图');
ylabel('销售单价(元/千克)');

4. 异常值识别

使用 IQR(四分位距)方法识别异常值:

outliers = false(size(data3));  % 创建与数据表格相同大小的逻辑数组

for col = 2:size(data3, 2)  % 从第二列开始(第一列通常是标签)
    column_data = data3{:, col};  % 获取当前列数据
    Q1 = quantile(column_data, 0.25);  % 计算下四分位数
    Q3 = quantile(column_data, 0.75);  % 计算上四分位数
    IQR = Q3 - Q1;  % 计算IQR

    k = 1.5;  % 调整异常值的阈值
    lower_threshold = Q1 - k * IQR;  % 下界阈值
    upper_threshold = Q3 + k * IQR;  % 上界阈值

    % 识别异常值
    outliers(:, col) = column_data < lower_threshold | column_data > upper_threshold;
end

5. 相关性分析

计算斯皮尔曼相关系数、绘制热力图:

% 按品类每日汇总销售量
category_sales = varfun(@sum, data2, 'GroupingVariables', {'time','sortname'},'InputVariables', 'xiaoliang');
% 按单品每日汇总销售量
category_sales1 = varfun(@sum, data2, 'GroupingVariables', {'time','danpingname'},'InputVariables', 'xiaoliang');

% 计算相关性
correlation_matrix = corr(table2array(category_sales));

6. 时间序列分析

分析单品在时间上的分布规律:

sortname = category_sales.sortname;
time = category_sales.time;
sum_xiaoliang = category_sales.sum_xiaoliang;

unique_sortnames = unique(sortname);

figure;
hold on;

% 遍历每个不同的sortname值,绘制不同的线段
for i = 1:length(unique_sortnames)
    current_sortname = unique_sortnames{i};
    mask = strcmp(sortname, current_sortname);
    plot(time(mask), sum_xiaoliang(mask), 'DisplayName', current_sortname);
end

title('不同品类的销售量折线图');
xlabel('时间');
ylabel('销量');
legend('Location', 'best');
hold off;

7. 多元线性回归

% 合并数据
data3 = readtable('附件3.xlsx');
data3 = renamevars(data3, {'x__', 'x____','x__________'}, {'time','singlema','pifajia'});
mergedData = join(data2, data3, 'Keys',{'time','singlema'});

% 进行多元线性回归分析
% ...

8. 利润计算

%首先计算出收益
data.shouyi = (data.xiaoliang .* data.danjia) - (data.xiaoliang .* data.pifajia ./ (1 - data.sunhao ./100));

%通过时间与单品名称聚类,计算每日单品收益和
category_sales = varfun(@sum, data, 'GroupingVariables', {'time','danpingname'},'InputVariables', 'shouyi');
%通过时间与单品名称聚类,计算每日单品销量和
category_sales1 = varfun(@sum, data, 'GroupingVariables', {'time','danpingname'},'InputVariables', 'xiaoliang');
%合并
mergedData = join(category_sales1, category_sales, 'Keys',{'time','danpingname'});

技术栈

  • MATLAB: 主要开发工具
  • 数据分析: 数据清洗、预处理、统计分析
  • 数据可视化: 折线图、箱线图、热力图
  • 统计方法: IQR 异常值检测、相关性分析、多元线性回归

项目总结

通过这次数学建模竞赛,我深入学习了:

  • MATLAB 数据处理和分析
  • 数据清洗和预处理技术
  • 统计分析方法
  • 数据可视化
  • 多元线性回归模型
  • 时间序列分析

虽然是从零开始学习 MATLAB,但通过 ChatGPT 辅助编程和三天的高强度学习,最终完成了比赛并获得了宝贵的经验。