首页 > 解决方案 > 在 pandas 中尽快生成一个随机数字的列,平均值 = 20,最大值 = 25,最小值 = 5

问题描述

我有一个 df 如下所示

        df = pd.DataFrame({'Session': ['s1', 's1', 's1', 's1', 's1', 's1', 's1',
                                       's1', 's1', 's1', 's1', 's1', 's1', 's1', 's1'],
                          'slot_num': [1, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9]})

东风:

Session         slot_num
s1              1
s1              2
s1              3
s1              3
s1              4
s1              4
s1              5
s1              5
s1              6
s1              7
s1              7
s1              8
s1              8
s1              9
s1              9

从上面我想尽可能快地创建一个名为 service_time 的列,其平均值恰好为 20,最大值为 25,最小值为 2。

我尝试了下面的代码,但它并没有给出 20 的平均值。

注意:服务时间只能包含整数

# generate service time with mean = 20, min = 2 and max = 25
def gen_avg(n, expected_avg=20, a=2, b=25):
    l = np.random.randint(a, b, size=n)
    while True:
        if np.mean(l) == expected_avg:
            break
        while np.mean(l) > expected_avg:
            c = np.random.choice(np.where(l>expected_avg)[0])
            l[c] = np.random.randint(a, expected_avg+1)
        while np.mean(l) < expected_avg:
            c = np.random.choice(np.where(l<expected_avg)[0])
            l[c] = np.random.randint(expected_avg, b)
        return l

df['service_time'] = df.groupby('Session')['Session'].transform(lambda x: gen_avg(len(x)))

我也尝试过低于一个,但需要很长时间

#https://stackoverflow.com/a/39435600/2901002
def gen_avg(n, expected_avg=20, a=5, b=25):
    while True:
        l = np.random.randint(a, b, size=n)
        avg = np.mean(l)

        if avg == expected_avg:
            return l

df['service_time'] = df.groupby('Session')['Session'].transform(lambda x: gen_avg(len(x)))

标签: pandasnumpypandas-groupby

解决方案


这可能需要很长时间,因为您期望平均值完全等于expected_avg. 因为它是一个随机变量,其中一个n观察值可以改变平均值,所以这是一个问题,尤其是随着n增长。如果允许,您可以使用使平均值足够接近的方法,例如最多相差 5%。假设我们称之为tolerance。尝试以下操作:

while abs((avg-expected_avg)/expected_avg) > tolerance:
  l = np.random.randint(a, b, size=n)
  avg = np.mean(l)

推荐阅读