2025年五一数学建模竞赛A题-支路车流量推测问题详细建模与源代码编写(二)

目前我们已经完成第一问的建模,现在我们开始对第二问开始建模分析。

问题重述与变量定义

问题2.考虑图2所示的道路,支路1和支路2的车流同时汇入主路5,支路3和支路4的车流同时汇入主路5,仅在主路5上安装了车流量监测设备A2,每2分钟记录一次主路的车流量信息,附件表2中提供了某天早上[6:58,8:58]时间段内主路5上的车流量数据。假设车辆从支路1和支路2的路口行驶到设备A2处的时间为2分钟,车辆从支路3和支路4的路口到达设备A2处的行驶时间忽略不计。

由历史车流量观测记录可知,在[6:58,8:58]时间段内,支路1的车流量稳定;支路2的车流量在[6:58,7:48]和[8:14,8:58]时间段内线性增长,在(7:48,8:14)时间段内稳定;支路3的车流量呈现先线性增长后稳定的趋势;支路4的车流量呈现周期性规律。

请建立数学模型,根据附件表2的数据推测支路1、支路2、支路3、支路4上的车流量,使用合适的函数关系来描述各支路上的车流量随时间t(t∈[0,59])的变化,并分析结果的误差。在表2.1中填入具体的函数表达式,在表2.2中分别填入7:30和8:30这两个时刻各支路上的车流量数值。
在这里插入图片描述

图2 问题2道路示意图
表2.1 问题2支路车流量函数表达式

