附件2中有50辆共享单车(编号为951-1000)的数据。已知其中5辆单车会间歇性地发生故障,从而导致该车在部分时段的骑行速度过慢。请根据附件1,判断附件2中有哪5辆车最有可能是问题车。
导入附件1数据
%% 导入数据
[~, ~, raw0_0] = xlsread('附件1 共享单车数据.xls','Sheet1','B1:B12030');
[~, ~, raw0_1] = xlsread('附件1 共享单车数据.xls','Sheet1','D1:D12030');
[~, ~, raw0_2] = xlsread('附件1 共享单车数据.xls','Sheet1','F1:F12030');
[~, ~, raw0_3] = xlsread('附件1 共享单车数据.xls','Sheet1','H1:H12030');
[~, ~, raw0_4] = xlsread('附件1 共享单车数据.xls','Sheet1','J1:J12030');
raw = [raw0_0,raw0_1,raw0_2,raw0_3,raw0_4];
raw(cellfun(@(x) ~isempty(x) && isnumeric(x) && isnan(x),raw)) = {''};
%% 将非数值元胞替换为 NaN
R = cellfun(@(x) ~isnumeric(x) && ~islogical(x),raw); % 查找非数值元胞
raw(R) = {NaN}; % 替换非数值元胞
%% 创建输出变量
data = reshape([raw{:}],size(raw));
%% 创建表
data1 = table;
%% 将导入的数组分配给列变量名称
data1.bh = data(:,1);
data1.cf_time = data(:,2);
data1.cf_tcd = data(:,3);
data1.dd_time = data(:,4);
data1.dd_tcd = data(:,5);
%% 清除临时变量
clearvars data raw raw0_0 raw0_1 raw0_2 raw0_3 raw0_4 R;
% 备份一下数据
data_bf = data1;
处理第一列的缺失值
data1.bh = fillmissing(data1.bh,'previous');
删除表中包含缺失数据的任何行
data1 = rmmissing(data1);
提取这10个停车点来回之间的数据
num = 10; % 10个停车点
tcd_data = cell(num,num);
for i = 1:num
for j = 1:i
ind1 = (data1.cf_tcd == i & data1.dd_tcd == j); % i-->j
ind2 = (data1.cf_tcd == j & data1.dd_tcd == i); % j-->i
tcd_data{i,j} = data1(ind1|ind2,:);
end
end
计算平均值和标准差
mean_tcd = cellfun(@(x) mean(x.dd_time-x.cf_time), tcd_data,'ErrorHandler',@(varargin) NaN);
std_tcd = cellfun(@(x) std(x.dd_time-x.cf_time), tcd_data,'ErrorHandler',@(varargin) NaN);
生成一个对称矩阵,在此之前将nan改为0
mean_tcd(isnan(mean_tcd)) = 0;
std_tcd(isnan(std_tcd)) = 0;
mean_tcd = mean_tcd + mean_tcd';
std_tcd = std_tcd + std_tcd';
导入附件2数据
%% 导入数据
[~, ~, raw0_0] = xlsread('附件2 待检测的共享单车数据.xls','Sheet1','B1:B619');
[~, ~, raw0_1] = xlsread('附件2 待检测的共享单车数据.xls','Sheet1','D1:D619');
[~, ~, raw0_2] = xlsread('附件2 待检测的共享单车数据.xls','Sheet1','F1:F619');
[~, ~, raw0_3] = xlsread('附件2 待检测的共享单车数据.xls','Sheet1','H1:H619');
[~, ~, raw0_4] = xlsread('附件2 待检测的共享单车数据.xls','Sheet1','J1:J619');
raw = [raw0_0,raw0_1,raw0_2,raw0_3,raw0_4];
raw(cellfun(@(x) ~isempty(x) && isnumeric(x) && isnan(x),raw)) = {''};
%% 将非数值元胞替换为 NaN
R = cellfun(@(x) ~isnumeric(x) && ~islogical(x),raw); % 查找非数值元胞
raw(R) = {NaN}; % 替换非数值元胞
%% 创建输出变量
data = reshape([raw{:}],size(raw));
%% 创建表
data2 = table;
%% 将导入的数组分配给列变量名称
data2.bh = data(:,1);
data2.cf_time = data(:,2);
data2.cf_tcd = data(:,3);
data2.dd_time = data(:,4);
data2.dd_tcd = data(:,5);
%% 清除临时变量
clearvars data raw raw0_0 raw0_1 raw0_2 raw0_3 raw0_4 R;
% 备份一下数据
data_bf2 = data2;
处理第一列的缺失值
data2.bh = fillmissing(data2.bh,'previous');
删除表中包含缺失数据的任何行
data2 = rmmissing(data2);
计算行驶的时间
data2.dif_time = data2.dd_time-data2.cf_time;
3sigma原则确定异常值
diftime = data2.dif_time;
cfd = data2.cf_tcd;
ddd = data2.dd_tcd;
num = length(cfd); % 569
res = zeros(num,1); % 初始化要求的结果
for i = 1:num
sigma = std_tcd(cfd(i),ddd(i));
if diftime(i) < mean_tcd(cfd(i),ddd(i)) - 3*sigma
res(i) = 1;
elseif diftime(i) > mean_tcd(cfd(i),ddd(i)) + 3*sigma
res(i) = 1;
end
end
data2.res = res;
统计这50辆车中,异常值的占比
先对数据进行分组,G是分组编号,M是代表的意义
[G,M] = findgroups(data2.bh);
f = @(x) length(x(x==1))/length(x);
bl = splitapply(f,data2.res,G); % 计算异常值的比例
format long g
sortrows([M,bl],2,'descend')
ans = 50×2
975 0.833333333333333
961 0.8
996 0.636363636363636
977 0.625
981 0.444444444444444
951 0
952 0
953 0
954 0
955 0
编号为[975 961 996 977 981]的这五辆车存在问题。
为确保停车点的正常运行,工作人员每天需骑车从第1个停车点开始,对10个停车点依次进行无重复无遗漏地巡视,途中不作停留,最后回到第1个停车点。为了尽快完成所有停车点的巡视并返回,根据附件1,请给出一条巡视路线(即10个停车点的巡视顺序),并给出巡视一次所需要的最短时间。
factorial(9)
ans =
362880
问题规模不算太大,可以枚举,没太大必要用模拟退火或者遗传算法等智能优化算法!
枚举法:先来生成路径的排列组合(不到1s出结果了)
tic
PATH = perms(2:10);
num = size(PATH,1);
PATH = [ones(num,1),PATH];
TIME = zeros(num,1); % 保存每条路径的时间
for i = 1:num
TIME(i) = calculate_tsp_d(PATH(i,:),mean_tcd);
end
toc
历时 0.432379 秒。
function result = calculate_tsp_d(path,d)
% 输入:path:路径(1至n的一个序列),d:距离矩阵(在本题中就是时间~)
n = length(path);
result = 0; % 初始化该路径走的距离为0
for i = 1:n-1
result = d(path(i),path(i+1)) + result; % 按照这个序列不断的更新走过的路程这个值
end
result = d(path(1),path(n)) + result; % 别忘了加上从最后一个城市返回到最开始那个城市的距离
end
[min_time,ind] = min(TIME);
disp('最优路线是:')
PATH(ind,:)
% ans = 1×10
% 1 10 2 8 5 7 4 9 3 6
disp('最短时间是')
最短时间是
min_time
min_time =
53.4753546422219
为应对疫情,工作人员需要每隔4小时对共享单车进行一次消毒。消毒的方式为:从停车点1开始消毒,并骑电动车对10个停车点依次进行无重复无遗漏地消毒(电动车的速度为共享单车的1.5倍),每个停车点停留10分钟,最后返回停车点1。在某个停车点停留时,对出现在当前停车点的所有共享单车,在把手、坐垫和篮筐上喷洒医用酒精进行消毒。由于消毒方式便于操作,停留的10分钟已然够用。同时,鉴于酒精的快速挥发性,消毒不影响借还车的进行。若某次消毒,工作人员在上午9点出发,根据附件1,请给出一条消毒路线(即10个停车点的消毒顺序),使得本次能够被消毒的共享单车数量尽可能地多,并且不影响下一次消毒的进行。
这个题目有一点点歧义,即要不要算上附件二中编号为951-1000的这50辆车
如果算上的话可以这么做:
% data = union(data1,data2(:,1:5));
如果同时还要排除存在问题的这五辆车,可以这样做:
% ind = [975 961 996 977 981];
% for i = 1:length(ind)
% data(data.bh == ind(i),:) = [];
% end
%统计在一天的每一分钟,每个停车点有多少辆车
R = zeros(24 * 60 , 10);
data = data1;
data.cf_time = ceil(data.cf_time);
data.dd_time = ceil(data.dd_time);
bh = unique(data.bh);
num_bh = length(bh);
for k = 1:num_bh
tmp = data(data.bh == bh(k),:);
num = height(tmp); % 有几个记录
if num == 1
R(1:tmp.cf_time, tmp.cf_tcd) = R(1:tmp.cf_time, tmp.cf_tcd)+1;
R(tmp.dd_time:end, tmp.dd_tcd) = R(tmp.dd_time:end, tmp.dd_tcd)+1;
else
for i = 1:num
if i == 1
R(1:tmp.cf_time(i), tmp.cf_tcd(i)) = R(1:tmp.cf_time(i), tmp.cf_tcd(i))+1;
elseif i == num
R(tmp.dd_time(i): end, tmp.dd_tcd(i)) = R(tmp.dd_time(i):end, tmp.dd_tcd(i))+1;
R(tmp.dd_time(i-1): tmp.cf_time(i), tmp.dd_tcd(i-1)) = R(tmp.dd_time(i-1): tmp.cf_time(i), tmp.dd_tcd(i-1))+1;
else
R(tmp.dd_time(i-1): tmp.cf_time(i), tmp.dd_tcd(i-1)) = R(tmp.dd_time(i-1): tmp.cf_time(i), tmp.dd_tcd(i-1))+1;
end
end
end
end
这一问也可以采用枚举法:先来生成路径的排列组合(不到10s出结果了)
tic
PATH = perms(2:10);
num = size(PATH,1);
PATH = [ones(num,1),PATH];
CLS = zeros(num,1); % 保存每条路径能够消毒的车辆数
for i = 1:num
CLS(i) = calculate_num(PATH(i,:),mean_tcd,R);
end
toc
历时 4.385277 秒。
function result = calculate_num(path,mean_tcd,R)
% 1 10 9 8 7 6 5 4 3 2
start_clock = 60 * 9; % 在上午9点开始消毒
tlsj = 10; % 每个停车点停留时间是10分钟
num = length(path);
result = 0;
for i = 1:num
result = result + max(R(start_clock: start_clock+tlsj-1, path(i)));
if i < num
start_clock = ceil(start_clock + tlsj + mean_tcd(path(i),path(i+1)) / 1.5);
end
end
end
[max_cls,ind] = max(CLS);
disp('最优路线是:')
最优路线是:
PATH(ind,:)
ans = 1×10
1 3 7 6 2 8 4 10 5 9
disp('能够消毒的车辆数最多是:')
能够消毒的车辆数最多是:
max_cls
max_cls =
943
根据附件1,如何在某个时间段内对停车点的共享单车需求程度进行评估,给出评价标准,并指出从450到600这个时间段,对共享单车需求程度最高的3个停车点。
这里考虑一种最简单的定义需求的关系:
如果某个停车点第x分钟有f(x)辆车,第x+1分钟有f(x+1)辆车
这一分钟的需求量是max(f(x)-f(x+1),0)辆车(车被借走了才有需求)
同理可以考虑一段时间的需求量,只需要进行一个累计求和即可。
r1 = R(450:599,:);
r2 = R(451:600,:);
demand = sum(max(r1-r2,0))
demand = 1×10
123 84 102 95 116 111 112 100 97 95
上面这种需求方式只考虑了借车的需求,如果同时考虑还车的需求,可以这样做:
% r1 = R(450:599,:);
% r2 = R(451:600,:);
% demand = sum(abs(r1-r2))
还有一个小问题:按照这个需求关系的定义:如果某一时刻借出一辆然后同时还回一辆不是需求量就变成零了吗?
解决方法:上面我们生成矩阵的时候时间是以1分钟分割的,如果你把时间划分的更加精细一点,比如以0.1分钟来分割,就可以减小这个误差。但这个时候的R矩阵会比原来的大10倍,这对matlab来说还是能够应付的过来的,大家有兴趣可以自己实现这个代码。
下面是画图(matlab2021a版本可以运行,2017a版本会报错,其他版本请自己测试)
figure1 = figure('NumberTitle','off','Name','Figure','Color',[1 1 1]);
% 创建 axes
axes1 = axes('Parent',figure1);
hold(axes1,'on');
% 创建 bar
b = bar(demand,'DisplayName',' 需求');
% 添加数据点
xtips1 = b(1).XEndPoints;
ytips1 = b(1).YEndPoints;
labels1 = string(b(1).YData);
text(xtips1,ytips1,labels1,'HorizontalAlignment','center',...
'VerticalAlignment','bottom')
% 创建 plot
plot([0,11],[mean(demand),mean(demand)],'DisplayName',' 均值','Tag','mean y','LineStyle','-.',...
'Color',[0 0.5 0]);
box(axes1,'on');
hold(axes1,'off');
% 设置其余坐标区属性
set(axes1,'XTick',[1 2 3 4 5 6 7 8 9 10]);
% 创建 legend
legend(axes1,'show');
2019年,宁波市发布了文件《关于规范宁波市互联网租赁自行车发展的若干意见》(附件3),文件中提到:“按照交通相宜、规模适度、因地制宜、方便公众的原则,科学编制非机动车停放区域设置规划” 。公司根据文件精神,要撤销2个停车点。具体操作为,在附件1中的所有借还车行为结束后,移除这两个停车点的车辆,并运送到其他城市。请给出撤销停车点的评判标准,并指出应撤销哪两个停车点?
这题就很简单了,可以考虑很多指标
比如上一问定义的需求量 波动情况等