python - 如何使用逆 CDF 在 Python 中随机抽样对数正态数据并指定目标百分位数?

标签 python random statistics probability-density cdf

我正在尝试从 Python 中的对数正态分布生成随机样本,该应用程序用于模拟网络流量。我想生成这样的样本:

  1. 模态样本结果为 320 (~10^2.5)
  2. 80% 的样本位于 100 到 1000(10^2 到 10^3)的范围内

我的策略是使用逆 CDF(我相信是 Smirnov 变换):

  1. 使用以 2.5 为中心的正态分布的 PDF 计算 10^x 的 PDF,其中 x ~ N(2.5,sigma)。
  2. 计算上述分布的 CDF。
  3. 沿区间 0 到 1 生成随机均匀数据。
  4. 使用逆CDF将随机均匀数据变换到需要的范围内。

问题是,当我最后计算第 10 个和第 90 个百分位数时,我得到的数字完全错误。

这是我的代码:

%matplotlib inline

import matplotlib
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats
from scipy.stats import norm

# find value of mu and sigma so that 80% of data lies within range 2 to 3
mu=2.505
sigma = 1/2.505
norm.ppf(0.1, loc=mu,scale=sigma),norm.ppf(0.9, loc=mu,scale=sigma)
# output: (1.9934025, 3.01659743)

# Generate normal distribution PDF
x = np.arange(16,128000, 16) # linearly spaced here, with extra range so that CDF is correctly scaled
x_log = np.log10(x)
mu=2.505
sigma = 1/2.505
y = norm.pdf(x_log,loc=mu,scale=sigma)
fig, ax = plt.subplots()
ax.plot(x_log, y, 'r-', lw=5, alpha=0.6, label='norm pdf')

x2 = (10**x_log) # x2 should be linearly spaced, so that cumsum works (later)
fig, ax = plt.subplots()
ax.plot(x2, y, 'r-', lw=5, alpha=0.6, label='norm pdf')
ax.set_xlim(0,2000)

# Calculate CDF
y_CDF = np.cumsum(y) / np.cumsum(y).max()
fig, ax = plt.subplots()
ax.plot(x2, y_CDF, 'r-', lw=2, alpha=0.6, label='norm pdf')
ax.set_xlim(0,8000)

# Generate random uniform data
input = np.random.uniform(size=10000)

# Use CDF as lookup table
traffic = x2[np.abs(np.subtract.outer(y_CDF, input)).argmin(0)]

# Discard highs and lows
traffic = traffic[(traffic >= 32) & (traffic <= 8000)]

# Check percentiles
np.percentile(traffic,10),np.percentile(traffic,90)

产生输出:

(223.99999999999997, 2480.0000000000009)

... 而不是我希望看到的 (100, 1000)。任何建议表示赞赏!

最佳答案

首先,我不确定Use the PDF for a normal distribution centered around 2.5。毕竟,对数正态是以 e 为底的对数(又名自然对数),这意味着 320 = 102.5 = e5.77

其次,我会以不同的方式处理问题。您需要 msLog-Normal 中采样.

如果您查看上面的 wiki 文章,您会发现它是双参数分布。你正好有两个条件:

Mode = exp(m - s*s) = 320
80% samples in [100,1000] => CDF(1000,m,s) - CDF(100,m,s) = 0.8

其中 CDF 通过误差函数表示(这在任何库中都是很常见的函数)

所以两个参数的两个非线性方程。解决它们,找到ms并将其放入任何标准对数正态采样

关于python - 如何使用逆 CDF 在 Python 中随机抽样对数正态数据并指定目标百分位数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42935843/

相关文章:

python - 查询在 psql 中有效,但在使用 psycopg2 的 Python 中出现语法错误

python - 如何最好地在函数中初始化Python的随机模块

ruby - 如何获得随机的 0 和 1 数字

python - Python 中的 ITK : SimpleITK or not?

python - 在Python中使用 Storm

python - 文件中的递归键值

c - 在范围和特定步骤内在C中生成随机数

r - 如何创建一个循环

r - 正态分布均值贝叶斯推理的玩具 R 代码 [降雪量数据]

python-2.7 - Python(Scipy): Finding the scale parameter (standard deviation) of a gaussian distribution