我正在尝试针对最小向量覆盖率遗传算法对我的适应度函数进行矢量化处理,但是我对此却一无所知。
目前情况:
vert_cover_fitness = [1 if self.dna[edge[0]] or self.dna[edge[1]] else -num_edges for edge in edges]
dna
是大小为[0..n]
的一维 binary 数组,其中每个索引对应一个顶点,其值指示是否选择了顶点。 edges
是一个二维正整数数组,其中每个值对应于dna
中的一个顶点(索引)。两者都是ndarray
。
简单解释-如果“选择”了一条由边连接的顶点之一,那么我们得到的分数为1。如果不是,则该功能将受到-num_edges
的惩罚。
我尝试过 np.vectorize
,目的是通过lambda函数摆脱便宜:
fit_func = np.vectorize(lambda edge: 1 if self.dna[edge[0]] or self.dna[edge[1]] else -num_edges)
vert_cover_fitness = fit_func(edges)
这将返回IndexError: invalid index to scalar variable.
,因为此函数将应用于每个值,而不是应用于每一行。
为解决此问题,我尝试了np.apply_along_axis
。这行得通,但它只是循环的包装器,因此我没有得到任何提速。
如果任何Numpy向导都可以看到一些明显的方法来完成此操作,非常感谢您的帮助。我猜想问题在于问题的表示形式,并且更改dna
或edges
的形状可能会有所帮助。我只是不够熟练,无法知道应该怎么做。
答案 0 :(得分:3)
我想出了一些numpy代码,它对我随机生成的数据的运行速度比for循环快30倍。
import numpy as np
num_vertices = 1000
num_edges = 500
dna = np.random.choice([0, 1], num_vertices)
edges = np.random.randint(0, num_vertices, num_edges * 2).reshape(-1, 2)
vert_cover_fitness1 = [1 if dna[edge[0]] or dna[edge[1]] else -num_edges for edge in edges]
vert_cover_fitness2 = np.full([num_edges], -num_edges)
mask = (dna[edges[:, 0]] | dna[edges[:, 1]]).astype(bool)
vert_cover_fitness2[mask] = 1.0
print((vert_cover_fitness1 == vert_cover_fitness2).all()) # this shows it's correct
这是用于测量加速的时间代码。
import timeit
setup = """
import numpy as np
num_vertices = 1000
num_edges = 500
dna = np.random.choice([0, 1], num_vertices)
edges = np.random.randint(0, num_vertices, num_edges*2).reshape(-1, 2)
"""
python_loop = "[1 if dna[edge[0]] or dna[edge[1]] else -num_edges for edge in edges]"
print(timeit.timeit(python_loop, setup, number=1000))
vectorised="""
vert_cover_fitness2 = np.full([num_edges], -num_edges)
mask = (dna[edges[:, 0]] | dna[edges[:, 1]]).astype(bool)
vert_cover_fitness2[mask] = 1.0
"""
print(timeit.timeit(vectorised, setup, number=1000))
# prints:
# 0.375906624016352
# 0.012783741112798452