【问题标题】:How do I do something like numpy where(2darray ==0, 1darray, 1darray)我该怎么做 numpy where(2d array ==0, 1d array, 1d array)
【发布时间】:2020-12-11 23:24:12
【问题描述】:

我正在研究遗传算法的变异函数,但我对 numpy 还很陌生。

默认的变异方法如下所示:

whereMutate = np.random.rand(np.shape(population)[0],np.shape(population)[1])
population[np.where(whereMutate < self.mutationProb)] = 1 - population[np.where(whereMutate < self.mutationProb)]

默认的 mutationprob 设置为 1/染色体长度。种群每行包含一条不同的染色体,染色体长561条,每个位置有0或1。

我试图做的是根据该染色体的 0 和 1 的频率来设置突变概率,这样当一个 1 很少的染色体发生突变时,它就有可能将 0 切换为 1因为它是走另一条路。

目前我有这样的事情:

mProbOne = 0.5/np.count_nonzero(population, axis=1)
mProbZero = 0.5/np.count_nonzero(population == 0, axis=1)
probs = np.where(population == 0, mProbZero, mProbOne)
# Something like the above ought to give me a 2d array 
# with probability of mutation for each position in the chromosome,
# separately for each chromosome
whereMutate = np.random.rand(np.shape(population)[0],np.shape(population)[1]
population[np.where(whereMutate < probs)] = 1-population[np.where(whereMutate < self.mutationProb)]

最后两行与当前存在的两行相同,用于突变概率固定的情况。 我的问题是上面的第 3 行。 mProbZero 和 mProbOne 是 1d numpy 数组。我得到了一个

ValueError: operands could not be broadcast together with shapes (2,5) (2,) (2,)

跟进:下面的代码似乎可以工作,虽然它可能比必要的多 4 行...有什么办法可以更好地做到这一点?

mProbZero = 0.5/np.count_nonzero(population == 0, axis=1)
mProbOne = 0.5/np.count_nonzero(population, axis=1)
probs = np.zeros(np.shape(population))
probs[np.where(population == 0)] = mProbZero[np.where(population == 0)[0]]
probs[np.where(population == 1)] = mProbOne[np.where(population == 1)[0]]
whereMutate = np.random.rand(np.shape(population)[0],np.shape(population)[1])
population[np.where(whereMutate < self.mutationProb)] = 1 - population[np.where(whereMutate < self.mutationProb)]

【问题讨论】:

  • 你了解numpy数组广播吗? where 接受 3 个参数,它们将是标量或数组。如果是数组,它们的形状必须是兼容的——即是可广播的。你有没有看过你切断的shapes...?
  • 我不是很了解它。形状不匹配。它类似于 (nChromosomes, lengthChromosome) 和 (nChromosomes, ) 是否有一个很好的速记来做我想做的事情? :O
  • 这样的事情似乎可行,但我认为可能有更好的方法吗? mProbZero = 0.5/np.count_nonzero(population == 0, axis=1) mProbOne = 0.5/np.count_nonzero(population, axis=1) probs = np.zeros(np.shape(population)) probs[np.where(人口 == 0)] = mProbZero[np.where(人口 == 0)[0]] 概率[np.where(人口 == 1)] = mProbOne[np.where(人口 == 1)[0]]
  • 抱歉,不确定如何在评论中格式化该代码... :(
  • 总是把代码放在有问题的地方,而不是放在评论里。

标签: python numpy genetic-algorithm mutation


【解决方案1】:

具有 (2,1) 值的 (2,3) 条件:

In [470]: np.where(np.array([[1,0,1],[0,1,1]]), np.array([['a'],['b']]), np.array([['c'],['d']]))    
Out[470]: 
array([['a', 'c', 'a'],
       ['d', 'b', 'b']], dtype='<U1')

使用 (3,) 值(通过广播 (1,3)):

In [471]: np.where(np.array([[1,0,1],[0,1,1]]), np.array(['a','b','c']), np.array(['d','e','f']))    
Out[471]: 
array([['a', 'e', 'c'],
       ['d', 'b', 'c']], dtype='<U1')

在这两种情况下,结果形状都与条件匹配。

【讨论】:

  • 好的,谢谢。如此有效地,我需要做的就是将形状从 (2, ) 更改为 (2, 1)? (2, 1) 将是可广播的,因为它与 (5, 2) 具有相同的维度,而 (2, ) 则不是?我还是有点麻木。我需要学会更好地理解这两种形状之间的区别 - (2, 1) 和 (2, )。感谢您为我指明正确的方向。
  • 记住(2,) 是一个单元素元组。这是基本的 Python。 (2,1) 是一个 2 元素元组。因此,在谈论形状时,这就是 1d 和 2d 之间的差异——维度的数量。在numpy 中,数组可以有 0、1、2 或更多维度。数组可以有相同的元素,但它们的形状不同。
  • 啊,对了,明白了!谢谢!我想我只是觉得将 (2,1) 案例视为二维数组有点违反直觉,但我想从描述其形状的元组的角度来看,这确实更有意义。干杯!
【解决方案2】:

我相信您使用的是二进制遗传算法。这意味着在您的突变中,您需要将 1 转换为 0 并将 0 转换为 1。我不知道您的人口是什么样的。 对于一个简单的方法,您可以修改此代码。这里我使用选择随机位置,你可以更改为变异概率。

   def binary_mutation(parent1):
        posi = random.randint(0, len(parent1)-1)
        if parent1[posi] == 1:
            parent1[posi] = 0
        elif parent1[posi] == 0:
            parent1[posi] = 1
        return parent1

【讨论】:

  • 谢谢。我明白了 - 但试图改变概率,以便具有 20 个 1 和 541 个 0 的染色体与 0-> 1 一样可能切换 1->0。这就是为什么我一直在寻找根据当前值设置突变概率的方法。
猜你喜欢
  • 2018-08-25
  • 2022-01-18
  • 2021-05-05
  • 2021-11-01
  • 1970-01-01
  • 2018-05-31
  • 2021-07-28
  • 2018-12-23
  • 2021-02-13
相关资源
最近更新 更多