<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`进行高效的最小二乘拟合。
---
###