Python 使用numpy生成带有case-when条件的随机数据 问题:

Python 使用numpy生成带有case-when条件的随机数据 问题:,python,numpy,if-statement,Python,Numpy,If Statement,我想生成要建模的数据。基于以下逻辑: 输入:2个名为z和d的numpy数组 z:1d数组,值0/1 d:1d数组,值0/1 返回: y:1d数组。值:范数随机数 如果z==0,d==0,y~范数(1,1) 如果z==0,d==1,y~范数(0,1) 如果z==1,d==0,y~范数(1,1) 如果z==1,d==1,y~范数(2,1) 我想以一种超快速、清晰和类似蟒蛇的方式来做。 这似乎是基础数学和np。其中更快。在这种情况下,我只有3个条件(你们可以从基本数学部分清楚地看到)。若我有10个或更

我想生成要建模的数据。基于以下逻辑:

输入:2个名为
z
d
的numpy数组

z
:1d数组,值0/1

d
:1d数组,值0/1

返回:
y
:1d数组。值:范数随机数

如果z==0,d==0,y~范数(1,1)

如果z==0,d==1,y~范数(0,1)

如果z==1,d==0,y~范数(1,1)

如果z==1,d==1,y~范数(2,1)

我想以一种超快速、清晰和类似蟒蛇的方式来做。

这似乎是基础数学和
np。其中
更快。在这种情况下,我只有3个条件(你们可以从基本数学部分清楚地看到)。若我有10个或更多的条件,在
If-else
语句中键入它们有时会令人困惑。我想进行数据模拟,这意味着我将在不同的
n
下生成数百万次的数据。那么,最好的方法是什么

我所尝试的: 口述案情 输出:

每个回路16.2 ms±139µs(7次运行的平均值±标准偏差,每个100个回路)

简单的
if-else
输出:

每个回路1.38 ms±22.1µs(7次运行的平均值±标准偏差,每个1000个回路)

基础数学 输出:

每个回路140µs±135 ns(7次运行的平均值±标准偏差,每个10000个回路)

np.在哪里 输出:

每个回路156µs±598 ns(7次运行的平均值±标准偏差,每个10000个回路)


还有其他新方法吗?

看来你已经在这里做了准备工作。结果现在是基于权衡。上述所有解决方案都在不同程度上符合标准

这个代码是用来教别人的吗?也许一天只执行一到两次?它是一个更大的项目的一部分,需要非常清楚,以便其他人维护?如果是这种情况,请选择较慢但更易于理解和阅读的选项

它是每天执行数千次还是数百万次?资源成本降低产品利润的钱?如果是这样的话,请好好评论一下,并使用更快的选项

看来,
基础数学
选项是最好的折衷方案,因为它简单易懂,而且执行速度快

我对每种方法的偏颇评价:

  • dict case when
    :慢速,需要多次阅读/测试才能完全理解实际发生的情况,并找出是否存在任何未知问题
  • simple if else
    :速度慢,需要多次阅读/测试才能完全理解实际发生的情况,并找出是否存在任何未知问题
  • 基础数学
    :如果你有一个小数学背景(应该包括大多数程序员),那么速度快,容易理解
  • np.where
    :快速完成任务,需要多次阅读/测试才能完全理解实际发生的情况,但不太容易出错,因为它基于数组
以下是pythonic编写代码的哲学:

  • 美胜于丑
  • 显式比隐式好
  • 简单总比复杂好
  • 复杂总比复杂好
  • 平的比嵌套的好
  • 稀疏比密集好
  • 可读性很重要

使用上述标准可以更容易地评估代码是否为pythonic。

我认为最快的选择是通过将数组值参数用于
normal
,只生成一次随机数。使用新的随机API:

import numpy as np

rng = np.random.default_rng()

# generate data
n = 2000
z = rng.binomial(1, 0.5, n)
d = rng.binomial(1, 0.5, n)

def generate_once(z, d):
    """Generate randoms for https://stackoverflow.com/questions/59676147"""

    # encode mean; scale is always 1 anyway in the example
    means = np.zeros_like(z, dtype=float)
    z_inds = z == 0
    d_inds = d == 0
    means[d_inds] = 1
    means[z_inds & ~d_inds] = 2

    # generate the data
    y = rng.normal(means)
    return y

y = generate_once(z, d)

我并没有试着和其他人较量,但我希望这是有竞争力的。如果是“<代码> >,请考虑它是您的<代码>的一个更快的变体。在映射
时使用快捷方式意味着
(一般来说,
可以缩放
),因为一个数组可以减少开销,而且只生成一次正常的数字应该可以减少运行时间。

我肯定你的
如果没有
做你认为会做的事情,那么请确保你所有的选项都先做同样的事情。@AndrasDeak抱歉,我的帖子修改得更好了,但是你也应该仔细看看
I==0&j==1
def myfun(x):
    return {(0,1):np.random.normal(0,1),\
            (0,0):np.random.normal(1,1),\
            (1,0):np.random.normal(1,1),\
            (1,1):np.random.normal(2,1)}[x]
%%timeit
y = [myfun(i) for i in zip(z,d)]
%%timeit
y = np.random.normal([0 if (i == 0) & (j ==1) else 2 if (i == 1) & (j == 1) else 1 for i,j in zip(z,d)],1)
%%timeit
h0 = np.random.normal(0,1,n)
h1 = np.random.normal(1,1,n)
h2 = np.random.normal(2,1,n)
y = (1-z)*d*h0 + (1-d)*h1 + z*d*h2
%%timeit
h0 = np.random.normal(0,1,n)
h1 = np.random.normal(1,1,n)
h2 = np.random.normal(2,1,n)
y = np.where((d== 0),h1,0) + np.where((z ==1) & (d== 1),h2,0) + np.where((z ==0) & (d== 1),h0,0)
import numpy as np

rng = np.random.default_rng()

# generate data
n = 2000
z = rng.binomial(1, 0.5, n)
d = rng.binomial(1, 0.5, n)

def generate_once(z, d):
    """Generate randoms for https://stackoverflow.com/questions/59676147"""

    # encode mean; scale is always 1 anyway in the example
    means = np.zeros_like(z, dtype=float)
    z_inds = z == 0
    d_inds = d == 0
    means[d_inds] = 1
    means[z_inds & ~d_inds] = 2

    # generate the data
    y = rng.normal(means)
    return y

y = generate_once(z, d)