【问题标题】:Pythonic way to sparsely randomly populate array?Pythonic 稀疏随机填充数组的方法?
【发布时间】:2013-11-10 08:29:48
【问题描述】:

问题: 用 10 个 1、20 个 2、30 个 3 随机填充一个 10 x 10 的零数组。

我实际上不必使用数组,我只需要值所在位置的坐标。就数组而言,它更容易理解。

我为此编写了几个解决方案,但它们似乎都不是直截了当且非 Python 的。我希望有人能给我一些见解。我的方法一直使用 0--99 的线性数组,随机选择 (np.random.choice) 10 个值,从数组中删除它们,然后选择 20 个随机值。之后,我将线性位置转换为 (y,x) 坐标。

import numpy as np

dim = 10
grid = np.arange(dim**2)

n1 = 10
n2 = 20
n3 = 30

def populate(grid, n, dim):
    pos = np.random.choice(grid, size=n, replace=False)
    yx = np.zeros((n,2))
    for i in xrange(n):
        delPos = np.where(grid==pos[i])
        grid = np.delete(grid, delPos)
        yx[i,:] = [np.floor(pos[i]/dim), pos[i]%dim]
    return(yx, grid)

pos1, grid = populate(grid, n1, dim)
pos2, grid = populate(grid, n2, dim)
pos3, grid = populate(grid, n3, dim)

额外 假设当我填充 1 时,我希望它们都在“数组”的一半上。我可以使用我的方法(从 grid[dim**2/2:] 采样)来做到这一点,但我还没有弄清楚如何对其他建议做同样的事情。

【问题讨论】:

    标签: python arrays random


    【解决方案1】:

    不确定这是否不再是“pythonic”,但这是我使用 Simeon 的部分答案想出的。

    import random
    
    dim = 10
    n1 = 10
    n2 = 20
    n3 = 30
    
    coords = [[i,j] for i in xrange(dim) for j in xrange(dim)]
    
    def setCoords(coords, n):
        pos = []
        for i in xrange(n):
            random.shuffle(coords)
            pos.append(coords.pop())
        return(coords, pos)
    
    coordsTmp, pos1 = setCoords(coords[dim**2/2:], n1)
    coords = coords[:dim**2/2] + coordsTmp
    coords, pos2 = setCoords(coords, n2)
    coords, pos3 = setCoords(coords, n3)
    

    【讨论】:

      【解决方案2】:

      要生成数组,可以使用numpy.random.choice

      np.random.choice([0, 1, 2, 3], size=(10,10), p=[.4, .1, .2, .3])
      

      然后就可以转换成坐标了。请注意,numpy.random.choice 使用概率p 生成随机样本,因此不能保证您得到p 中的准确比例。

      额外

      如果您想将所有1s 放在数组的特定一侧,您可以生成两个随机数组,然后生成hstack 它们。诀窍是稍微修改每一边每个数字的概率。

      In [1]: import numpy as np
      In [2]: rem = .1/3 # amount to de- / increase the probability for non-1s
      In [3]: A = np.random.choice([0, 1, 2, 3], size=(5, 10),
                                    p=[.4-rem, .2, .2-rem, .3-rem])
      In [4]: B = np.random.choice([0, 2, 3], size=(5, 10), p=[.4+rem, .2+rem, .3+rem])
      In [5]: M = np.hstack( (A, B) )
      In [6]: M
      Out[1]: 
      array([[1, 1, 3, 0, 3, 0, 0, 1, 1, 0, 2, 2, 0, 2, 0, 2, 3, 3, 2, 0],
             [0, 3, 3, 3, 3, 0, 1, 3, 1, 3, 0, 2, 3, 0, 0, 0, 3, 3, 2, 3],
             [1, 0, 0, 0, 1, 0, 3, 1, 2, 2, 0, 3, 0, 3, 3, 0, 0, 3, 0, 0],
             [3, 2, 3, 0, 3, 0, 1, 2, 3, 2, 0, 0, 0, 0, 3, 2, 0, 0, 0, 3],
             [3, 3, 0, 3, 3, 3, 1, 3, 0, 3, 0, 2, 0, 2, 0, 0, 0, 3, 3, 3]])
      

      这里,因为我将 all 1s 放在左侧,所以我将 1 的概率加倍,并平均降低每个数字的概率。创建另一边时也适用相同的逻辑。

      【讨论】:

      • 哇,尽管我之前使用过 p 参数,但我从未想过在这个应用程序中使用它。您的解决方案简单而雄辩,谢谢!
      • 我认为 p[0] 应该是 0.4
      • @mititan8:我在我的问题中添加了一个额外的内容,我正在尝试弄清楚如何修改您的答案,以便它在这种情况下工作。你有什么建议吗?
      • 实际上,这种方法不会给你确切的 10 个 1、20 个 2、30 个 3 - 它只会保持这些概率的平均值。要检查,请计算您获得的数组中的出现次数。如果您需要确切的数字,您应该使用 Simeon 的方法
      • @ngimel:好点,我已经更新了我的答案,让这一点显而易见。
      【解决方案3】:

      您可以创建所有坐标的列表,shuffle 该列表并取其中的前 60 个 (10 + 20 + 30):

      >>> import random
      >>> coordinates = [(i, j) for i in xrange(10) for j in xrange(10)]
      >>> random.shuffle(coordinates)
      >>> coordinates[:60]
      [(9, 5), (6, 9), (1, 5), ..., (0, 2), (5, 9), (2, 6)]
      

      然后您可以使用前 10 个插入 10 个值,接下来的 20 个插入 20 个值,其余的插入 30 个值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-27
        • 2016-05-31
        • 2021-12-11
        • 1970-01-01
        • 2012-07-28
        相关资源
        最近更新 更多