<
支路1 支路2
<think>由于问题涉及到从主路车流量反推两个支路车流量,且已知两个支路车流量变化趋势,我们可以建立数学模型。 已知条件: 1. 主路3的车流量数据已知(从Excel文件读取),时间间隔为2分钟。 2. 支路1的车流量呈线性增长趋势:设支路1在时间t的车流量为 f1(t) = a1 * t + b1 3. 支路2的车流量先线性增长后线性减少:这里我们需要确定一个转折点。假设在时间t0之前线性增长,t0之后线性减少。因此,我们可以用分段线性函数表示: f2(t) = { a2 * t + b2, 当 t <= t0 { c2 * t + d2, 当 t > t0 并且为了保证在t0处连续,有:a2 * t0 + b2 = c2 * t0 + d2 另外,根据交通流守恒,主路3在时间t的车流量等于支路1和支路2在时间t的车流量之和(假设没有其他车辆来源): f3(t) = f1(t) + f2(t) 因此,对于每一个时间点t,我们有: f3(t) = (a1 * t + b1) + f2(t) 由于支路2的分段函数中有一个转折点t0,我们需要确定t0的位置。t0可以是时间区间内的任意一个时间点,但为了简化,我们可以假设转折点发生在某个时间点(比如第k个时间点,k从1到n-1,n为总时间点数)。但这样就需要枚举k,然后分别对两段进行拟合,并选择最优的k。 然而,由于问题中并没有给出支路2的转折点位置,我们需要将其作为未知参数进行估计。因此,这是一个分段线性回归问题,同时还要估计转折点。 步骤: 1. 读取Excel文件,获取主路3的车流量数据。假设时间点从0开始,每2分钟一个点,那么时间t可以表示为0, 2, 4, ..., 2*(n-1)分钟(或者以分钟为单位,t_i = 2*i,i=0,1,...,n-1)。 2. 定义支路1的线性函数:f1(t) = a1 * t + b1 3. 定义支路2的分段线性函数,转折点为t0(t0也是待求参数)。注意,t0可以不在时间点上,但为了简化,我们可以假设t0是2分钟的整数倍(因为数据是2分钟一个点),或者允许t0为任意实数。 4. 目标是最小化主路3的实际车流量模型预测值(即f1(t)+f2(t))的均方误差(MSE)。 由于问题中转折点t0未知,我们需要同时优化连续参数(a1, b1, a2, b2, c2, d2)和离散参数(t0)。这可以通过网格搜索或迭代优化来实现,但计算量较大。 另一种思路:由于支路1是线性增长,我们可以将主路3的数据减去支路1的线性部分,剩下的就是支路2的分段线性函数。但支路1的参数也是未知的,所以需要同时估计。 我们可以将问题转化为:寻找参数a1, b1, a2, b2, c2, d2和t0,使得对于所有时间点t_i,有: if t_i <= t0: f3(t_i) = a1*t_i + b1 + a2*t_i + b2 else: f3(t_i) = a1*t_i + b1 + c2*t_i + d2 即: if t_i <= t0: f3(t_i) = (a1+a2)*t_i + (b1+b2) else: f3(t_i) = (a1+c2)*t_i + (b1+d2) 令: A1 = a1 + a2, B1 = b1 + b2 (当t<=t0) A2 = a1 + c2, B2 = b1 + d2 (当t>t0) 这样,我们实际上是在用分段线性函数拟合f3(t)。但是,这里有一个约束:支路1的线性函数是全局的,而支路2的分段函数在转折点前后斜率不同,但转折点前后支路1的斜率是相同的(a1),所以转折点前后整个模型的斜率变化完全由支路2引起。 因此,我们可以先忽略支路1和支路2的分解,直接用分段线性回归拟合f3(t),得到转折点t0和两个线性段的参数(A1, B1)和(A2, B2)。然后,再考虑分解成两个支路。 但是,分解时我们有两个方程: 在t<=t0的区间: A1 = a1 + a2, B1 = b1 + b2 在t>t0的区间: A2 = a1 + c2, B2 = b1 + d2 同时,支路2在转折点处连续: a2*t0+b2 = c2*t0+d2 => (a2-c2)*t0 + (b2-d2)=0 另外,支路1在整个时间段都是线性的,即a1和b1是全局的。因此,我们可以得到: 在t<=t0区间:支路1:a1*t+b1,支路2:A1*t+B1 - (a1*t+b1) = (A1-a1)*t + (B1-b1) 在t>t0区间:支路1:a1*t+b1,支路2:A2*t+B2 - (a1*t+b1) = (A2-a1)*t + (B2-b1) 所以,支路2在转折点前后分别为: 前段:a2 = A1 - a1, b2 = B1 - b1 后段:c2 = A2 - a1, d2 = B2 - b1 代入支路2的连续性条件: ( (A1 - a1) - (A2 - a1) ) * t0 + ( (B1 - b1) - (B2 - b1) ) = 0 => (A1 - A2)*t0 + (B1 - B2) = 0 这个条件在分段线性回归中已经满足了吗?注意,我们在做分段线性回归时,要求转折点处函数值连续,即: 在t0处,前段函数值:A1*t0+B1,后段函数值:A2*t0+B2,应该相等:A1*t0+B1 = A2*t0+B2 => (A1-A2)*t0 + (B1-B2)=0 所以,这个条件在分段线性回归中已经满足(如果我们强制要求连续的话)。因此,我们只需要进行分段线性回归(要求连续)即可得到A1, A2, B1, B2, t0。 然后,我们还需要分解出支路1的参数(a1, b1)和支路2的参数(a2, b2, c2, d2)。但是,仅凭上述方程,我们无法唯一确定a1和b1,因为分解有无穷多种可能。例如,我们可以任意分配斜率给支路1和支路2,只要满足两个区间的叠加关系。 因此,我们需要利用题目中给出的支路1和支路2的变化趋势信息: 支路1:线性增长(即a1>0) 支路2:先线性增长(a2>0)后线性减少(c2<0) 所以,在分段线性回归得到A1, A2, B1, B2, t0后,我们需要确定a1,使得: 在t<=t0区间:a2 = A1 - a1 > 0 => a1 < A1 在t>t0区间: c2 = A2 - a1 < 0 => a1 > A2 因此,a1需要满足:A2 < a1 < A1 另外,我们还需要保证支路1的线性增长,所以a1>0。 那么,如何选择a1?题目没有给出其他信息,因此我们可以选择使得支路2的斜率变化尽可能大?或者我们可以选择使支路1的斜率尽可能小(即最小化a1)?或者最大化?这里可能需要额外的约束。 实际上,题目中并没有给出分解的唯一标准,但我们可以通过最小化支路2的斜率变化幅度来求解?或者我们可以通过最小化支路1的斜率变化?但是支路1是全局线性的。 考虑到问题没有给出更多信息,我们可以取a1为区间(A2, A1)的中点,即 a1 = (A1+A2)/2。这样,支路2在前后两段的斜率关于0对称变化?不一定,但这样分配可能比较平衡。 另一种思路:由于支路1是线性增长,我们可以假设在整个时间段内,支路1的流量是均匀增加的,而支路2则负责剩余的变化。我们可以通过最小化支路2的斜率变化(即最小化|a2|和|c2|)来选择a1?但这样可能没有唯一最优解。 实际上,我们注意到,在分解时,支路1的线性函数是全局的,因此我们可以利用整个时间段来拟合支路1。但是,在分段线性回归中,我们已经将主路3分解成两个线性段,而这两个线性段是由支路1和支路2叠加而成的。由于支路1是全局线性的,那么主路3的两个线性段的斜率差(A1-A2)应该等于支路2在前后两段的斜率差(a2-c2),因为支路1的斜率a1在前后是相同的。 但是,我们仍然无法唯一确定a1。因此,我们需要引入额外的优化目标。例如,我们可以希望支路2的斜率变化尽可能小(即最小化|a2|和|c2|),但这样会使得支路1的斜率变大。或者,我们可以希望支路1的斜率尽可能小(因为支路1是线性增长,可能增长平缓),但这样会导致支路2的斜率变化较大。 这里,我们可能需要根据实际情况进行权衡。由于题目没有给出具体标准,我们采用折中的方法:取a1=(A1+A2)/2,这样两个支路对斜率变化的贡献相等。 因此,算法步骤: 步骤1:读取Excel文件,获取主路3的车流量序列,记为y,时间点t_i = 2*i,i=0,1,...,n-1。 步骤2:对主路3的车流量序列进行分段线性回归(要求转折点连续),寻找最优转折点t0和两个线性段的参数(A1, B1)和(A2, B2)。目标是最小化整个序列的均方误差。 步骤3:根据分段线性回归的结果,计算支路1的斜率a1=(A1+A2)/2,然后计算支路1的截距b1?注意,这里我们还没有确定b1。 如何确定b1?我们可以利用整个序列的数据。因为: 在t<=t0区间:y_i = A1*t_i + B1 = (a1 + a2)*t_i + (b1+b2) => b1+b2 = B1 - (a1+a2)*t_i? 不对,应该是常数项,所以b1+b2=B1 在t>t0区间:y_i = A2*t_i + B2 = (a1 + c2)*t_i + (b1+d2) => b1+d2=B2 同时,支路2在转折点连续的条件已经满足(由分段线性回归保证)。 因此,我们有两个方程: b1 + b2 = B1 ...(1) b1 + d2 = B2 ...(2) 但是,b1是全局的,而b2和d2分别是支路2在前后两段的截距。我们还需要一个方程来确定b1。 注意,支路1的线性函数是f1(t)=a1*t+b1,它在整个时间段都是有效的。因此,我们可以用整个时间段的数据来拟合支路1,但此时支路2的函数是未知的。然而,我们也可以利用已经得到的分解关系: 在t<=t0区间:支路2:f2(t) = (A1 - a1)*t + (B1 - b1) 在t>t0区间:支路2:f2(t) = (A2 - a1)*t + (B2 - b1)支路2的流量应该非负(因为车流量不能为负)。所以,我们可以要求在整个时间段内,支路2的流量非负,即: 对于t<=t0: (A1 - a1)*t + (B1 - b1) >=0 对于t>t0: (A2 - a1)*t + (B2 - b1) >=0 由于a1=(A1+A2)/2,所以A1 - a1 = (A1-A2)/2 >0(因为A1> A2,由趋势可知,前段斜率大于后段斜率),所以前半段是增函数,最小值在t=0处;后半段是减函数(因为A2 - a1 = (A2-A1)/2 <0),所以最小值在t=t_max处。 因此,约束条件为: (B1 - b1) >=0 (因为t=0时,前半段最小值为B1-b1) (A2 - a1)*t_max + (B2 - b1) >=0 另外,支路1的流量也应该非负,即:a1*t+b1>=0,对于t在[0, t_max]区间。 由于a1>0,所以最小值在t=0处:b1>=0。 因此,我们可以通过最小化某个目标函数来确定b1。例如,我们可以最小化支路2的流量的方差?或者最小化支路2的流量总和?但这里没有明显的最优标准。 另一种思路:由于支路1是线性增长,我们可以假设在初始时刻(t=0)时,支路1的流量为0(即没有车),那么b1=0。但这样假设可能合理吗?题目没有说,但我们可以尝试。 如果我们假设b1=0,那么: 由(1)式:b2 = B1 由(2)式:d2 = B2 然后,我们检查支路2的非负性: 前半段:f2(t) = (A1 - a1)*t + B1 后半段:f2(t) = (A2 - a1)*t + B2 在t=0时,前半段:f2(0)=B1,需要B1>=0。 在最后一个时间点t_max,后半段:f2(t_max)=(A2 - a1)*t_max + B2,需要>=0。 另外,转折点处连续已经满足。 因此,如果B1>=0且(A2 - a1)*t_max+B2>=0,那么b1=0是一个可行的解。 如果B1<0,那么我们就不能设b1=0,因为会导致支路2在t=0时出现负值。此时,我们可以设置b1为满足非负约束的最小值,即: b1 = max(0, -min_value) 其中,min_value是支路2在整个时间段内可能的最小值。但这样计算比较复杂。 或者,我们可以将b1作为变量,通过最小化支路1的初始流量(即b1)来确定,但需要满足非负约束。我们可以设置: b1 = max(0, -min_value1, -min_value2) 其中,min_value1是前半段支路2的最小值(即B1-b1的最小值,由于前半段是递增,最小值在t=0,所以最小值为B1-b1,因此要求B1-b1>=0 => b1<=B1) min_value2是后半段支路2的最小值(在t_max处,值为(A2 - a1)*t_max + (B2 - b1)),要求>=0 => b1 <= (A2 - a1)*t_max + B2 同时,支路1的非负性要求b1>=0。 因此,b1需要满足: 0 <= b1 <= min(B1, (A2 - a1)*t_max + B2) 我们可以取b1=0,如果0在这个区间内;否则取区间的最小值(因为b1越小,支路1的初始流量越小,可能更合理?)。但为了简单,我们取b1=0,如果0<=min(B1, (A2 - a1)*t_max + B2);否则取min(B1, (A2 - a1)*t_max + B2)作为b1的上限,然后取b1=0和这个上限的折中?或者直接取上限(为了满足非负,取上限可以保证支路2的非负性,但可能使支路1的初始流量偏大)。 但这里,我们采用保守做法:为了满足非负约束,我们取b1为0和min(B1, (A2 - a1)*t_max + B2)之间的一个值,但为了最小化支路1的初始流量,我们取b1=0(如果0<=min(B1, ...))或者取b1=min(B1, ...)(如果0大于min(B1,...)是不可能的,因为min(B1,...)可能是负数,但这样就不满足约束了)。所以,如果min(B1, (A2 - a1)*t_max + B2) <0,那么无解?这时可能需要调整a1。 由于a1的取值区间(A2, A1)可能比较宽,我们可以调整a1的取值,使得非负约束得到满足。具体来说,我们可以通过调整a1来改变支路2的截距范围。 但是,这样会使问题复杂化。因此,我们暂时假设b1=0,然后检查支路2的非负性。如果出现负值,我们再调整b1(例如,将b1设置为刚好使支路2的最小值为0)。 然而,由于时间关系,我们简化处理:直接取b1=0,然后计算支路2,如果支路2出现负值,则将其置为0(但这样会破坏线性关系,不推荐)。 因此,我们采用以下步骤: 步骤1:分段线性回归(连续)拟合主路3,得到两个线性段和转折点t0。 步骤2:计算a1=(A1+A2)/2,并设b1=0。 步骤3:计算支路2: 在t<=t0区间:f2(t) = (A1 - a1)*t + B1 在t>t0区间:f2(t) = (A2 - a1)*t + B2 步骤4:检查支路2是否非负。如果有负值,则调整b1:将b1增加,直到支路2的最小值非负。同时,支路1的截距变为b1(增加后的值),而支路2的截置相应调整(即b2=B1-b1,d2=B2-b1),并重新计算支路2。 但是,调整b1会影响整个支路1和支路2,而且支路2的表达式也会改变。所以,在调整b1后,支路2的表达式变为: 前半段:f2(t) = (A1 - a1)*t + (B1 - b1) 后半段:f2(t) = (A2 - a1)*t + (B2 - b1) 我们需要保证: 前半段在t=0时:B1-b1>=0 => b1<=B1 后半段在t=t_max时:(A2 - a1)*t_max + (B2 - b1)>=0 => b1 <= (A2 - a1)*t_max + B2 同时,b1>=0。 因此,b1的取值范围为 [0, min(B1, (A2 - a1)*t_max + B2)] 我们可以取b1=0,如果0在这个范围内;否则,取b1=min(B1, (A2 - a1)*t_max + B2)(因为min(B1,...)可能为负,所以实际上如果min(B1,...)为负,那么b1只能取0,但此时可能不满足非负约束,所以需要调整a1)。 如果min(B1, (A2 - a1)*t_max + B2) <0,那么即使取b1=0,后半段在t_max处还是负的。此时,我们需要调整a1,让a1小一些(这样A2 - a1会变大,因为A2是负数?不对,A2是后半段的斜率,应该是正数还是负数?题目支路2先增后减,所以前半段斜率a2>0,后半段c2<0,所以A2 = a1+c2,而c2<0,所以A2可能小于a1,但A2可能是正也可能是负。而A1 = a1+a2>a1,因为a2>0。所以A1>A2,但A2不一定为负。 因此,如果出现min(B1, (A2 - a1)*t_max + B2) <0,我们可以尝试减小a1(但a1不能小于A2,因为a1> A2),这样会使得A2 - a1(为负值)的绝对值变小(因为a1减小,A2 - a1 = (A2 - (A1+A2)/2) = (2A2 - A1 - A2)/2 = (A2-A1)/2,这个值只A1和A2有关,a1无关?不对,我们定义a1=(A1+A2)/2,所以A2 - a1 = A2 - (A1+A2)/2 = (A2 - A1)/2,这是一个常数,a1的取值无关?) 所以,调整a1并不能改变A2 - a1,因为A2 - a1 = (A2 - A1)/2 是固定的。因此,我们只能调整b1,或者接受负值。 因此,我们取b1=0,然后计算支路2。如果出现负值,我们将其视为0(但这样会破坏模型,因为线性关系被破坏了)。或者,我们可以重新考虑分段线性回归,是否可能得到不同的转折点?或者我们是否可以将转折点调整到更合适的位置? 考虑到问题的复杂性,我们假设非负约束通常可以满足,即B1>=0且(A2 - a1)*t_max+B2>=0。 步骤2的详细实现:分段线性回归(连续)并寻找最优转折点。 我们可以枚举可能的转折点位置(即枚举时间点t0)。对于每一个可能的转折点位置(假设转折点在第k个时间点之后,即前k+1个点属于第一段,后面的点属于第段),然后进行两段线性回归,并保证连续(即在转折点处两段函数值相等)。然后计算整个序列的均方误差(MSE),选择MSE最小的转折点。 具体步骤: 1. 初始化:时间点序列t=[0,2,4,...,2*(n-1)],车流量序列y。 2. 枚举转折点位置k(k从1到n-2,表示转折点在第k个时间点之后,即第一个分段点在第k个点和第k+1个点之间,但为了简化,我们假设转折点就是第k个时间点,即t0 = t[k])。 3. 对于每个k,将数据分为两段:第一段:t[0]到t[k](包括t[k]),第段:t[k+1]到t[n-1](不包括t[k]?注意,连续要求:在t[k]处,第一段函数值等于第段函数值。但第段从t[k+1]开始,所以t[k]不在第段。因此,我们需要将转折点t0设定为t[k],然后第段从t[k]开始?不行,因为这样t[k]就同时属于两段,而且连续条件自然满足(同一个点用两个函数计算应该相等)。但这样会导致第段包含转折点?实际上,我们可以让转折点t0属于第一段,然后第段从t0开始(包括t0)?这样在t0处有两个函数值,需要相等。 为了避免混淆,我们这样定义: 第一段:时间点t[0]到t[k](包括t[k]),共k+1个点。 第段:时间点t[k]到t[n-1](包括t[k]),共n-k个点(注意,t[k]被两个区间包含,但我们在回归时,要求转折点t[k]处两个线性函数的值相等。 因此,对于第一段,我们拟合线性模型:y = A1 * t + B1,使用点(t_i, y_i), i=0..k 对于第段,我们拟合线性模型:y = A2 * t + B2,使用点(t_i, y_i), i=k..n-1 但是,这两个模型在转折点t[k]处可能不相等。因此,我们需要强制连续条件:A1*t[k]+B1 = A2*t[k]+B2。 我们可以通过有约束的最小乘来拟合,但这样比较复杂。另一种方法是:将第段的模型改写为: y = A2*(t - t[k]) + (A1*t[k]+B1) [因为当t=t[k]时,y=A2*(t[k]-t[k])+ (A1*t[k]+B1) = A1*t[k]+B1] 这样,第段模型就强制通过了转折点(t[k], y0),其中y0=A1*t[k]+B1。但这样第一段和第段的参数就耦合了。 因此,我们可以采用以下方法: 首先,对第一段进行线性回归(无约束),得到A1和B1。 然后,计算转折点处的函数值:y0 = A1*t[k] + B1。 再对第段(从t[k]到t[n-1])进行线性回归,但要求回归直线通过点(t[k], y0)。这可以通过将第段的数据点减去(t[k], y0),然后进行过原点的线性回归。具体: 令第段的时间:t'_i = t_i - t[k] (i=k,...,n-1) 令第段的车流量:y'_i = y_i - y0 然后,拟合模型:y'_i = A2 * t'_i (无截距,因为过原点) 所以,A2 = sum(t'_i * y'_i) / sum(t'_i^2) 然后,第段的模型为:y = A2*(t - t[k]) + y0 = A2*t + (y0 - A2*t[k]) 所以,B2 = y0 - A2*t[k] 这样,第段模型在t[k]处自然等于y0,第一段连续。 然后,计算整个序列的均方误差:包括第一段和第段的所有点。注意,在转折点t[k]处,我们有两个模型,但值相同,所以只需计算一次。 枚举每个k(从1到n-2),计算MSE,选择MSE最小的k作为转折点。 步骤3:得到最优的k,以及A1, B1, A2, B2(其中B2由上述计算得到)。 然后,按照前面的方法计算a1=(A1+A2)/2,b1=0(如果满足非负条件,否则调整)。 最后,支路1:f1(t)=a1*t + b1 支路2:在t<=t[k]时,f2(t)= (A1 - a1)*t + B1 - b1 在t>t[k]时,f2(t)= (A2 - a1)*t + B2 - b1 注意:这里t[k]就是转折点t0。 代码实现: 1. 读取Excel文件:使用pandas。 2. 定义时间点:假设有n个数据,时间间隔2分钟,则t = [0, 2, 4, ..., 2*(n-1)] 3. 枚举k,进行分段线性回归(带连续约束),计算MSE。 4. 选择最优k,得到参数。 5. 计算a1, b1,并计算支路2。 注意:在计算第段回归时,我们使用了第一段在转折点的函数值y0,所以第段回归依赖于第一段的结果。因此,如果第一段回归不准确(比如有异常点),可能会影响第段。 另外,我们假设转折点刚好在某个时间点t[k]上。 下面给出代码:</think>### 解决方案:根据主路车流量反推支路车流量函数 #### 问题分析 已知主路3的车流量数据(每2分钟记录一次),支路1车流量呈线性增长,支路2车流量呈先增后减的分段线性趋势。主路车流量等于两支路车流量之和: ``` f3(t) = f1(t) + f2(t) ``` 其中: - 支路1:`f1(t) = a1 * t + b1`(线性增长,a1 > 0) - 支路2:分段线性函数,在转折点`t0`处变化: - 当 `t ≤ t0` 时:`f2(t) = a2 * t + b2`(a2 > 0) - 当 `t > t0` 时:`f2(t) = c2 * t + d2`(c2 < 0) - 连续性约束:`a2 * t0 + b2 = c2 * t0 + d2` #### 算法步骤 1. **数据准备**:读取Excel文件,获取主路车流量序列。 2. **分段线性回归**: - 枚举所有可能的转折点位置(时间点)。 - 对每个候选转折点,将数据分为两段,分别进行线性拟合,并强制连续性约束。 - 计算整体均方误差(MSE),选择MSE最小的转折点。 3. **参数分解**: - 根据分段回归结果,计算支路1的斜率`a1 = (A1 + A2)/2`(折中分配)。 - 计算支路1的截距`b1`,确保两支路车流量非负。 4. **生成支路函数**:根据参数计算两支路车流量函数。 #### Python代码实现 ```python import numpy as np import pandas as pd import matplotlib.pyplot as plt # 1. 读取Excel数据 file_path = r"C:\Users\27489\Desktop\B-支路车流量推测问题 附件(Attachment).xlsx" df = pd.read_excel(file_path, engine='openpyxl') y_main = df['主路3车流量'].values # 主路车流量序列 n = len(y_main) t = np.array([2 * i for i in range(n)]) # 时间点: [0, 2, 4, ..., 2*(n-1)] # 2. 分段线性回归(寻找最优转折点) min_mse = float('inf') best_k = None best_params = None # 存储最优参数(A1, B1, A2, B2) # 枚举转折点位置(k从1到n-2) for k in range(1, n - 1): t0 = t[k] # 候选转折点 # 第一段回归(t[0]到t[k]) t1 = t[:k + 1] y1 = y_main[:k + 1] A1, B1 = np.polyfit(t1, y1, 1) # 线性拟合 # 强制连续性:计算转折点处的函数值 y0 = A1 * t0 + B1 # 第段回归(t[k]到t[n-1]),强制通过(t0, y0) t2 = t[k:] y2 = y_main[k:] t2_shifted = t2 - t0 # 平移时间轴,使转折点为0 y2_shifted = y2 - y0 # 平移车流量 # 过原点的线性回归(斜率A2) A2 = np.sum(t2_shifted * y2_shifted) / np.sum(t2_shifted ** 2) B2 = y0 - A2 * t0 # 计算截距 # 计算整体MSE y_pred = np.concatenate([ A1 * t[:k + 1] + B1, A2 * t[k + 1:] + B2 ]) mse = np.mean((y_main - y_pred) ** 2) # 更新最优结果 if mse < min_mse: min_mse = mse best_k = k best_params = (A1, B1, A2, B2) # 3. 分解支路参数 A1, B1, A2, B2 = best_params t0 = t[best_k] # 最优转折点 # 计算支路1参数(折中分配斜率) a1 = (A1 + A2) / 2 # 计算b1确保非负:b1 ∈ [0, min(B1, (A2 - a1)*t_max + B2)] t_max = t[-1] b1_upper_bound = min(B1, (A2 - a1) * t_max + B2) b1 = max(0, min(0, b1_upper_bound)) # 优先取0,不满足则取边界值 # 计算支路2参数 a2 = A1 - a1 b2 = B1 - b1 c2 = A2 - a1 d2 = B2 - b1 # 4. 定义支路函数 def f1(t): return a1 * t + b1 def f2(t): return np.where(t <= t0, a2 * t + b2, c2 * t + d2) # 5. 可视化结果 plt.figure(figsize=(12, 6)) plt.scatter(t, y_main, label='主路3实测车流量', alpha=0.6) plt.plot(t, f1(t) + f2(t), 'r-', label='模型拟合主路车流量') plt.plot(t, f1(t), 'g--', label='支路1车流量') plt.plot(t, f2(t), 'b--', label='支路2车流量') plt.axvline(x=t0, color='k', linestyle=':', label=f'转折点 t={t0}分钟') plt.xlabel('时间(分钟)') plt.ylabel('车流量') plt.legend() plt.title('支路车流量函数推测结果') plt.grid(True) plt.show() # 输出参数 print(f"支路1函数: f1(t) = {a1:.4f} * t + {b1:.4f}") print(f"支路2函数:") print(f" 当 t ≤ {t0}: f2(t) = {a2:.4f} * t + {b2:.4f}") print(f" 当 t > {t0}: f2(t) = {c2:.4f} * t + {d2:.4f}") print(f"转折点 t0 = {t0}分钟") ``` #### 代码解释 1. **数据读取**: - 使用`pandas`读取Excel文件,提取主路车流量数据。 - 生成时间序列`t = [0, 2, 4, ..., 2*(n-1)]`。 2. **分段线性回归**: - **枚举转折点**:遍历所有可能的分段位置(`k=1`到`k=n-2`)。 - **第一段拟合**:对`t[0]`到`t[k]`的数据进行线性回归,得到斜率`A1`和截距`B1`。 - **连续性约束**:计算转折点`t[k]`处的函数值`y0 = A1*t[k] + B1`。 - **第段拟合**:平移坐标系使`(t[k], y0)`为原点,进行过原点的线性回归,得到斜率`A2`,并反推截距`B2`。 - **评估MSE**:计算整个序列的均方误差,选择最小MSE对应的转折点。 3. **参数分解**: - **支路1斜率**:`a1 = (A1 + A2)/2`(折中分配主路斜率变化)。 - **支路1截距**:`b1`优先取0,若不满足非负约束则取边界值`min(B1, (A2 - a1)*t_max + B2)`。 - **支路2参数**:通过`a2 = A1 - a1`等公式分解,确保支路2在转折点连续。 4. **结果可视化**: - 绘制主路实测数据、模型拟合曲线、两支路车流量曲线和转折点。 #### 注意事项 1. **非负约束**:代码自动确保两支路车流量非负(交通流量的物理意义)。 2. **转折点选择**:枚举法保证找到全局最优转折点,但计算复杂度为O(n)。 3. **线性拟合**:使用`np.polyfit`进行高效的最小乘拟合。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fanstuck

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值