MATLAB学习文档(二十二)
目录
10.5表格相关练习题
30 个地区一年的存取款数据分析
步骤1: 创建模拟数据
步骤2: 创建表格并添加变量名
步骤3: 计算每个地区的年总存款和总取款
步骤4: 计算净存款额(存款-取款)
步骤5: 数据分析
5.1 找出存款最多的地区
5.2 找出取款最多的地区
5.3 找出净存款额最高的地区
步骤6: 数据可视化
步骤7: 月度趋势分析
过程
12个地区的高考招生数据整理
步骤1: 创建模拟数据
步骤2: 创建嵌套表格结构
步骤3: 数据整理和分析
3.1 计算每个地区的总招生计划、总报名人数和总录取人数
3.2 计算每所高校在各地区的平均数据
步骤4: 数据可视化
4.1 各地区总报名人数和总录取人数对比
4.2 各地区平均录取率
4.3 各高校平均最低分数
步骤5: 导出数据到Excel
过程
将24个月的招聘数据汇总到同一表格
步骤1: 创建模拟数据
步骤2: 生成24个月的模拟数据
步骤3: 将24个月的数据汇总到同一表格
步骤4: 数据分析
4.1 按月份统计招聘数量
4.2 按职位名称统计招聘数量
4.3 按工作地点统计招聘数量
4.4 按学历要求统计招聘数量
步骤5: 数据可视化
5.1 月度招聘趋势
5.2 各职位招聘数量
5.3 各城市招聘数量
5.4 学历要求分布
步骤6: 薪资分析
步骤7: 导出汇总数据
过程
共享单车数据预处理
步骤1: 创建模拟的共享单车数据
步骤2: 数据预处理
2.1 检查缺失值
2.2 处理异常值
2.3 处理重复值
2.4 数据转换
2.5 添加骑行速度列(公里/小时)
步骤3: 数据质量评估
3.1 统计数据预处理后的基本情况
3.2 检查骑行速度是否合理
步骤4: 数据分析和可视化
4.1 骑行时长分布
4.2 骑行距离分布
4.3 每小时使用量
4.4 工作日vs周末使用量
步骤5: 热点分析
5.1 统计每个站点的出发和到达次数
5.2 可视化热门站点
5.3 分析站点间的流量
步骤6: 导出预处理后的数据
过程
57个分拣中心的小时货量数据整理
步骤1: 创建模拟数据
步骤2: 创建表格并添加变量名
步骤3: 数据整理
3.1 计算每个分拣中心的日总货量
3.2 计算每个分拣中心的平均小时货量
3.3 找出每个分拣中心的峰值小时和峰值货量
3.4 计算每个分拣中心的货量变异系数(标准差/均值)
步骤4: 按小时汇总所有分拣中心的货量
步骤5: 数据分析和可视化
5.1 找出货量最大的分拣中心
5.2 找出峰值货量最大的分拣中心
5.3 找出货量最稳定的分拣中心(变异系数最小)
5.4 找出货量波动最大的分拣中心(变异系数最大)
步骤6: 数据可视化
6.1 所有分拣中心的日内货量变化
6.2 日总货量TOP10的分拣中心
6.3 小时总货量变化趋势
6.4 分拣中心聚类分析(基于日内货量模式)
步骤7: 导出数据
过程
蔬菜商品表格的联接
步骤1: 创建模拟数据
1.1 创建蔬菜基本信息表
1.2 创建蔬菜价格表
1.3 创建蔬菜销量表
步骤2: 表格联接
2.1 将基本信息表与价格表联接
2.2 将上述结果与销量表联接
步骤3: 数据处理和分析
3.1 计算销售额
3.2 按类别汇总
3.3 按产地汇总
3.4 按蔬菜汇总
3.5 按日期汇总
步骤6: 导出数据
过程
同步空气质量时间表
步骤1: 创建模拟数据
1.1 创建监测站信息
1.2 创建空气质量监测数据
步骤2: 同步时间表
2.1 创建完整的时间戳序列(所有监测站的时间戳并集)
2.2 为每个监测站创建同步后的数据
2.3 合并所有监测站的数据
步骤3: 缺失值处理
3.1 统计缺失值情况
3.2 使用线性插值处理缺失值
3.3 再次统计缺失值情况
步骤4: 计算空气质量指数(AQI)
4.1 定义各指标的浓度限值和对应的IAQI计算函数
4.2 定义计算IAQI的函数
4.3 计算各指标的IAQI
4.4 计算AQI(取各指标IAQI的最大值)
4.5 确定首要污染物
4.6 确定空气质量等级
步骤5: 数据分析和可视化
5.1 按监测站统计AQI平均值
5.2 按空气质量等级统计记录数
5.3 按首要污染物统计记录数
5.4 按小时统计平均AQI
5.5 可视化
步骤6: 导出数据
过程
步骤4: 数据可视化
4.1 各类别蔬菜的总销售额
4.2 不同产地蔬菜的平均价格
4.3 销量TOP10的蔬菜
4.4 每日总销售额变化趋势
4.5 价格与销量的散点图
步骤5: 高级分析
5.1 计算价格弹性
5.2 可视化价格弹性
10.5表格相关练习题
30 个地区一年的存取款数据分析
步骤1: 创建模拟数据
% 假设我们有30个地区,12个月的存取款数据regions = string(arrayfun(@(x) sprintf('地区%d', x), 1:30, 'UniformOutput', false));months = string(arrayfun(@(x) sprintf('%d月', x), 1:12, 'UniformOutput', false));% 生成随机存取款数据(单位:万元)deposit_data = randi([1000, 5000], 30, 12); % 存款数据withdrawal_data = randi([500, 3000], 30, 12); % 取款数据
步骤2: 创建表格并添加变量名
deposit_table = array2table(deposit_data, 'VariableNames', months);deposit_table.Properties.DimensionNames{1} = '地区';deposit_table.地区 = regions;withdrawal_table = array2table(withdrawal_data, 'VariableNames', months);withdrawal_table.Properties.DimensionNames{1} = '地区';withdrawal_table.地区 = regions;
步骤3: 计算每个地区的年总存款和总取款
deposit_table.年总存款 = sum(deposit_table{:, 2:13}, 2);withdrawal_table.年总取款 = sum(withdrawal_table{:, 2:13}, 2);
步骤4: 计算净存款额(存款-取款)
net_deposit = table();net_deposit.地区 = regions;net_deposit.年总存款 = deposit_table.年总存款;net_deposit.年总取款 = withdrawal_table.年总取款;net_deposit.净存款额 = net_deposit.年总存款 - net_deposit.年总取款;
步骤5: 数据分析
5.1 找出存款最多的地区
[max_deposit, max_idx] = max(net_deposit.年总存款);fprintf('存款最多的地区是%s,存款总额为%.2f万元\n', net_deposit.地区{max_idx}, max_deposit);
5.2 找出取款最多的地区
[max_withdrawal, max_w_idx] = max(net_deposit.年总取款);fprintf('取款最多的地区是%s,取款总额为%.2f万元\n', net_deposit.地区{max_w_idx}, max_withdrawal);
5.3 找出净存款额最高的地区
[max_net, max_net_idx] = max(net_deposit.净存款额);fprintf('净存款额最高的地区是%s,净存款额为%.2f万元\n', net_deposit.地区{max_net_idx}, max_net);
步骤6: 数据可视化
figure;subplot(2,1,1);bar(net_deposit.年总存款);title('各地区年总存款');xlabel('地区');ylabel('存款额(万元)');xticks(1:30);xticklabels(net_deposit.地区);xtickangle(45);subplot(2,1,2);bar(net_deposit.年总取款);title('各地区年总取款');xlabel('地区');ylabel('取款额(万元)');xticks(1:30);xticklabels(net_deposit.地区);xtickangle(45);
步骤7: 月度趋势分析
monthly_deposit = sum(deposit_table{:, 2:13}, 1);monthly_withdrawal = sum(withdrawal_table{:, 2:13}, 1);figure;plot(1:12, monthly_deposit, '-o', 'LineWidth', 2);hold on;plot(1:12, monthly_withdrawal, '-s', 'LineWidth', 2);title('月度存取款趋势');xlabel('月份');ylabel('金额(万元)');legend('总存款', '总取款');grid on;xticks(1:12);xticklabels(months);xtickangle(45);
过程
- 首先创建了30个地区和12个月的标签,然后生成了随机的存取款数据
- 将数据转换为表格格式,便于后续处理和分析
- 计算了每个地区的年总存款和总取款,并计算净存款额
- 进行了基本的数据分析,找出存款最多、取款最多和净存款额最高的地区
- 通过条形图可视化各地区的存取款情况
- 通过折线图展示了月度存取款趋势,便于观察季节性变化
12个地区的高考招生数据整理
步骤1: 创建模拟数据
% 假设有12个地区,每个地区有5所高校的招生数据regions = string(arrayfun(@(x) sprintf('地区%d', x), 1:12, 'UniformOutput', false));universities = string(arrayfun(@(x) sprintf('高校%d', x), 1:5, 'UniformOutput', false));% 生成随机招生数据% 招生计划数、报名人数、实际录取人数、最低录取分数plan_data = randi([100, 500], 12, 5); % 招生计划数apply_data = randi([200, 1000], 12, 5); % 报名人数admit_data = randi([100, 500], 12, 5); % 实际录取人数score_data = randi([400, 700], 12, 5); % 最低录取分数
步骤2: 创建嵌套表格结构
% 创建一个主表格,每个地区一行admission_table = table();admission_table.地区 = regions;% 为每个地区创建一个包含高校数据的子表格for i = 1:12% 创建子表格sub_table = table();sub_table.高校 = universities';sub_table.招生计划 = plan_data(i,:)';sub_table.报名人数 = apply_data(i,:)';sub_table.实际录取 = admit_data(i,:)';sub_table.最低分数 = score_data(i,:)';% 计算录取率和报录比sub_table.录取率 = sub_table.实际录取 ./ sub_table.报名人数 * 100;sub_table.报录比 = sub_table.报名人数 ./ sub_table.招生计划;% 将子表格添加到主表格admission_table.高校数据{i} = sub_table;end
步骤3: 数据整理和分析
3.1 计算每个地区的总招生计划、总报名人数和总录取人数
region_summary = table();region_summary.地区 = regions;region_summary.总招生计划 = sum(plan_data, 2);region_summary.总报名人数 = sum(apply_data, 2);region_summary.总录取人数 = sum(admit_data, 2);region_summary.平均录取率 = region_summary.总录取人数 ./ region_summary.总报名人数 * 100;region_summary.平均报录比 = region_summary.总报名人数 ./ region_summary.总招生计划;
3.2 计算每所高校在各地区的平均数据
university_summary = table();university_summary.高校 = universities';university_summary.平均招生计划 = mean(plan_data, 1)';university_summary.平均报名人数 = mean(apply_data, 1)';university_summary.平均录取人数 = mean(admit_data, 1)';university_summary.平均最低分数 = mean(score_data, 1)';university_summary.平均录取率 = mean(admit_data ./ apply_data * 100, 1)';university_summary.平均报录比 = mean(apply_data ./ plan_data, 1)';
步骤4: 数据可视化
4.1 各地区总报名人数和总录取人数对比
figure;bar([region_summary.总报名人数, region_summary.总录取人数]);title('各地区总报名人数与总录取人数对比');xlabel('地区');ylabel('人数');legend('报名人数', '录取人数');xticks(1:12);xticklabels(region_summary.地区);xtickangle(45);
4.2 各地区平均录取率
figure;bar(region_summary.平均录取率);title('各地区平均录取率');xlabel('地区');ylabel('录取率(%)');xticks(1:12);xticklabels(region_summary.地区);xtickangle(45);
4.3 各高校平均最低分数
figure;bar(university_summary.平均最低分数);title('各高校平均最低录取分数');xlabel('高校');ylabel('分数');xticks(1:5);xticklabels(university_summary.高校);xtickangle(45);
步骤5: 导出数据到Excel
% writetable(admission_table, '高考招生数据.xlsx');% writetable(region_summary, '地区招生汇总.xlsx');% writetable(university_summary, '高校招生汇总.xlsx');
过程
- 创建了12个地区和5所高校的模拟招生数据,包括招生计划、报名人数、实际录取人数和最低录取分数
- 使用嵌套表格结构组织数据,主表格包含地区信息,每个地区对应一个包含高校数据的子表格
- 计算了录取率和报录比等关键指标
- 生成了两个汇总表格:一个按地区汇总,一个按高校汇总
- 通过条形图可视化各地区报名与录取人数对比、各地区平均录取率以及各高校平均最低分数
将24个月的招聘数据汇总到同一表格
步骤1: 创建模拟数据
% 假设我们有24个月的招聘数据,每个月份是一个单独的表格% 每个表格包含: 职位名称、公司名称、薪资范围、工作地点、学历要求、工作经验要求% 创建24个月份标签months = string(arrayfun(@(x) sprintf('%d年%d月', 2021+floor((x-1)/12), mod(x-1,12)+1), 1:24, 'UniformOutput', false));% 定义可能的职位类别job_titles = ["软件工程师", "数据分析师", "产品经理", "市场营销", "人力资源", "财务会计", "销售代表", "客户服务"];companies = ["公司A", "公司B", "公司C", "公司D", "公司E", "公司F", "公司G", "公司H"];locations = ["北京", "上海", "广州", "深圳", "杭州", "成都", "武汉", "西安"];education = ["本科", "硕士", "博士", "大专", "不限"];experience = ["应届生", "1-3年", "3-5年", "5-10年", "10年以上"];
步骤2: 生成24个月的模拟数据
monthly_data = cell(24, 1); % 使用cell数组存储每个月的表格for m = 1:24% 每个月随机生成50-100条招聘记录num_records = randi([50, 100]);% 随机生成数据jobs = job_titles(randi(length(job_titles), num_records, 1));comps = companies(randi(length(companies), num_records, 1));locs = locations(randi(length(locations), num_records, 1));edu = education(randi(length(education), num_records, 1));exp = experience(randi(length(experience), num_records, 1));% 生成薪资范围(单位:千元/月)min_salary = randi([5, 20], num_records, 1);max_salary = min_salary + randi([5, 15], num_records, 1);salary = arrayfun(@(x,y) sprintf('%d-%d', x, y), min_salary, max_salary, 'UniformOutput', false);% 创建表格monthly_table = table();monthly_table.职位名称 = jobs;monthly_table.公司名称 = comps;monthly_table.薪资范围 = salary;monthly_table.工作地点 = locs;monthly_table.学历要求 = edu;monthly_table.工作经验 = exp;% 存储到cell数组monthly_data{m} = monthly_table;end
步骤3: 将24个月的数据汇总到同一表格
% 添加月份列并合并所有表格for m = 1:24monthly_data{m}.月份 = repmat(months(m), height(monthly_data{m}), 1);end% 使用vertcat垂直合并所有表格combined_data = vertcat(monthly_data{:});
步骤4: 数据分析
4.1 按月份统计招聘数量
monthly_count = groupcounts(combined_data, '月份');
4.2 按职位名称统计招聘数量
job_count = groupcounts(combined_data, '职位名称');
4.3 按工作地点统计招聘数量
location_count = groupcounts(combined_data, '工作地点');
4.4 按学历要求统计招聘数量
education_count = groupcounts(combined_data, '学历要求');
步骤5: 数据可视化
5.1 月度招聘趋势
figure;plot(1:24, monthly_count.Percent, '-o', 'LineWidth', 2);title('24个月招聘数量趋势');xlabel('月份');ylabel('招聘数量');grid on;xticks(1:24);xticklabels(months);xtickangle(45);
5.2 各职位招聘数量
figure;pie(job_count.Percent, job_count.职位名称);title('各职位招聘数量占比');
5.3 各城市招聘数量
figure;barh(location_count.Percent);title('各城市招聘数量');xlabel('招聘数量');ylabel('城市');yticks(1:length(location_count.工作地点));yticklabels(location_count.工作地点);
5.4 学历要求分布
figure;pie(education_count.Percent, education_count.学历要求);title('学历要求分布');
步骤6: 薪资分析
% 从薪资范围中提取最低薪资和最高薪资min_sal = zeros(height(combined_data), 1);max_sal = zeros(height(combined_data), 1);for i = 1:height(combined_data)salary_str = combined_data.薪资范围{i};parts = strsplit(salary_str, '-');min_sal(i) = str2double(parts{1});max_sal(i) = str2double(parts{2});end% 添加到表格combined_data.最低薪资 = min_sal;combined_data.最高薪资 = max_sal;combined_data.平均薪资 = (min_sal + max_sal) / 2;% 按职位分析薪资job_salary = groupsummary(combined_data, '职位名称', {'mean', 'min', 'max'}, '平均薪资');% 可视化各职位平均薪资figure;bar(job_salary.平均薪资);title('各职位平均薪资');xlabel('职位');ylabel('平均薪资(千元/月)');xticks(1:length(job_salary.职位名称));xticklabels(job_salary.职位名称);xtickangle(45);
步骤7: 导出汇总数据
% writetable(combined_data, '24个月招聘数据汇总.xlsx');
过程
- 创建了24个月的模拟招聘数据,包括职位名称、公司名称、薪资范围、工作地点、学历要求和工作经验
- 使用cell数组存储每个月的表格,然后通过添加月份列并使用vertcat函数将所有数据合并到一个表格中
- 进行了多维度分析:按月份、职位名称、工作地点和学历要求统计招聘数量
- 通过多种图表可视化数据:折线图展示月度趋势,饼图展示职位和学历分布,水平条形图展示城市分布
- 对薪资数据进行了特殊处理,从字符串中提取数值并计算平均薪资
- 按职位分析了薪资情况,并通过条形图展示各职位的平均薪资
共享单车数据预处理
步骤1: 创建模拟的共享单车数据
% 假设数据包含: 单车ID、开始时间、结束时间、开始位置、结束位置、骑行时长、骑行距离% 创建可能的单车IDbike_ids = string(arrayfun(@(x) sprintf('B%04d', x), 1:100, 'UniformOutput', false));% 创建位置点(假设有20个固定站点)locations = string(arrayfun(@(x) sprintf('站点%d', x), 1:20, 'UniformOutput', false));% 生成1000条随机骑行记录num_records = 1000;bike_data = table();% 随机分配单车IDbike_data.单车ID = bike_ids(randi(length(bike_ids), num_records, 1));% 生成开始和结束时间(假设数据来自2023年1月)start_dates = datetime(2023, 1, 1) + hours(randi(0, 23, num_records, 1)) + minutes(randi(0, 59, num_records, 1));ride_durations = minutes(randi(5, 120, num_records, 1)); % 骑行时长5-120分钟end_dates = start_dates + ride_durations;bike_data.开始时间 = start_dates;bike_data.结束时间 = end_dates;% 随机分配开始和结束位置bike_data.开始位置 = locations(randi(length(locations), num_records, 1));bike_data.结束位置 = locations(randi(length(locations), num_records, 1));% 计算骑行时长(分钟)bike_data.骑行时长 = minutes(bike_data.结束时间 - bike_data.开始时间);% 生成骑行距离(公里)bike_data.骑行距离 = 0.2 + rand(num_records, 1) * 4.8; % 0.2-5公里
步骤2: 数据预处理
2.1 检查缺失值
missing_values = ismissing(bike_data);fprintf('缺失值统计:\n');for i = 1:width(bike_data)fprintf('%s: %d\n', bike_data.Properties.VariableNames{i}, sum(missing_values(:, i)));end
2.2 处理异常值
% 检查骑行时长是否异常(假设超过3小时为异常)abnormal_duration = bike_data.骑行时长 > 180;fprintf('\n骑行时长异常记录数: %d\n', sum(abnormal_duration));% 检查骑行距离是否异常(假设超过10公里为异常)abnormal_distance = bike_data.骑行距离 > 10;fprintf('骑行距离异常记录数: %d\n', sum(abnormal_distance));% 标记异常记录bike_data.异常记录 = abnormal_duration | abnormal_distance;
2.3 处理重复值
% 检查是否有完全相同的记录[~, unique_idx] = unique(bike_data(:, 1:6), 'rows');duplicates = setdiff(1:height(bike_data), unique_idx);fprintf('\n重复记录数: %d\n', length(duplicates));% 删除重复记录bike_data = bike_data(unique_idx, :);
2.4 数据转换
% 添加日期、星期几和小时列,便于后续分析bike_data.日期 = date(bike_data.开始时间);bike_data.星期几 = weekday(bike_data.开始时间);bike_data.小时 = hour(bike_data.开始时间);% 将星期几转换为文本weekdays = ["日", "一", "二", "三", "四", "五", "六"];bike_data.星期几文本 = string(arrayfun(@(x) weekdays(x), bike_data.星期几, 'UniformOutput', false));% 添加是否周末列bike_data.是否周末 = bike_data.星期几 == 1 | bike_data.星期几 == 7;
2.5 添加骑行速度列(公里/小时)
bike_data.骑行速度 = bike_data.骑行距离 ./ (bike_data.骑行时长 / 60);
步骤3: 数据质量评估
3.1 统计数据预处理后的基本情况
fprintf('\n数据预处理后基本情况:\n');fprintf('总记录数: %d\n', height(bike_data));fprintf('异常记录数: %d\n', sum(bike_data.异常记录));fprintf('正常记录数: %d\n', sum(~bike_data.异常记录));
3.2 检查骑行速度是否合理
abnormal_speed = bike_data.骑行速度 > 25 | bike_data.骑行速度 < 3; % 假设速度超过25km/h或低于3km/h为异常fprintf('骑行速度异常记录数: %d\n', sum(abnormal_speed));% 更新异常记录标记bike_data.异常记录 = bike_data.异常记录 | abnormal_speed;
步骤4: 数据分析和可视化
4.1 骑行时长分布
figure;subplot(2,2,1);histogram(bike_data.骑行时长(~bike_data.异常记录), 20);title('骑行时长分布(正常数据)');xlabel('时长(分钟)');ylabel('频次');
4.2 骑行距离分布
subplot(2,2,2);histogram(bike_data.骑行距离(~bike_data.异常记录), 20);title('骑行距离分布(正常数据)');xlabel('距离(公里)');ylabel('频次');
4.3 每小时使用量
hourly_usage = groupcounts(bike_data(~bike_data.异常记录, :), '小时');subplot(2,2,3);bar(hourly_usage.小时, hourly_usage.Percent);title('每小时使用量');xlabel('小时');ylabel('使用次数');xticks(0:23);
4.4 工作日vs周末使用量
weekday_weekend = groupcounts(bike_data(~bike_data.异常记录, :), '是否周末');subplot(2,2,4);pie(weekday_weekend.Percent, ["工作日", "周末"]);title('工作日vs周末使用量');
步骤5: 热点分析
5.1 统计每个站点的出发和到达次数
start_counts = groupcounts(bike_data(~bike_data.异常记录, :), '开始位置');end_counts = groupcounts(bike_data(~bike_data.异常记录, :), '结束位置');% 合并统计结果location_stats = outerjoin(start_counts, end_counts, 'Keys', '开始位置', 'MergeKeys', true);location_stats.Properties.VariableNames{1} = '站点';location_stats.Properties.VariableNames{2} = '出发次数';location_stats.Properties.VariableNames{3} = '到达次数';% 填充缺失值location_stats.出发次数(ismissing(location_stats.出发次数)) = 0;location_stats.到达次数(ismissing(location_stats.到达次数)) = 0;% 计算总使用次数location_stats.总使用次数 = location_stats.出发次数 + location_stats.到达次数;% 按总使用次数排序location_stats = sortrows(location_stats, '总使用次数', 'descend');5.2 可视化热门站点
figure;subplot(2,1,1);barh(location_stats.总使用次数(1:10));title('热门站点TOP10');xlabel('使用次数');ylabel('站点');yticks(1:10);yticklabels(location_stats.站点(1:10));
5.3 分析站点间的流量
% 创建站点间的流量矩阵flow_matrix = zeros(length(locations), length(locations));for i = 1:height(bike_data(~bike_data.异常_record, :))if ~bike_data.异常记录(i)start_loc = bike_data.开始位置{i};end_loc = bike_data.结束位置{i};start_idx = find(strcmp(locations, start_loc));end_idx = find(strcmp(locations, end_loc));if ~isempty(start_idx) && ~isempty(end_idx)flow_matrix(start_idx, end_idx) = flow_matrix(start_idx, end_idx) + 1;endendend% 找出流量最大的前10条路线[flow_values, flow_indices] = sort(flow_matrix(:), 'descend');top_flows = flow_values(1:10);% 获取对应的站点对[top_i, top_j] = ind2sub(size(flow_matrix), flow_indices(1:10));top_routes = arrayfun(@(x,y) sprintf('%s -> %s', locations{x}, locations{y}), top_i, top_j, 'UniformOutput', false);% 可视化热门路线subplot(2,1,2);barh(top_flows);title('热门路线TOP10');xlabel('流量');ylabel('路线');yticks(1:10);yticklabels(top_routes);
步骤6: 导出预处理后的数据
% writetable(bike_data, '共享单车预处理数据.xlsx');% writetable(location_stats, '站点使用统计.xlsx');
过程
- 创建了模拟的共享单车数据,包括单车ID、开始时间、结束时间、开始位置、结束位置、骑行时长和骑行距离
- 进行了全面的数据预处理:
- 检查并统计缺失值
- 识别并标记异常值(如过长的骑行时间或过长的骑行距离)
- 删除重复记录
- 进行数据转换,添加日期、星期几、小时和是否周末等列
- 计算骑行速度并检查是否合理
- 评估了数据质量,统计了异常记录和正常记录的数量
- 通过多种图表进行数据分析和可视化:
- 骑行时长和距离的分布直方图
- 每小时使用量的条形图
- 工作日vs周末使用量的饼图
- 进行了热点分析:
- 统计每个站点的出发和到达次数,找出热门站点
- 分析站点间的流量,找出热门路线
57个分拣中心的小时货量数据整理
步骤1: 创建模拟数据
% 假设有57个分拣中心,记录24小时的货量数据% 创建分拣中心IDcenters = string(arrayfun(@(x) sprintf('C%03d', x), 1:57, 'UniformOutput', false));% 创建小时标签(0-23时)hours = 0:23;% 生成57个分拣中心24小时的货量数据% 考虑到分拣中心的货量通常有日内变化模式,我们使用正弦函数加随机噪声生成数据base_volume = 1000; % 基础货量amplitude = 500; % 波动幅度peak_hour = 14; % 峰值小时(下午2点)% 创建货量数据矩阵volume_data = zeros(57, 24);for i = 1:57% 每个分拣中心的基础货量和波动幅度略有不同center_base = base_volume + randi([-200, 200]);center_amplitude = amplitude + randi([-100, 100]);center_peak = peak_hour + randi([-2, 2]); % 峰值时间略有不同% 生成日内变化模式for h = 1:24% 使用正弦函数模拟日内变化,并添加随机噪声hour_factor = sin(pi * (h-1-center_peak+12)/12);volume_data(i, h) = max(0, center_base + center_amplitude * hour_factor + randn * 50);endend
步骤2: 创建表格并添加变量名
volume_table = array2table(volume_data, 'VariableNames', string(hours));volume_table.Properties.DimensionNames{1} = '分拣中心';volume_table.分拣中心 = centers;
步骤3: 数据整理
3.1 计算每个分拣中心的日总货量
volume_table.日总货量 = sum(volume_table{:, 2:25}, 2);
3.2 计算每个分拣中心的平均小时货量
volume_table.平均小时货量 = mean(volume_table{:, 2:25}, 2);
3.3 找出每个分拣中心的峰值小时和峰值货量
[peak_volumes, peak_hours] = max(volume_data, [], 2);volume_table.峰值小时 = peak_hours - 1; % 转换为0-23小时volume_table.峰值货量 = peak_volumes;
3.4 计算每个分拣中心的货量变异系数(标准差/均值)
hourly_volumes = volume_table{:, 2:25};volume_table.变异系数 = std(hourly_volumes, 0, 2) ./ mean(hourly_volumes, 2);
步骤4: 按小时汇总所有分拣中心的货量
hourly_summary = table();hourly_summary.小时 = hours';hourly_summary.总货量 = sum(volume_data, 1)';hourly_summary.平均货量 = mean(volume_data, 1)';hourly_summary.最大货量 = max(volume_data, [], 1)';hourly_summary.最小货量 = min(volume_data, [], 1)';
步骤5: 数据分析和可视化
5.1 找出货量最大的分拣中心
[max_daily, max_center_idx] = max(volume_table.日总货量);fprintf('日总货量最大的分拣中心是%s,货量为%.2f\n', volume_table.分拣中心{max_center_idx}, max_daily);
5.2 找出峰值货量最大的分拣中心
[max_peak, max_peak_idx] = max(volume_table.峰值货量);fprintf('峰值货量最大的分拣中心是%s,峰值货量为%.2f\n', volume_table.分拣中心{max_peak_idx}, max_peak);
5.3 找出货量最稳定的分拣中心(变异系数最小)
[min_cv, min_cv_idx] = min(volume_table.变异系数);fprintf('货量最稳定的分拣中心是%s,变异系数为%.4f\n', volume_table.分拣中心{min_cv_idx}, min_cv);
5.4 找出货量波动最大的分拣中心(变异系数最大)
[max_cv, max_cv_idx] = max(volume_table.变异系数);fprintf('货量波动最大的分拣中心是%s,变异系数为%.4f\n', volume_table.分拣中心{max_cv_idx}, max_cv);
步骤6: 数据可视化
6.1 所有分拣中心的日内货量变化
figure;plot(hours, volume_data', 'LineWidth', 1);hold on;plot(hours, hourly_summary.平均货量, 'k-', 'LineWidth', 3);title('所有分拣中心的日内货量变化');xlabel('小时');ylabel('货量');legend('平均货量', 'Location', 'best');grid on;xticks(hours);
6.2 日总货量TOP10的分拣中心
sorted_centers = sortrows(volume_table, '日总货量', 'descend');top10_centers = sorted_centers(1:10, :);figure;bar(top10_centers.日总货量);title('日总货量TOP10的分拣中心');xlabel('分拣中心');ylabel('日总货量');xticks(1:10);xticklabels(top10_centers.分拣中心);xtickangle(45);
6.3 小时总货量变化趋势
figure;plot(hours, hourly_summary.总货量, '-o', 'LineWidth', 2);hold on;plot(hours, hourly_summary.平均货量, '-s', 'LineWidth', 2);plot(hours, hourly_summary.最大货量, '-^', 'LineWidth', 1);plot(hours, hourly_summary.最小货量, '-v', 'LineWidth', 1);title('小时货量变化趋势');xlabel('小时');ylabel('货量');legend('总货量', '平均货量', '最大货量', '最小货量', 'Location', 'best');grid on;xticks(hours);
6.4 分拣中心聚类分析(基于日内货量模式)
% 使用K-means聚类将分拣中心分为5类num_clusters = 5;[idx, centroids] = kmeans(volume_data, num_clusters);% 将聚类结果添加到表格volume_table.聚类类别 = idx;% 可视化聚类结果figure;for c = 1:num_clusterssubplot(num_clusters, 1, c);cluster_centers = volume_data(idx == c, :);plot(hours, cluster_centers', 'LineWidth', 1);hold on;plot(hours, centroids(c, :), 'k-', 'LineWidth', 3);title(sprintf('类别%d (%d个分拣中心)', c, sum(idx == c)));xlabel('小时');ylabel('货量');grid on;xticks(hours);end
步骤7: 导出数据
% writetable(volume_table, '分拣中心货量数据.xlsx');% writetable(hourly_summary, '小时货量汇总.xlsx');
过程
- 创建了57个分拣中心24小时的模拟货量数据,使用正弦函数模拟日内变化模式,并添加随机噪声
- 将数据转换为表格格式,便于后续处理和分析
- 进行了数据整理,计算了每个分拣中心的日总货量、平均小时货量、峰值小时和峰值货量
- 计算了货量变异系数,用于衡量货量波动程度
- 按小时汇总了所有分拣中心的货量数据
- 进行了数据分析,找出了货量最大、峰值最大、最稳定和波动最大的分拣中心
- 通过多种图表进行数据可视化:
- 所有分拣中心的日内货量变化曲线
- 日总货量TOP10的分拣中心条形图
- 小时货量变化趋势图
- 使用K-means聚类分析将分拣中心按日内货量模式分为5类,并可视化各类别的货量模式
蔬菜商品表格的联接
步骤1: 创建模拟数据
假设我们有三个表格:蔬菜基本信息表、蔬菜价格表和蔬菜销量表
1.1 创建蔬菜基本信息表
vegetable_names = ["白菜", "菠菜", "芹菜", "生菜", "油菜", ..."西红柿", "黄瓜", "茄子", "辣椒", "豆角", ..."土豆", "萝卜", "胡萝卜", "洋葱", "大蒜", ..."南瓜", "冬瓜", "丝瓜", "苦瓜", "西葫芦"];categories = ["叶菜类", "叶菜类", "叶菜类", "叶菜类", "叶菜类", ..."茄果类", "瓜菜类", "茄果类", "茄果类", "豆类", ..."根茎类", "根茎类", "根茎类", "根茎类", "根茎类", ..."瓜菜类", "瓜菜类", "瓜菜类", "瓜菜类", "瓜菜类"];origins = ["本地", "外地", "本地", "本地", "本地", ..."本地", "本地", "外地", "本地", "本地", ..."本地", "本地", "外地", "外地", "本地", ..."本地", "本地", "本地", "本地", "本地"];% 创建基本信息表basic_info = table();basic_info.蔬菜ID = string(arrayfun(@(x) sprintf('V%03d', x), 1:20, 'UniformOutput', false));basic_info.蔬菜名称 = vegetable_names';basic_info.类别 = categories';basic_info.产地 = origins';
1.2 创建蔬菜价格表
% 假设有30天的价格数据dates = datetime(2023, 6, 1) + caldays(0:29);% 生成随机价格数据(单位:元/公斤)price_data = table();price_rows = [];for d = 1:30for v = 1:20price_rows = [price_rows; {dates(d), basic_info.蔬菜ID{v}, basic_info.蔬菜名称{v}, ...2 + rand() * 8}]; % 价格在2-10元/公斤之间endendprice_data = cell2table(price_rows, 'VariableNames', {'日期', '蔬菜ID', '蔬菜名称', '价格'});
1.3 创建蔬菜销量表
% 生成随机销量数据(单位:公斤)sales_data = table();sales_rows = [];for d = 1:30for v = 1:20% 销量与价格有一定负相关关系base_sales = 500;price_factor = 1000 ./ price_data{(d-1)*20+v, '价格'}; % 价格越高,销量越低random_factor = 0.8 + rand() * 0.4; % 随机波动因子sales = base_sales * price_factor * random_factor;sales_rows = [sales_rows; {dates(d), basic_info.蔬菜ID{v}, basic_info.蔬菜名称{v}, sales}];endendsales_data = cell2table(sales_rows, 'VariableNames', {'日期', '蔬菜ID', '蔬菜名称', '销量'});
步骤2: 表格联接
2.1 将基本信息表与价格表联接
basic_price = outerjoin(basic_info, price_data, 'Keys', '蔬菜ID', 'MergeKeys', true);basic_price.Properties.VariableNames{1} = '蔬菜ID';basic_price.Properties.VariableNames{2} = '蔬菜名称_basic';basic_price.Properties.VariableNames{3} = '类别';basic_price.Properties.VariableNames{4} = '产地';basic_price.Properties.VariableNames{5} = '日期';basic_price.Properties.VariableNames{6} = '蔬菜名称_price';basic_price.Properties.VariableNames{7} = '价格';% 删除重复的蔬菜名称列basic_price.蔬菜名称_price = [];
2.2 将上述结果与销量表联接
full_data = outerjoin(basic_price, sales_data, 'Keys', {'蔬菜ID', '日期'}, 'MergeKeys', true);full_data.Properties.VariableNames{1} = '蔬菜ID';full_data.Properties.VariableNames{2} = '蔬菜名称';full_data.Properties.VariableNames{3} = '类别';full_data.Properties.VariableNames{4} = '产地';full_data.Properties.VariableNames{5} = '日期';full_data.Properties.VariableNames{6} = '价格';full_data.Properties.VariableNames{7} = '蔬菜名称_sales';full_data.Properties.VariableNames{8} = '销量';% 删除重复的蔬菜名称列full_data.蔬菜名称_sales = [];
步骤3: 数据处理和分析
3.1 计算销售额
full_data.销售额 = full_data.价格 .* full_data.销量;
3.2 按类别汇总
category_summary = groupsummary(full_data, '类别', {'mean', 'sum'}, {'价格', '销量', '销售额'});category_summary.Properties.VariableNames{1} = '类别';category_summary.Properties.VariableNames{2} = '组数';category_summary.Properties.VariableNames{3} = '平均价格';category_summary.Properties.VariableNames{4} = '总销量';category_summary.Properties.VariableNames{5} = '总销售额';
3.3 按产地汇总
origin_summary = groupsummary(full_data, '产地', {'mean', 'sum'}, {'价格', '销量', '销售额'});origin_summary.Properties.VariableNames{1} = '产地';origin_summary.Properties.VariableNames{2} = '组数';origin_summary.Properties.VariableNames{3} = '平均价格';origin_summary.Properties.VariableNames{4} = '总销量';origin_summary.Properties.VariableNames{5} = '总销售额';
3.4 按蔬菜汇总
vegetable_summary = groupsummary(full_data, '蔬菜名称', {'mean', 'sum'}, {'价格', '销量', '销售额'});vegetable_summary.Properties.VariableNames{1} = '蔬菜名称';vegetable_summary.Properties.VariableNames{2} = '组数';vegetable_summary.Properties.VariableNames{3} = '平均价格';vegetable_summary.Properties.VariableNames{4} = '总销量';vegetable_summary.Properties.VariableNames{5} = '总销售额';
3.5 按日期汇总
date_summary = groupsummary(full_data, '日期', {'mean', 'sum'}, {'价格', '销量', '销售额'});date_summary.Properties.VariableNames{1} = '日期';date_summary.Properties.VariableNames{2} = '组数';date_summary.Properties.VariableNames{3} = '平均价格';date_summary.Properties.VariableNames{4} = '总销量';date_summary.Properties.VariableNames{5} = '总销售额';
步骤4: 数据可视化
4.1 各类别蔬菜的总销售额
figure;pie(category_summary.总销售额, category_summary.类别);title('各类别蔬菜的总销售额');
4.2 不同产地蔬菜的平均价格
figure;bar(origin_summary.平均价格);title('不同产地蔬菜的平均价格');xlabel('产地');ylabel('平均价格(元/公斤)');xticks(1:2);xticklabels(origin_summary.产地);
4.3 销量TOP10的蔬菜
sorted_vegetables = sortrows(vegetable_summary, '总销量', 'descend');top10_vegetables = sorted_vegetables(1:10, :);figure;barh(top10_vegetables.总销量);title('销量TOP10的蔬菜');xlabel('总销量(公斤)');ylabel('蔬菜');yticks(1:10);yticklabels(top10_vegetables.蔬菜名称);
4.4 每日总销售额变化趋势
figure;plot(date_summary.日期, date_summary.总销售额, '-o', 'LineWidth', 2);title('每日总销售额变化趋势');xlabel('日期');ylabel('总销售额(元)');grid on;xtickangle(45);
4.5 价格与销量的散点图
figure;scatter(full_data.价格, full_data.销量, 'filled');title('价格与销量的关系');xlabel('价格(元/公斤)');ylabel('销量(公斤)');grid on;% 计算相关系数price_sales_corr = corr(full_data.价格, full_data.销量);fprintf('价格与销量的相关系数: %.4f\n', price_sales_corr);
步骤5: 高级分析
5.1 计算价格弹性
% 价格弹性 = 销量变化百分比 / 价格变化百分比% 我们按蔬菜计算价格弹性price_elasticity = table();price_elasticity.蔬菜名称 = vegetable_names';for v = 1:20% 获取单个蔬菜的数据veg_data = full_data(strcmp(full_data.蔬菜名称, vegetable_names{v}), :);% 按价格排序veg_data = sortrows(veg_data, '价格');% 计算价格和销量的对数log_price = log(veg_data.价格);log_sales = log(veg_data.销量);% 使用线性回归计算弹性X = [ones(size(log_price)), log_price];b = X \ log_sales;elasticity = b(2); % 弹性系数price_elasticity.价格弹性(v) = elasticity;end
5.2 可视化价格弹性
sorted_elasticity = sortrows(price_elasticity, '价格弹性');figure;barh(sorted_elasticity.价格弹性);title('各蔬菜的价格弹性');xlabel('价格弹性');ylabel('蔬菜');yticks(1:20);yticklabels(sorted_elasticity.蔬菜名称);grid on;% 添加参考线xline(0, 'r-', 'LineWidth', 2);text(-1.5, 10, '缺乏弹性', 'Color', 'r');text(0.5, 10, '富有弹性', 'Color', 'r');
步骤6: 导出数据
% writetable(full_data, '蔬菜商品完整数据.xlsx');% writetable(category_summary, '类别汇总.xlsx');% writetable(origin_summary, '产地汇总.xlsx');% writetable(vegetable_summary, '蔬菜汇总.xlsx');% writetable(date_summary, '日期汇总.xlsx');% writetable(price_elasticity, '价格弹性.xlsx');
过程
- 创建了三个模拟表格:蔬菜基本信息表、蔬菜价格表和蔬菜销量表
- 基本信息表包含蔬菜ID、名称、类别和产地
- 价格表包含30天的价格数据
- 销量表包含30天的销量数据,销量与价格有一定负相关关系
- 使用outerjoin函数将三个表格联接成一个完整的数据表
- 进行了数据处理和分析:
- 计算销售额
- 按类别、产地、蔬菜和日期进行汇总统计
- 通过多种图表进行数据可视化:
- 各类别蔬菜的总销售额饼图
- 不同产地蔬菜的平均价格条形图
- 销量TOP10的蔬菜水平条形图
- 每日总销售额变化趋势折线图
- 价格与销量的散点图,并计算相关系数
- 进行了高级分析,计算了价格弹性(销量变化百分比/价格变化百分比)
- 使用对数线性回归方法计算每种蔬菜的价格弹性
- 通过水平条形图展示各蔬菜的价格弹性,并标注缺乏弹性和富有弹性的区域
同步空气质量时间表
步骤1: 创建模拟数据
假设我们有多个空气质量监测站的数据,需要同步时间表
1.1 创建监测站信息
stations = ["监测站A", "监测站B", "监测站C", "监测站D", "监测站E"];locations = ["城区", "工业区", "郊区", "居民区", "商业区"];station_info = table();station_info.监测站ID = string(arrayfun(@(x) sprintf('S%03d', x), 1:5, 'UniformOutput', false));station_info.监测站名称 = stations';station_info.位置类型 = locations';
1.2 创建空气质量监测数据
% 假设监测周期为30天,每小时记录一次start_date = datetime(2019, 1, 1);end_date = datetime(2019, 1, 30);timestamps = start_date:hours(1):end_date;% 空气质量指标: PM2.5, PM10, SO2, NO2, O3, CO% 创建5个监测站的数据station_data = cell(5, 1); % 使用cell数组存储每个监测站的数据for s = 1:5% 每个监测站的数据量可能不同(模拟不同监测站可能有缺失记录)% 假设监测站A和C数据完整,其他监测站有部分缺失if s == 1 || s == 3% 数据完整station_timestamps = timestamps;else% 随机缺失5-15%的数据missing_percent = 0.05 + rand() * 0.1;num_missing = round(length(timestamps) * missing_percent);missing_indices = randperm(length(timestamps), num_missing);station_timestamps = timestamps;station_timestamps(missing_indices) = [];end% 生成空气质量数据num_records = length(station_timestamps);% PM2.5 (μg/m³)if s == 2 % 工业区PM2.5较高pm25 = 50 + randn(num_records, 1) * 30;elseif s == 3 % 郊区PM2.5较低pm25 = 20 + randn(num_records, 1) * 10;elsepm25 = 35 + randn(num_records, 1) * 20;endpm25 = max(0, pm25); % 确保非负% PM10 (μg/m³)pm10 = pm25 + 10 + randn(num_records, 1) * 15;pm10 = max(0, pm10);% SO2 (μg/m³)if s == 2 % 工业区SO2较高so2 = 20 + randn(num_records, 1) * 10;elseso2 = 5 + randn(num_records, 1) * 5;endso2 = max(0, so2);% NO2 (μg/m³)if s == 2 % 工业区NO2较高no2 = 40 + randn(num_records, 1) * 20;elseif s == 4 % 居民区NO2中等no2 = 30 + randn(num_records, 1) * 15;elseno2 = 20 + randn(num_records, 1) * 10;endno2 = max(0, no2);% O3 (μg/m³) - 日间较高,夜间较低hour_of_day = hour(station_timestamps);o3_base = 50 + 40 * sin(pi * (hour_of_day - 6) / 12); % 峰值在下午o3 = o3_base + randn(num_records, 1) * 15;o3 = max(0, o3);% CO (mg/m³)if s == 2 % 工业区CO较高co = 1.2 + randn(num_records, 1) * 0.5;elseco = 0.8 + randn(num_records, 1) * 0.3;endco = max(0, co);% 创建表格station_table = table();station_table.时间戳 = station_timestamps;station_table.监测站ID = repmat(station_info.监测站ID(s), num_records, 1);station_table.PM25 = pm25;station_table.PM10 = pm10;station_table.SO2 = so2;station_table.NO2 = no2;station_table.O3 = o3;station_table.CO = co;% 存储到cell数组station_data{s} = station_table;end
步骤2: 同步时间表
2.1 创建完整的时间戳序列(所有监测站的时间戳并集)
all_timestamps = unique(vertcat(station_data{:}.时间戳));all_timestamps = sort(all_timestamps);
2.2 为每个监测站创建同步后的数据
synced_data = cell(5, 1);for s = 1:5% 获取原始数据original_data = station_data{s};% 创建新的表格,包含所有时间戳new_table = table();new_table.时间戳 = all_timestamps;new_table.监测站ID = repmat(station_info.监测站ID(s), length(all_timestamps), 1);% 初始化空气质量指标列为NaNnew_table.PM25 = NaN(length(all_timestamps), 1);new_table.PM10 = NaN(length(all_timestamps), 1);new_table.SO2 = NaN(length(all_timestamps), 1);new_table.NO2 = NaN(length(all_timestamps), 1);new_table.O3 = NaN(length(all_timestamps), 1);new_table.CO = NaN(length(all_timestamps), 1);% 填充已有数据for i = 1:length(all_timestamps)% 查找当前时间戳在原始数据中的位置idx = find(original_data.时间戳 == all_timestamps(i));if ~isempty(idx)% 找到匹配项,复制数据new_table.PM25(i) = original_data.PM25(idx);new_table.PM10(i) = original_data.PM10(idx);new_table.SO2(i) = original_data.SO2(idx);new_table.NO2(i) = original_data.NO2(idx);new_table.O3(i) = original_data.O3(idx);new_table.CO(i) = original_data.CO(idx);endend% 存储同步后的数据synced_data{s} = new_table;end
2.3 合并所有监测站的数据
combined_data = vertcat(synced_data{:});
步骤3: 缺失值处理
3.1 统计缺失值情况
missing_counts = sum(ismissing(combined_data(:, 3:8)));fprintf('各指标缺失值统计:\n');fprintf('PM25: %d\n', missing_counts(1));fprintf('PM10: %d\n', missing_counts(2));fprintf('SO2: %d\n', missing_counts(3));fprintf('NO2: %d\n', missing_counts(4));fprintf('O3: %d\n', missing_counts(5));fprintf('CO: %d\n', missing_counts(6));
3.2 使用线性插值处理缺失值
% 按监测站分组处理缺失值for s = 1:5station_id = station_info.监测站ID(s);station_mask = strcmp(combined_data.监测站ID, station_id);station_data_subset = combined_data(station_mask, :);% 对每个空气质量指标进行插值for col = 3:8% 获取列名col_name = combined_data.Properties.VariableNames{col};% 获取数据data = station_data_subset.(col_name);% 找出非NaN值的索引valid_idx = ~isnan(data);% 如果有至少两个非NaN值,进行插值if sum(valid_idx) >= 2% 使用线性插值data = interp1(find(valid_idx), data(valid_idx), 1:length(data), 'linear', 'extrap');% 更新数据combined_data{station_mask, col_name} = data;endendend
3.3 再次统计缺失值情况
missing_counts_after = sum(ismissing(combined_data(:, 3:8)));fprintf('\n插值后各指标缺失值统计:\n');fprintf('PM25: %d\n', missing_counts_after(1));fprintf('PM10: %d\n', missing_counts_after(2));fprintf('SO2: %d\n', missing_counts_after(3));fprintf('NO2: %d\n', missing_counts_after(4));fprintf('O3: %d\n', missing_counts_after(5));fprintf('CO: %d\n', missing_counts_after(6));
步骤4: 计算空气质量指数(AQI)
4.1 定义各指标的浓度限值和对应的IAQI计算函数
% PM2.5pm25_breakpoints = [0, 35, 75, 115, 150, 250, 350, 500];pm25_iaqi_breakpoints = [0, 50, 100, 150, 200, 300, 400, 500];% PM10pm10_breakpoints = [0, 50, 150, 250, 350, 420, 500, 600];pm10_iaqi_breakpoints = [0, 50, 100, 150, 200, 300, 400, 500];% SO2so2_breakpoints = [0, 50, 150, 475, 800, 1600, 2100, 2620];so2_iaqi_breakpoints = [0, 50, 100, 150, 200, 300, 400, 500];% NO2no2_breakpoints = [0, 40, 80, 180, 280, 565, 750, 940];no2_iaqi_breakpoints = [0, 50, 100, 150, 200, 300, 400, 500];% O3o3_breakpoints = [0, 100, 160, 215, 265, 800];o3_iaqi_breakpoints = [0, 50, 100, 150, 200, 300];% CO (单位转换为mg/m³)co_breakpoints = [0, 2, 4, 14, 24, 36, 48, 60];co_iaqi_breakpoints = [0, 50, 100, 150, 200, 300, 400, 500];
4.2 定义计算IAQI的函数
calculate_iaqi = @(concentration, bp_lo, bp_hi, iaqi_lo, iaqi_hi) ...(iaqi_hi - iaqi_lo) / (bp_hi - bp_lo) * (concentration - bp_lo) + iaqi_lo;
4.3 计算各指标的IAQI
% 初始化IAQI列combined_data.IAQI_PM25 = NaN(height(combined_data), 1);combined_data.IAQI_PM10 = NaN(height(combined_data), 1);combined_data.IAQI_SO2 = NaN(height(combined_data), 1);combined_data.IAQI_NO2 = NaN(height(combined_data), 1);combined_data.IAQI_O3 = NaN(height(combined_data), 1);combined_data.IAQI_CO = NaN(height(combined_data), 1);% 计算PM2.5的IAQIfor i = 1:height(combined_data)pm25 = combined_data.PM25(i);% 找到对应的浓度区间for j = 1:length(pm25_breakpoints)-1if pm25 >= pm25_breakpoints(j) && pm25 <= pm25_breakpoints(j+1)bp_lo = pm25_breakpoints(j);bp_hi = pm25_breakpoints(j+1);iaqi_lo = pm25_iaqi_breakpoints(j);iaqi_hi = pm25_iaqi_breakpoints(j+1);combined_data.IAQI_PM25(i) = calculate_iaqi(pm25, bp_lo, bp_hi, iaqi_lo, iaqi_hi);break;endendend% 计算PM10的IAQIfor i = 1:height(combined_data)pm10 = combined_data.PM10(i);% 找到对应的浓度区间for j = 1:length(pm10_breakpoints)-1if pm10 >= pm10_breakpoints(j) && pm10 <= pm10_breakpoints(j+1)bp_lo = pm10_breakpoints(j);bp_hi = pm10_breakpoints(j+1);iaqi_lo = pm10_iaqi_breakpoints(j);iaqi_hi = pm10_iaqi_breakpoints(j+1);combined_data.IAQI_PM10(i) = calculate_iaqi(pm10, bp_lo, bp_hi, iaqi_lo, iaqi_hi);break;endendend% 计算SO2的IAQIfor i = 1:height(combined_data)so2 = combined_data.SO2(i);% 找到对应的浓度区间for j = 1:length(so2_breakpoints)-1if so2 >= so2_breakpoints(j) && so2 <= so2_breakpoints(j+1)bp_lo = so2_breakpoints(j);bp_hi = so2_breakpoints(j+1);iaqi_lo = so2_iaqi_breakpoints(j);iaqi_hi = so2_iaqi_breakpoints(j+1);combined_data.IAQI_SO2(i) = calculate_iaqi(so2, bp_lo, bp_hi, iaqi_lo, iaqi_hi);break;endendend% 计算NO2的IAQIfor i = 1:height(combined_data)no2 = combined_data.NO2(i);% 找到对应的浓度区间for j = 1:length(no2_breakpoints)-1if no2 >= no2_breakpoints(j) && no2 <= no2_breakpoints(j+1)bp_lo = no2_breakpoints(j);bp_hi = no2_breakpoints(j+1);iaqi_lo = no2_iaqi_breakpoints(j);iaqi_hi = no2_iaqi_breakpoints(j+1);combined_data.IAQI_NO2(i) = calculate_iaqi(no2, bp_lo, bp_hi, iaqi_lo, iaqi_hi);break;endendend% 计算O3的IAQIfor i = 1:height(combined_data)o3 = combined_data.O3(i);% 找到对应的浓度区间for j = 1:length(o3_breakpoints)-1if o3 >= o3_breakpoints(j) && o3 <= o3_breakpoints(j+1)bp_lo = o3_breakpoints(j);bp_hi = o3_breakpoints(j+1);iaqi_lo = o3_iaqi_breakpoints(j);iaqi_hi = o3_iaqi_breakpoints(j+1);combined_data.IAQI_O3(i) = calculate_iaqi(o3, bp_lo, bp_hi, iaqi_lo, iaqi_hi);break;endendend% 计算CO的IAQIfor i = 1:height(combined_data)co = combined_data.CO(i);% 找到对应的浓度区间for j = 1:length(co_breakpoints)-1if co >= co_breakpoints(j) && co <= co_breakpoints(j+1)bp_lo = co_breakpoints(j);bp_hi = co_breakpoints(j+1);iaqi_lo = co_iaqi_breakpoints(j);iaqi_hi = co_iaqi_breakpoints(j+1);combined_data.IAQI_CO(i) = calculate_iaqi(co, bp_lo, bp_hi, iaqi_lo, iaqi_hi);break;endendend
4.4 计算AQI(取各指标IAQI的最大值)
iaqi_columns = combined_data{:, {'IAQI_PM25', 'IAQI_PM10', 'IAQI_SO2', 'IAQI_NO2', 'IAQI_O3', 'IAQI_CO'}};combined_data.AQI = max(iaqi_columns, [], 2);
4.5 确定首要污染物
% 找出每个记录的IAQI最大值对应的指标combined_data.首要污染物 = strings(height(combined_data), 1);pollutant_names = ["PM2.5", "PM10", "SO2", "NO2", "O3", "CO"];for i = 1:height(combined_data)[~, max_idx] = max(iaqi_columns(i, :));combined_data.首要污染物(i) = pollutant_names(max_idx);end
4.6 确定空气质量等级
combined_data.空气质量等级 = strings(height(combined_data), 1);combined_data.等级描述 = strings(height(combined_data), 1);for i = 1:height(combined_data)aqi = combined_data.AQI(i);if aqi <= 50combined_data.空气质量等级(i) = "一级";combined_data.等级描述(i) = "优";elseif aqi <= 100combined_data.空气质量等级(i) = "二级";combined_data.等级描述(i) = "良";elseif aqi <= 150combined_data.空气质量等级(i) = "三级";combined_data.等级描述(i) = "轻度污染";elseif aqi <= 200combined_data.空气质量等级(i) = "四级";combined_data.等级描述(i) = "中度污染";elseif aqi <= 300combined_data.空气质量等级(i) = "五级";combined_data.等级描述(i) = "重度污染";elsecombined_data.空气质量等级(i) = "六级";combined_data.等级描述(i) = "严重污染";endend
步骤5: 数据分析和可视化
5.1 按监测站统计AQI平均值
station_aqi = groupsummary(combined_data, '监测站ID', 'mean', 'AQI');station_aqi = outerjoin(station_info, station_aqi, 'Keys', '监测站ID');
5.2 按空气质量等级统计记录数
level_counts = groupcounts(combined_data, '等级描述');
5.3 按首要污染物统计记录数
pollutant_counts = groupcounts(combined_data, '首要污染物');
5.4 按小时统计平均AQI
combined_data.小时 = hour(combined_data.时间戳);hourly_aqi = groupsummary(combined_data, '小时', 'mean', 'AQI');
5.5 可视化
5.5.1 各监测站平均AQI
figure;bar(station_aqi.mean_AQI);title('各监测站平均AQI');xlabel('监测站');ylabel('AQI');xticks(1:5);xticklabels(station_aqi.监测站名称);xtickangle(45);
5.5.2 空气质量等级分布
figure;pie(level_counts.Percent, level_counts.等级描述);title('空气质量等级分布');
5.5.3 首要污染物分布
figure;pie(pollutant_counts.Percent, pollutant_counts.首要污染物);title('首要污染物分布');
5.5.4 小时平均AQI变化
figure;plot(hourly_aqi.小时, hourly_aqi.mean_AQI, '-o', 'LineWidth', 2);title('小时平均AQI变化');xlabel('小时');ylabel('AQI');grid on;xticks(0:23);
5.5.5 各监测站AQI时间序列
figure;for s = 1:5station_id = station_info.监测站ID(s);station_name = station_info.监测站名称{s};station_mask = strcmp(combined_data.监测站ID, station_id);station_data_subset = combined_data(station_mask, :);% 按时间排序station_data_subset = sortrows(station_data_subset, '时间戳');% 每天取一个平均值点(减少数据量)daily_data = groupsummary(station_data_subset, '时间戳', 'mean', 'AQI');plot(daily_data.时间戳, daily_data.mean_AQI, 'LineWidth', 2);hold on;endtitle('各监测站日均AQI时间序列');xlabel('日期');ylabel('AQI');legend(station_info.监测站名称, 'Location', 'best');grid on;xtickangle(45);
步骤6: 导出数据
% writetable(combined_data, '同步空气质量数据.xlsx');% writetable(station_aqi, '监测站AQI统计.xlsx');% writetable(level_counts, '空气质量等级统计.xlsx');% writetable(pollutant_counts, '首要污染物统计.xlsx');% writetable(hourly_aqi, '小时AQI统计.xlsx');
过程
- 创建了5个空气质量监测站的模拟数据,包括监测站信息和30天的空气质量监测数据
- 每个监测站记录PM2.5、PM10、SO2、NO2、O3和CO六项指标
- 不同位置的监测站有不同的污染物特征(如工业区PM2.5、SO2、NO2较高)
- 模拟了部分监测站有数据缺失的情况
- 进行了时间表同步:
- 创建完整的时间戳序列(所有监测站的时间戳并集)
- 为每个监测站创建包含所有时间戳的新表格,缺失值用NaN填充
- 合并所有监测站的数据
- 处理缺失值:
- 统计各指标的缺失值情况
- 使用线性插值方法处理缺失值
- 再次统计缺失值情况,验证处理效果
- 计算空气质量指数(AQI):
- 定义各指标的浓度限值和对应的IAQI计算函数
- 计算各指标的IAQI(个体空气质量指数)
- 计算AQI(取各指标IAQI的最大值)
- 确定首要污染物(IAQI最大的指标)
- 确定空气质量等级和描述
- 进行了数据分析和可视化:
- 按监测站统计AQI平均值
- 按空气质量等级和首要污染物统计记录数
- 按小时统计平均AQI
- 通过多种图表展示分析结果:各监测站平均AQI条形图、空气质量等级和首要污染物分布饼图、小时平均AQI变化折线图、各监测站AQI时间序列图