我在设计适合于pyswarms的适应功能时遇到麻烦,该功能实际上会遍历粒子。我基于这个(有效的)示例代码进行设计:
# import modules
import numpy as np
# create a parameterized version of the classic Rosenbrock unconstrained optimzation function
def rosenbrock_with_args(x, a, b, c=0):
f = (a - x[:, 0]) ** 2 + b * (x[:, 1] - x[:, 0] ** 2) ** 2 + c
return f
from pyswarms.single.global_best import GlobalBestPSO
# instatiate the optimizer
x_max = 10 * np.ones(2)
x_min = -1 * x_max
bounds = (x_min, x_max)
options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9}
optimizer = GlobalBestPSO(n_particles=10, dimensions=2, options=options, bounds=bounds)
# now run the optimization, pass a=1 and b=100 as a tuple assigned to args
cost, pos = optimizer.optimize(rosenbrock_with_args, 1000, a=1, b=100, c=0)
kwargs={"a": 1.0, "b": 100.0, 'c':0}
似乎通过编写
x[:, 0]
和x[:, 1]
,可以以某种方式为优化函数参数化粒子位置矩阵。例如,在调试器中执行x[:, 0]
将返回:array([ 9.19955426, -5.31471451, -2.28507312, -2.53652044, -6.29916204, -8.44170591, 7.80464884, -6.42048159, 9.77440842, -9.06991295])
现在,跳到我的代码(摘录),我有这个:
def optimize_eps_and_mp(x):
clusterer = DBSCAN(eps=x[:, 0], min_samples=x[:, 1], metric="precomputed")
clusterer.fit(distance_matrix)
clusters = pd.DataFrame.from_dict({index_to_gid[i[0]]: [i[1]] for i in enumerate(clusterer.labels_)},
orient="index", columns=["cluster"])
settlements_clustered = settlements.join(clusters)
cluster_pops = settlements_clustered.loc[settlements_clustered["cluster"] >= 0].groupby(["cluster"]).sum()["pop_sum"].to_list()
print()
return 1
options = {'c1': 0.5, 'c2': 0.3, 'w':0.9}
max_bound = [1000, 10]
min_bound = [1, 2]
bounds = (min_bound, max_bound)
n_particles = 10
optimizer = ps.single.GlobalBestPSO(n_particles=n_particles, dimensions=2, options=options, bounds=bounds)
cost, pos = optimizer.optimize(optimize_eps_and_mp, iters=1000)
(变量
distance_matrix
和settlements
是在代码前面定义的,但是在clusterer = DBSCAN(eps=x[:, 0], min_samples=x[:, 1], metric="precomputed")
行上失败,因此它们不相关。此外,我知道它总是返回1
,我只是在完成功能之前尝试使其无错误运行)当我在调试器中执行
x[:, 0]
时,它返回:array([-4.54925788, 3.94338766, 0.97085618, 9.44128746, -2.1932764 , 9.24640763, 9.18286758, -8.91052863, 0.637599 , -2.28228841])
因此,在结构上与工作示例相同。但是它在行
clusterer = DBSCAN(eps=x[:, 0], min_samples=x[:, 1], metric="precomputed")
上失败,因为它会将x[:, 0]
的全部内容传递给DBSCAN
函数,而不是像在工作示例中那样将其参数化。我只是看不到这些示例之间有什么区别?
我还试图将适应性函数从工作示例(
rosenbrock_with_args
)粘贴到我的代码中,并对其进行优化,以消除任何可能设置实现的方式不正确的可能性。然后,该解决方案会像往常一样收敛,因此我完全无法理解为什么它不能与我的功能配合使用(optimize_eps_and_mp
)我得到的确切stacktrace指的是dbscan算法中的错误,我假设由于某种原因,它被传递了整个粒子群值集而不是单个值:
pyswarms.single.global_best: 0%| |0/1000Traceback (most recent call last):
File "C:/FILES/boates/work_local/_code/warping-pso-dbscan/optimize_eps_and_mp.py", line 63, in <module>
cost, pos = optimizer.optimize(optimize_eps_and_mp, iters=1000)
File "C:\FILES\boates\Anaconda\envs\warping_pso_dbscan\lib\site-packages\pyswarms\single\global_best.py", line 184, in optimize
self.swarm.current_cost = compute_objective_function(self.swarm, objective_func, pool=pool, **kwargs)
File "C:\FILES\boates\Anaconda\envs\warping_pso_dbscan\lib\site-packages\pyswarms\backend\operators.py", line 239, in compute_objective_function
return objective_func(swarm.position, **kwargs)
File "C:/FILES/boates/work_local/_code/warping-pso-dbscan/optimize_eps_and_mp.py", line 38, in optimize_eps_and_mp
clusterer.fit(distance_matrix)
File "C:\FILES\boates\Anaconda\envs\warping_pso_dbscan\lib\site-packages\sklearn\cluster\dbscan_.py", line 351, in fit
**self.get_params())
File "C:\FILES\boates\Anaconda\envs\warping_pso_dbscan\lib\site-packages\sklearn\cluster\dbscan_.py", line 139, in dbscan
if not eps > 0.0:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
pyswarms.single.global_best: 0%| |0/1000
最佳答案
TL; DR
粒子群优化使用批处理。
给定一批粒子,优化函数必须返回一批成本。
错误信息说明
这是错误消息的有趣部分:
[...]
File "C:\FILES\boates\Anaconda\envs\warping_pso_dbscan\lib\site-packages\sklearn\cluster\dbscan_.py", line 139, in dbscan
if not eps > 0.0:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
这是一个非常常见的Numpy错误消息。
当您尝试使用数组作为条件时,它会出现。
如该消息所述,truth value是什么
像
[True, False]
这样的数组。您必须使用
all()
之类的功能或
any()
将您的数组转换为单个布尔值。
那么,为什么会这样呢?
因为
eps
不能用作数组。从
DBSCAN
class的文档中,参数
eps
和min_samples
是可选的整数。在这里,您将它们传递给数组。
clusterer = DBSCAN(eps=x[:, 0], min_samples=x[:, 1], metric="precomputed")
实例比较
您问为什么代码可以与
rosenbrock_with_args
函数一起使用。那是因为它执行可以很好地处理数组的操作。
您将其传递为形状为
x
(尺寸为2的10个粒子)和[10, 2]
标量的二维数组a, b, c
(粒子批)。据此,它计算形状为
[10]
的一维数组,这是每个粒子的成本值。但是,您的新
optimize_eps_and_mp
函数尝试对阵列执行一些不支持的操作。特别是,将数组的一维用作
eps
的DBSCAN
参数,该参数需要标量。为了使它起作用,您应该自己处理批处理,并实例化许多
DBSCAN
对象:for row in x:
clusterer = DBSCAN(eps=row[0], min_value=row[1], [...])
分布式执行
You said
那:
pyswarms
库应该独立运行多次([目标函数])(针对群中的每个粒子)并评估其结果,并且通过某种方式将函数一次分配给多个输入集来做到这一点。pyswarm
实际上可以将群执行与n_processes
的optimize
参数并行化功能。
在这种情况下,您的函数在不同的过程中被多次调用,但仍将数组作为输入。
在您的情况下,具有10个粒子,2个维度和
n_processes
作为None
(默认值),您的x
输入的形状为[10, 2]
。如果将
n_processes
设置为2,则您的x
输入将具有形状[5, 2]
。最后,如果将
n_processes
设置为10,则您的x
输入将具有形状[1, 2]
。无论哪种情况,都必须“展开”粒子群以进行
DBSCAN
实例化。import pyswarms as ps
def foo(x):
print(x.shape)
return x[:,0]
if __name__ == "__main__":
options = {'c1': 0.5, 'c2': 0.3, 'w': 0.9}
max_bound = [1000, 10]
min_bound = [1, 2]
bounds = (min_bound, max_bound)
n_particles = 10
optimizer = ps.single.GlobalBestPSO(n_particles=n_particles, dimensions=2, options=options, bounds=bounds)
for n_processes in [None, 1, 2, 10]:
print("\nParallelizing on {} processes.".format(n_processes))
optimizer.optimize(foo, iters=1, n_processes=n_processes)
Parallelizing on None processes.
(10, 2)
Parallelizing on 1 processes.
(10, 2)
Parallelizing on 2 processes.
(5, 2)
(5, 2)
Parallelizing on 10 processes.
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)
(1, 2)
因此,这是有关如何使用
DBSCAN
的完整示例。def optimize_eps_and_mp(x):
num_particles = x.shape[0]
costs = np.zeros([num_particles])
print("Particles swarm", x)
for idx, particle in enumerate(x):
print("Particle", particle)
clusterer = DBSCAN(eps=x[0], min_samples=x[1], metric="precomputed")
clusterer.fit(distance_matrix)
clusters = pd.DataFrame.from_dict({index_to_gid[i[0]]: [i[1]] for i in enumerate(clusterer.labels_)},
orient="index", columns=["cluster"])
settlements_clustered = settlements.join(clusters)
cluster_pops = settlements_clustered.loc[settlements_clustered["cluster"] >= 0].groupby(["cluster"]).sum()["pop_sum"].to_list()
cost = 1 # Update this to compute cost value of the current particle
costs[idx] = cost
return costs
关于python - 在热战中无法正确参数化粒子位置,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59106677/