文章目录
- 一、概述
- 二、算法原理
- 三、python实现
一、概述
人工蜂群算法(Artificial Bee Colony Algorithm, 简称ABC算法)是一个由蜂群行为启发的算法,在2005年由Karaboga小组为优化代数问题而提出。方法人工蜂群算法是模仿蜜蜂行为提出的一种优化方法,是集群智能思想的一个具体应用,它的主要特点是不需要了解问题的特殊信息,只需要对问题进行优劣的比较,通过各人工蜂个体的局部寻优行为,最终在群体中使全局最优值突现出来,有着较快的收敛速度。
二、算法原理
人工蜂群算法网上教程比较多,我就不再抄书了,推荐大家读一下简书大佬的讲解人工蜂群算法。我和他的观点一致,蜜蜂之间如何转换,按照何种策略从侦查蜂中选择采蜜蜂等等,对算法的性能和结果影响都不大。基于这个思考,在编程中,我们着重关注蜜源,就可以清晰明了的理清楚思绪,并完成相关算法。
三、python实现
# 定义待优化函数
def function(position):
x = position[0]
y = position[1]
# 待优化函数表达式
z = -20*np.exp(-0.2*np.sqrt((x**2+y**2)/2))- \
np.exp((np.cos(2*np.pi*x)+np.cos(2*np.pi*y))/2)+20+np.e
return z
我们可以先看一下这个函数的图形。
bounds = np.array([[-10, -10], [10, 10]])
x = np.linspace(bounds[0, 0], bounds[1, 0], 1000)
y = np.linspace(bounds[0, 1], bounds[1, 1], 1000)
X,Y=np.meshgrid(x,y)
Z = -20*np.exp(-0.2*np.sqrt((X**2+Y**2)/2))-np.exp((np.cos(2*np.pi*X)+np.cos(2*np.pi*Y))/2)+20+np.e
fig=plt.figure()
ax=plt.axes(projection='3d')
ax.plot_surface(X,Y,Z,cmap='rainbow')
plt.show()
我们主要定义一下蜜源以及蜜源的评价体系。记住每个蜜源对应一个引导蜂(也有叫雇佣蜂的),同时它在搜寻新蜜源的时候称为侦查蜂,其余的全是雇佣蜂。这些蜜蜂怎么飞怎么转换,不要去关注,没有意义。
# 定义蜜源
class Nectar:
# 初始化
def __init__(self, position):
# 蜜源位置
self.position=position
# 采蜜者数量(包含引领蜂)
self.follower_counts = 1
# 历史采蜜者数量
self.counts_history = 1
# 跟随蜂采蜜则增加采蜜者数量
def add_Followers(self):
self.follower_counts += 1
# 放弃采蜜
def cal_give_up_rate(self):
self.give_up_rate = self.counts_history / self.follower_counts - 1
return self.give_up_rate
# 更新蜜源(flag=True,代表蜜源位置更新)
def refresh(self, flag=True):
# 如位置不更新,需保存前一次采蜜者数量
if ~flag:
self.counts_history = self.follower_counts
# 重置该蜜源采蜜者数量
self.follower_counts = 1
# 蜜源评价及更新
class Evaluate:
def __init__(self, function):
self.function = function
# 待优化函数
def cal_function(self, position):
z = self.function(position)
return z
# 计算适应度值
def cal_fitness(self, nectar_group):
# 计算函数值
values = [self.cal_function(_nectar.position) for _nectar in nectar_group]
# 计算适应度函数
fitness = [(_value>0) and (1/(1+_value)) or (1+np.abs(_value))
for _value in values]
return fitness
# 计算各蜜源被选中的概率
def cal_possibility(self, nectar_group):
# 计算适应度函数
fitness = self.cal_fitness(nectar_group)
possibility = [_fitness/np.sum(fitness) for _fitness in fitness]
return possibility
# 蜜源吸引跟随蜂
def evaluate_nectar_grop(self, nectar_group, number_flowers):
# 计算各蜜源被选中的概率
possibility = evaluate.cal_possibility(nectar_group)
# 跟随蜂开始工作
for i in range(number_flowers):
poss = 0
# 生成随机数
rand_poss = np.random.random()
# 跟随蜂随机进入蜜源开始采蜜
for i, _poss in enumerate(possibility):
poss += _poss
if poss > rand_poss:
# 蜜源跟随蜂数量增加
nectar_group[i].add_Followers()
return nectar_group
以下是主程序,代码中未关注蜜蜂是如何飞来飞去的,因为真的不重要。建议大家对照着算法看代码,简单明了。
if __name__ == '__main__':
# 定义蜂群规模
bee_population = 100
# 定义引领蜂比例
guider_rate = 0.3
# 定义搜索次数
iteration = 100
# 定义搜寻范围
bounds = np.array([[-10, -10], [10, 10]])
# 初始化蜜源以及引领蜂位置
init_position = np.random.uniform(low=bounds[0,:], high=bounds[1,:],
size=(int(bee_population*guider_rate), bounds.shape[1]))
# 定义蜜源初始位置
nectar_group = []
for _position in init_position:
# 引领蜂找到蜜源
_nectar = Nectar(_position)
# 将该蜜源加入蜜源大家庭
nectar_group.append(_nectar)
# 向蜜源传入待优化函数
func = function
evaluate = Evaluate(func)
# 开始进入循环
_iteration = 0
while _iteration != iteration:
# 跟随蜂开始选择蜜源
nectar_group = evaluate.evaluate_nectar_grop(nectar_group,
bee_population - len(nectar_group))
# 引领蜂开始工作
for i,_nectar in enumerate(nectar_group):
# 若该蜜源无跟随蜂,引领蜂需寻找下一个蜜源
flag1 = _nectar.follower_counts == 1
# 若该蜜源在上一轮被跟随蜂放弃的概率大于50%,引领蜂需寻找下一个蜜源
flag2 = _nectar.cal_give_up_rate() > 0.5
# 此外,引领蜂有30%的概率,不安于现状,开始搜索新的蜜源
flag3 = np.random.random() <= 0.3
if((flag1 | flag2) | flag3):
# 计算该蜜源函数值
z = evaluate.cal_function(_nectar.position)
# 引领蜂连续搜索30次
search_count = 0
while search_count != 30:
# 搜索新的蜜源
rand_nectar = np.random.choice(nectar_group)
new_position = _nectar.position + np.random.random()*\
(rand_nectar.position - _nectar.position)
# 计算新蜜源的函数值
new_z = evaluate.cal_function(new_position)
# 若新蜜源函数值更小,则替换最优值
good_z, good_position = (new_z < z) and \
(new_z, new_position) or (z, _nectar.position)
search_count += 1
# 若搜索30次后发现更好的蜜源则进行蜜源替换
if good_z < z:
_nectar.position = good_position
_nectar.refresh(flag = True)
# 若未替换蜜源,对蜜源内的跟随蜂数量置零
else:
_nectar.refresh(flag = False)
_iteration += 1
# 展示迭代过程
if _iteration % 10 == 0:
position_group = [_nectar.position for _nectar in nectar_group]
position_group = np.array(position_group).flatten().reshape([-1, 2])
plt.scatter(position_group[:,0], position_group[:,1])
plt.xlim((-10,10))
plt.ylim((-10,10))
plt.show()