fisher分割(python实现)–交通信控时段划分
本文重点参考该篇博文:
【版权声明:本文为CSDN博主「Trisyp」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明】
【原文链接:https://blog.csdn.net/Trisyp/article/details/118492913】
一、理论知识
1.1、Fisher最优分割法概念及重要指标
最优分割法
是对有序样本的一种聚类方法,例如 N N N个样品按顺序排列 { x 1 , x 2 , . . . x N } \{x_1,x_2,...x_N\} {x1,x2,...xN},在分类中不允许打破样本的顺序。即 N N N个有序样本进行分割,可能有 2 N − 1 2^{N-1} 2N−1种划分方式:N=2时,有2种划分( 2 1 2^1 21,表示该样本是否加入前面的划分);N=3时,有4种划分( 2 2 2^2 22)种划分方法,这每一种分法称为一种分割。
在所有的这些分割中,找到一种分割法,这种分割法使得各组内样品之间的差异最小,而各组之间的差异最大。这种对 N N N个样品分组并使组内差异最小的分割方法,称为最优分割法。
对于第
k
k
k组样本
{
x
i
,
x
i
+
1
.
.
.
x
j
}
\{x_i,x_{i+1}...x_j\}
{xi,xi+1...xj},组内样本差异计算公式如下(求组内样本均值,然后计算方差):
d
i
j
=
∑
k
s
=
i
j
[
x
k
s
−
x
k
ˉ
(
i
,
j
)
]
2
d_{ij}=\sum_{k_s=i}^{j}[{x_{k_s}}-\bar{x_k}{(i,j)}]^2
dij=ks=i∑j[xks−xkˉ(i,j)]2
x k ˉ ( i , j ) = 1 j − i + 1 ∑ k s = i j x k s \bar{x_k}{(i,j)}=\frac{1}{j-i+1}\sum_{k_s=i}^{j}x_{k_s} xkˉ(i,j)=j−i+11ks=i∑jxks
Fisher最优分割法
Fisher最优分割法是用离差平方和来表示同类样本之间的差异程度(可以称为该组的直径 D ( i , j ) D{(i,j)} D(i,j),与 d i , j d_{i,j} di,j计算公式相同,也可以采用其他的距离度量方式,例如计算各个样本与样本中位数的差异),通过迭代计算,确定最优分类数,使同类样本间的差异最小,各类别样本间的差异最大。
1.2、Fisher最优分割递推公式及计算流程
用 b ( N , K ) b(N,K) b(N,K)表示将 N N N个有序样本分为 K K K类的一种方法,定义损失函数为 L [ b ( N , K ) ] = ∑ k = 1 K D k ( i , j ) L[b(N,K)]=\sum_{k=1}^{K}D_k(i,j) L[b(N,K)]=∑k=1KDk(i,j)
使损失函数最小的分类方法即为最优分割,记为 P ( N , K ) P(N,K) P(N,K)。
计算流程
目标:对于 N N N个有序样本,分类数 K K K已知,求最优分割方法 P ( N , K ) P(N,K) P(N,K)
算法流程:
- 对于最优分割 L [ P ( N , K ) ] L[P(N,K)] L[P(N,K)],最右侧的类别 K K K的直径为 D ( 1 , N ) D(1,N) D(1,N),则最优分割的损失函数可以写成: L [ P ( N , K ) ] = m i n k ≤ j ≤ N { L [ P ( j − 1 , K − 1 ) ] + D ( j , N ) } L[P(N,K)]=min_{k{\leq}j{\leq}N}\{L[P(j-1,K-1)]+D(j,N)\} L[P(N,K)]=mink≤j≤N{L[P(j−1,K−1)]+D(j,N)},其中 L [ P ( j − 1 , K − 1 ) ] L[P(j-1,K-1)] L[P(j−1,K−1)]表示对前面 j − 1 j-1 j−1个样本划分为 K − 1 K-1 K−1类的最优分割;
- 采用该公式可依次往前递推,确定各个类别的最优分割;
- 确定 N N N个样本划分为一类( K = 1 K=1 K=1)的损失函数及最优分割: L [ P ( N , 1 ) ] = L [ b ( N , 1 ) ] = D ( 1 , N ) L[P(N,1)]=L[b(N,1)]=D(1,N) L[P(N,1)]=L[b(N,1)]=D(1,N);
举例说明:
L [ P ( 3 , 2 ) ] = m i n { L [ P ( 1 , 1 ) ] + D ( 2 , 3 ) , L [ P ( 2 , 1 ) ] + D ( 3 , 3 ) } L[P(3,2)]=min\{L[P(1,1)]+D(2,3),L[P(2,1)]+D(3,3)\} L[P(3,2)]=min{L[P(1,1)]+D(2,3),L[P(2,1)]+D(3,3)}
可参考LeetCode中的动态规划相关题目:
题目:剑指 Offer II 101. 分割等和子集
描述:给定一个非空的正整数数组 n u m s nums nums ,请判断能否将这些数字分成元素和相等的两部分。
题解链接(动态规划求解):https://leetcode.cn/problems/NUPfPr/solutions/1417796/fen-ge-deng-he-zi-ji-by-leetcode-solutio-re1t/
二、应用场景
2.1、交通信控时段划分
大多数交叉口全天交通流量是不断变化的,一般可主观划分为八个时段:早平峰、早高峰、上午平峰、中午闲散、下午平峰、晚高峰、晚平峰、夜间闲散。一般早晚高峰时期的交通流量大于其他时段,如果全天采用同一套定时配时方案很难适应路口交通量的变化,使交叉口在局部时间内出现拥堵或空放现象。因此,为保障交叉口的有效通行,应在不同时段应采用不同信号控制策略及配时方案。
基于交通流量的时段划分,可以看成是有序序列的分割问题,核心是找到一组分割,使得组内方差最小,组间方差最大。Fisher最优分割法是常用的交通信控时段划分算法:一般以5分钟为间隔统计交通流量作为一个样本,即全天共有288个样本( N = 288 N=288 N=288),分类数 K K K未知,可以通过比较 K K K取不同值的损失函数值确定最优分类数(类似于K-means聚类通过“肘形图”确定聚类数:http://t.csdn.cn/eRMaj)
三、代码精讲
计算组内样本均值及直径
def get_class_ave(samples, start, end):
"""
计算某一类的均值
:param samples: 所有输入数据
:param start: 某一类的开始索引(包含)
:param end: 某一类的结束索引(不包含)
:return:
"""
class_ave = 0.0
for i in range(start, end):
class_ave += samples[i]
class_ave = class_ave / (end - start)
return class_ave
def get_class_diameter(samples, start, end):
"""
计算某一类的直径(类内各样本的差异)
:param samples: 所有输入数据
:param start: 某一类的开始索引(包含)
:param end: 某一类的结束索引(不包含)
:return:
"""
class_diameter = 0.0
class_ave = get_class_ave(samples, start, end)
for i in range(start, end):
class_diameter += (samples[i] - class_ave) ** 2
return class_diameter
计算不同样本采取不同分割的损失函数值
def get_split_loss(samples, sample_num, split_class_num):
"""
计算得到不同样本划分为不同分类的loss矩阵
:param samples: 样本
:param sample_num: 样本数
:param split_class_num: 最大分类数
:return: 不同样本划分为不同分类的loss矩阵
"""
# 记录不同样本数(1~sample_num)分成不同类(1~split_class_num)的loss值
split_loss_result = np.zeros((sample_num + 1, split_class_num + 1))
# 对于第一列k=1
for n in range(1, sample_num + 1):
# 将所有样本分成1类,直接调用函数get_class_diameter计算
# 递推公式L(P(n,1))=D(1,n),其中P(n,1)表示将n个样本分成1类的最优划分,D(1,n)表示所有样本的差异
# 该式表示将n个样本分成1类的损失函数值L=该类的直径D(类内各样本的差异)
split_loss_result[n, 1] = get_class_diameter(samples, 0, n)
# 使用递推公式计算k>1时采取不同划分的损失函数值
for k in range(2, split_class_num + 1):
# n不能小于k
for n in range(k, sample_num + 1):
# 递推公式:L(P(n,k))=min{L(P(j-1,k-1))+D(j,n)}
# 其中,k<=j<=n,要保证前面每一类都至少有一个样本(j>=k),最后一类至少有一个样本(j<=n)
loss = []
for j in range(k - 1, n):
loss.append(split_loss_result[j, k - 1] + get_class_diameter(samples, j, n))
split_loss_result[n, k] = min(loss)
return split_loss_result
确定样本分类信息
def get_split_info(samples, split_loss_result):
"""
确定最佳分类数、分类点、各个样本的类别
:param samples: 样本
:param split_loss_result: loss矩阵
:return: 最佳分类数、分类点、各个样本的类别
"""
# 首先确定最优分类数k_best
# 以增加一个分类后loss下降不足30%(需多次尝试不同值比较分类效果)作为阈值确定k_best
loss_n_k = split_loss_result[-1, 1:]
k_best = 1
for i in range(len(loss_n_k) - 1):
# 对于loss为0的情况,直接确定k_best
if loss_n_k[i] == 0:
k_best = i + 1
break
else:
desc_rate = (loss_n_k[i] - loss_n_k[i + 1]) / loss_n_k[i]
if desc_rate > 0.05:
k_best = i + 2
# 确定各个样本所属类别
split_point = []
k = k_best - 1
n = len(samples)
split_loss = split_loss_result[n][k_best]
while k > 0:
while n > 0:
# 寻找类别划分点
if split_loss_result[n][k] < split_loss:
split_point.insert(0, n)
split_loss = split_loss_result[n][k]
break
n -= 1
k -= 1
# 确定样本类别
sample_class = []
class_index = 1
point_index = 0
# split_point中补充完整
# 举例:split_point = [6],有9个样本,则补充完整的split_point = [1, 6, 9]
split_point.insert(0, 1)
split_point.append(len(samples))
for i in range(len(samples)):
if i < split_point[point_index + 1]:
sample_class.append(class_index)
else:
point_index += 1
class_index += 1
sample_class.append(class_index)
return k_best, split_point, sample_class
测试样例
测试样本:[5, 6, 7, 1, 2, 1, 10, 11, 12]
计算得到损失函数值矩阵为
可确定最佳分类数、分割点、各个样本所属类别
四、后续研究方向
针对交通信控时段划分算法提出以下几点研究方向:
- 时段过短则方案变化、过渡过于频繁会导致控制效果不佳:要求每个时段必须包含一定的样本量(例如要求时段至少为15分钟,则需要至少包含3个样本(以5分钟为统计间隔的话));
- 允许指定时段,例如7:00-7:30指定为一个时段,设置了专属的控制策略,则可以对于指定时段前后的时段进行划分,再合并时段;
- 时段划分考虑相邻交叉口,即对同一子区内的交叉口进行时段划分。
五、参考链接:
完整代码及数据可在此处下载:
[1] https://download.csdn.net/download/weixin_42639395/87929803
Fisher分割相关:
[2] https://blog.csdn.net/Trisyp/article/details/118492913
动态规划相关:
[3] https://leetcode.cn/problems/NUPfPr/solutions/1417796/fen-ge-deng-he-zi-ji-by-leetcode-solutio-re1t/
交通信控时段划分相关:
[4] https://zhuanlan.zhihu.com/p/619567481
[5] 袁淑芬. 基于过车数据的单点交叉口多时段信号配时优化[D].东南大学,2019.DOI:10.27014/d.cnki.gdnau.2019.003104.