【问题标题】:How to generate a sample of x and y with conditional probability with NumPy如何使用 NumPy 生成具有条件概率的 x 和 y 样本
【发布时间】:2020-04-03 10:23:27
【问题描述】:

我正在尝试为二进制分类器生成 x 及其标签 - y 的样本。

我知道我的 x 均匀分布在 [0,1] 中。但我的 y 分布由我的 x 派生: if x in [0.2, 0.4] or in [0.6, 0.8] - P[Y=1] = 0.1。如果 x 超出这些范围,则 P[Y=1] = 0.8

我认为最好的方法是使用 NumPy(而不是使用 for 循环和 if 条件),但直到现在我都没有成功。

这是我的尝试:

s = np.random.uniform(0,1,100) # 100 x samples in [0,1] uniformly distributed
condition  = (np.logical_or((s>0.2)&(s < 0.4), (s>0.6)&(s < 0.8))) # attempt to mark with True the places of x in bounds.
x_in_bounds = np.select(condlist, s) # this line doesn't work
... # how to generate the y values?

我试图找到一种根据 x 值样本的条件随机生成 y 值的方法,但没有成功。我很想知道我错过了什么。

【问题讨论】:

标签: python numpy numpy-ndarray


【解决方案1】:

有关使用您的方法的解决方案,请参阅@adnanmuttaleb 的答案。

我的方法是使用 numpy 的高级索引:

x = np.random.uniform(0, 1, 100)

cond = ((x > 0.2) & (x < 0.4)) | ((x > 0.6) & (x < 0.8))
not_cond = np.logical_not(cond)

y = np.random.rand(*x.shape)
y[cond] = y[cond] < 0.1
y[not_cond] = y[not_cond] < 0.8
y = y.astype(int)

【讨论】:

    【解决方案2】:

    一种方法是生成两个随机序列,根据上述两种情况填充为 1 或 0。然后使用np.where 根据condition 选择一个或另一个:

    s = np.random.uniform(0,1,100)
    condition  = np.logical_or((s>0.2)&(s < 0.4), (s>0.6)&(s < 0.8))
    
    repl_a = (np.random.random(len(s))>0.9).view('i1')
    repl_b = (np.random.random(len(s))>0.2).view('i1')
    
    np.where(condition, repl_a, repl_b)
    
    array([1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1,
           0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0,
           1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
           1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1,
           0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0], dtype=int8)
    

    【讨论】:

      【解决方案3】:

      使用与您使用的相同方法的解决方案是:

      generate = lambda prob: 1 if np.random.rand() < prob else 0
      
      s = np.random.uniform(0, 1, 100)
      low_prob_condition = ((s > 0.2) & (s < 0.4)) | ((s > 0.6) & (s < 0.8))
      condlist = [low_prob_condition, np.logical_not(low_prob_condition)] 
      labels = np.select(condlist, [[generate(0.1) for _ in range(s.size)], [generate(0.8) for _ in range(s.size)]])
      
      print(labels)
      

      输出:

      [1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 0 0 0 1 0 0 0 0
       1 1 0 0 1 0 1 1 1 0 0 1 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 1 1 0 1 0 0 0 1 0 0
       0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 1 1 1 1 0 1 0 0 1 1]
      

      但更节省时间和空间的解决方案应该是:

      s = np.random.uniform(0, 1, 100)
      low_prob_cond = lambda x: ((x > 0.2) and (x < 0.4)) or ((x > 0.6) and (x < 0.8))
      gen = lambda prob: 1 if np.random.rand() < prob else 0
      labels = (gen(0.1) if low_prob_cond(x) else gen(0.8) for x in s)
      
      print(list(labels))
      

      输出:

      [0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1]
      

      np.select 要求与s 相同大小的列表作为每个条件的选择列表(在您的情况下为两个),这显然可以在您的问题中避免。

      【讨论】:

      • 修复第一个解决方案中的拼写错误genetate (-> generate)。
      • 我认为最好随机播种以证明解决方案是等效的并产生相同的结果。除非世代顺序不一样,然后就无关紧要了……
      • @idow09 tnx 错字已修复。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-23
      • 2021-06-26
      • 2013-09-12
      • 2015-06-08
      • 1970-01-01
      • 1970-01-01
      • 2013-12-15
      相关资源
      最近更新 更多