基于粒子群优化算法(PSO)的特征选择

相关文章:

  1. 粒子群优化算法(原理)
  2. 粒子群优化算法(实战)
  3. 使用粒子群优化聚类(实战)

1 理论

许多优化问题设置在一个特征空间,该空间中的变量是离散的,具有定性的差异以及量级差异。典型的例子:求离散元素排序或安排的问题,如调度和路由问题。

除了这些纯粹的组合问题外,研究人员还经常将浮点问题转化为二进制形式,并在离散的数字空间中求解。

不论是离散或连续的问题,都可以用二进制符号表示。一个优化器操作二值函数可能是有利的。

粒子群的工作原理是通过操纵粒子的每个坐标来调整轨迹。该算法在实数函数中取得的一些成功,似乎来自于它“超越”了已知的局部最优,探索了它们之间的界限。

接下来的问题是,在离散空间中,轨迹、速度、间隔和超越这些概念的意义是什么

在二元空间中,粒子可以通过翻转不同数量的位来移动到离超立方体更近或更远的角落。因此,粒子的总体速度可以用每次迭代改变的比特数来描述,也可以用粒子在时间 t t t t + 1 t+1 t+1 之间的汉明距离来描述。

一个零比特的粒子被翻转不移动,而它通过翻转所有的二进制坐标移动到最远。但这并没有回答 v i d v_{id} vid 在二进制函数中对应的问题,也就是说,单个位或坐标的速度或变化率是多少

解决这个难题的方法是根据一个比特处于一种状态或另一种状态的概率变化定义轨迹,速度等。因此,粒子在一个状态空间中移动,在每个维度上限制为0和1,其中每个 v i d v_{i d} vid 表示位 x i d x_{i d} xid 取1的概率

换句话说,如果 v i d = 0.2 v_{i d}=0.2 vid=0.2,那么 x i d x_{i d} xid 为 1 的概率是 20%,为 0 的概率是 80%。

如果之前的最佳位置在该位中有一个 0,那么 ( p i d − x i d ) (p_{i d}-x_{i d}) (pidxid) 可以合理地计算为 -1、0 或 +1,并用于在下一步 v i d v_{i d} vid 的概率变化加权。

v i d = v i d + φ ( p i d − x i d ) + φ ( p g d − x i d ) v_{i d}=v_{i d}+\varphi\left(p_{i d}-x_{i d}\right)+\varphi\left(p_{g d}-x_{i d}\right) vid=vid+φ(pidxid)+φ(pgdxid)

式中, φ \varphi φ 是为每个 i d id id 生成的随机正数,其上限值为系统的参数, p i d p_{i d} pid x i d x_{i d} xid { 0 , 1 } \{0,1\} {0,1} 间的整数, v i d v_{id} vid 是 [0.0,1.0] 之间的概率。

v i d v_{id} vid 通过逻辑转换函数 S ( v i d ) S(v_{id}) S(vid) 计算获取:

S ( x ) = 1 1 + e − x S(x)=\frac{1}{1+e^{-x}} S(x)=1+ex1

由此产生的位置变化由以下规则定义:

X i d = { 0 ,  if  rand ⁡ ( ) ≥ S ( v i d ) 1 ,  if  rand ⁡ ( ) < S ( v i d ) } \begin{aligned} X_{id}=\left\{\begin{array}{ll} 0, & \text { if } \operatorname{rand}() \geq S\left(v_{i d}\right) \\ 1, & \text { if } \operatorname{rand}()<S\left(v_{i d}\right) \end{array}\right\} \end{aligned} Xid={0,1, if rand()S(vid) if rand()<S(vid)}

个人理解:就是将速度转换成了概率,并通过生成随机数与概率相比,得到二元位置。本质上还是随机搜索。

2 实践

PSO特征选择采用的是 pyswarm包中的BinaryPSO():

class pyswarms.discrete.binary.BinaryPSO(n_particles, dimensions, options, init_pos=None, velocity_clamp=None, vh_strategy=‘unmodified’, ftol=-inf, ftol_iter=1)

输入参数:

  • n_particles:整数,粒子群中的粒子数量
  • dimension:整数,空间维度,或特征维度
  • options:系数,字典形式 {‘c1’=2, ‘c2’=2, ‘w’=0.3, ‘k’=4, ‘p’=2},其中 k 表示邻居个数,p 是计算邻居的方式,为[1,2]:1表示绝对值,2表示欧式距离表示

BinaryPSO()的优化方法:

optimize(objective_func, iters, n_processes=None, verbose=True, **kwargs)

输入参数:

  • objective_func (function):自适应函数或损失函数
  • iters (int):迭代次数

返回:

  • tuple:目标函数最优值和最优位置

定义PSO优化器:

import pyswarms as ps
options = {'c1':2, 'c2': 2, 'w':0.3, 'k': 4, 'p': 2}
optimizer = ps.discrete.BinaryPSO(n_particles=20, dimensions=X.shape[1], options=options)
cost, pos = optimizer.optimize(objective, iters=300)

提取特征:

上述返回的 pos值是个二元数据,即由 0 和 1 组成,因此只需提取 pos为1的索引,即为要选的特征索引,具体如下:

feature = np.argwhere(pos == 1).flatten()

得到最优模型:

from sklearn.linear_model import LinearRegression
model = LinearRegression()
best_model = model.fit(X[:, feature], y)

定义目标函数:

在定义目标函数时,需要将每个粒子的值带入模型中训练,然后返回模型的指标值。

这个指标值可以是分类中的准确率或是回归中的均方误差。

具体如下:

from sklearn.datasets import make_regression
from sklearn.model_selection import cross_val_score

cv=3

def objective(param):
    """
    计算每个粒子的均方误差
    param:(n_particles, dim):表示粒子的值, 不需要填入, PSO优化器会自动填入
    """
    scores = np.zeros((n_particles, cv))
    for i in range(n_particles):
        X = X[:, np.argwhere(param[i] == 1).flatten()]
        scores[i] = cross_val_score(model, X, y, scoring='neg_mean_squared_error', cv=cv)
    return -np.mean(scores, axis=1)

查看损失变化:

查看目标函数随迭代增加的变化情况:

from pyswarms.utils.plotters import plot_cost_history
plot_cost_history(cost_history=optimizer.cost_history)

到这里就结束了,只需要把最优模型运用于测试集即可。注意要提取特征。

  • 3
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值