【问题标题】:numpy irreversibly change items in a list at randomnumpy 不可逆地随机更改列表中的项目
【发布时间】:2017-12-15 09:37:51
【问题描述】:

我有一个清单

a = np.ones(100)

我想将该列表中的 50 个随机项目变为 0。一旦这些元素为 0,我想将列表中剩余项目的 25 个随机元素变为 0。在剩余的 25 个中,我想将 13其余元素随机归零等。

然后我将通过一个简单的循环来运行它,例如(伪代码)“如果 item == 1,打印红色粒子,否则打印蓝色粒子”等。

这基本上是为了模拟指数衰减,但我正在努力想一个算法来做到这一点。

这不是“Numpy:替换数组中的随机元素”的副本,因为一旦元素发生更改,我不希望它们再次被考虑更改。

【问题讨论】:

  • 只是为了好玩?因为numpy 太快了,你不会注意到衰减是指数的、线性的还是数组一开始就只包含 0。
  • 你不应该总是将 50 个随机元素设置为零以获得指数衰减吗?
  • 另外,a = np.ones(1,size=100) 是什么?它甚至不是合法的函数调用。
  • 大多数随机衰减过程会给每个元素一个独立的 50% 衰减机会,而不是每次都可靠地衰减剩余项目的确切比例。

标签: python numpy random


【解决方案1】:

您基本上需要数组中的递减对象,并且似乎有一个额外的限制,即被zeros 替换的对象仅来自现有的ones 集合。为了解决这个问题,这是一种方法,将np.random.choice 的可选参数replace 设置为False 以获取每次迭代的唯一索引以分配zeros 并使用np.flatnonzero 获取每次迭代的ones 的剩余索引.

因此,实现看起来像这样 -

# Counts of ones to be set as zeros per iteration
counts = np.array([50,25,13,6,3,2,1])
a = np.ones(100,dtype=int)
for c in counts:
    a[np.random.choice(np.flatnonzero(a), c, replace=False)] = 0

示例运行 -

In [49]: counts = np.array([50,25,13,6,3,2,1])
    ...: a = np.ones(100,dtype=int)
    ...: for c in counts:
    ...:     a[np.random.choice(np.flatnonzero(a), c, replace=False)] = 0
    ...:     print a.sum() # verify with summation of ones print at each iteration
50
25
12
6
3
1
0

要为通用长度输入数组a 设置counts 数组,我们可以这样做 -

N = int(np.log(len(a))/np.log(2)) # number of iterations
counts = (len(a)*((0.5)**(np.arange(N)+1))).astype(int)

【讨论】:

    【解决方案2】:

    这是一个简单的版本。它是其他答案的替代方案,并且通过将元素随机设置为零来偏离指令,如指数衰减所建议的那样,而不是在每一轮中移除确定性的 1/2。

    这会在每一轮打印整个数组,但替代方案可能包括第一个元素 print(a[0]) 或剩余的数字 print(a.sum())。

    a = np.ones(100)
    while any(a):
        print(a)
        for i, _ in enumerate(a):
            if random.random() > 0.5:
                a[i] = 0
    

    【讨论】:

      【解决方案3】:

      您想要实现它的方式是始终将剩余元素的 50% 设置为零。这意味着在每个 epoch 中,您总是会精确地衰减 50、25、12.5、... 个元素。

      但是我不相信指数衰减过程是这样运作的。

      据我了解,您应该以p 的概率将每个单独的元素设置为零。这意味着在每个 epoch 中,p = 0.5 的概率平均会衰减 50、25、12.5、... 个元素。

      这种方法也大大简化了解决方案:

      import numpy as np
      
      x = np.ones(100)
      p = .5  # probability of decay
      
      for i in range(20):
          mask = np.random.choice([True, False], size=len(x), p=[p, 1-p])
          x[mask] = 0
      

      如果速度是一个因素(但内存消耗不是),你也可以向量化这个操作:

      x = np.random.choice([-1, 0], size=(100, 20), p=[p, 1-p])
      x = np.cumsum(x, axis=1)
      x = x == 0
      

      之后

      x[:, n]
      

      n + 1 epochs 和之后的人口数

      np.sum(x, axis=0)
      

      是一段时间内的人口规模。

      【讨论】:

        【解决方案4】:

        这是您可以做到的一种方法。基本思想是创建一个索引数组 [0, 1, 2, ..., 99],对该数组进行洗牌,然后使用该数组中大小减小的切片作为要归零的 a 的索引。

        In [75]: a = np.ones(100)
        
        In [76]: sizes = (len(a)*np.power(2.0, [-1, -2, -3, -4, -5, -6, -7]) + 0.5).astype(int)
        
        In [77]: sizes
        Out[77]: array([50, 25, 13,  6,  3,  2,  1])
        
        In [78]: indices = np.arange(len(a))
        
        In [79]: np.random.shuffle(indices)
        
        In [80]: start = 0
        
        In [81]: for k in range(len(sizes)):
            ...:     end = start + sizes[k]
            ...:     a[indices[start:end]] = 0
            ...:     print(np.count_nonzero(a))
            ...:     start = end
            ...:     
        50
        25
        12
        6
        3
        1
        0
        

        【讨论】:

          猜你喜欢
          • 2023-03-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-30
          • 2019-01-09
          相关资源
          最近更新 更多