模拟渗透/采用外推的 CDF 曲线

问题描述

我希望能够为正态分布绘制一条类似于 cumulative distribution function 的线,因为它对于模拟采用曲线很有用:

Adoption curve

具体来说,我希望能够使用初始数据(产品采用的百分比)来推断该曲线的其余部分会是什么样子,以粗略估计每个阶段的时间表。因此,例如,如果我们在 30 天前达到 10% 的渗透率,到 40 天达到 20% 的渗透率,并且我们尝试拟合这条曲线,我想知道我们何时会达到 80% 的渗透率(vs另一个可能需要 50 天才能达到 10% 渗透率的人群)。

所以,我的问题是,我怎么才能做到这一点?理想情况下,我能够提供初始数据(时间和渗透率),并使用 python(例如 matplotlib)为我绘制图表的其余部分。但我不知道从哪里开始!有人能指出我正确的方向吗?

(顺便说一句,我也在 CrossValidated 上发布了这个问题,但我不确定它是属于那里的,因为它是一个统计问题,还是属于这里,因为它是一个 python 问题。抱歉重复!)

解决方法

cdf 可以通过 scipy.stats.norm.cdf() 计算。它的 ppf 可用于帮助映射所需的对应关系。 scipy.interpolate.pchip 然后可以创建一个函数来使转换平滑地进行插值。

import matplotlib.pyplot as plt
from matplotlib.ticker import PercentFormatter
import numpy as np
from scipy.interpolate import pchip  # monotonic cubic interpolation
from scipy.stats import norm

desired_xy = np.array([(30,10),(40,20)])  # (number of days,percentage adoption)
# desired_xy = np.array([(0,1),(30,20),(90,99)])
labels = ['Innovators','Early\nAdopters','Early\nMajority','Late\nMajority','Laggards']
xmin,xmax = 0,90  # minimum and maximum day on the x-axis

px = desired_xy[:,0]
py = desired_xy[:,1] / 100

# smooth function that transforms the x-values to the  corresponding spots to get the desired y-values
interpfunc = pchip(px,norm.ppf(py))

fig,ax = plt.subplots(figsize=(12,4))
# ax.scatter(px,py,color='crimson',s=50,zorder=3)  # show desired correspondances
x = np.linspace(xmin,xmax,1000)
ax.plot(x,norm.cdf(interpfunc(x)),lw=4,color='navy',clip_on=False)

label_divs = np.linspace(xmin,len(labels) + 1)
label_pos = (label_divs[:-1] + label_divs[1:]) / 2
ax.set_xticks(label_pos)
ax.set_xticklabels(labels,size=18,color='navy')
min_alpha,max_alpha = 0.1,0.4
for p0,p1,alpha in zip(label_divs[:-1],label_divs[1:],np.linspace(min_alpha,max_alpha,len(labels))):
    ax.axvspan(p0,alpha=alpha,zorder=-1)
    ax.axvline(p0,color='white',lw=1,zorder=0)
ax.axhline(0,lw=2,clip_on=False)
ax.axvline(0,clip_on=False)
ax.yaxis.set_major_formatter(PercentFormatter(1))
ax.set_xlim(xmin,xmax)
ax.set_ylim(0,1)
ax.set_ylabel('Total Adoption',color='navy')
ax.set_title('Adoption Curve',size=24,color='navy')
for s in ax.spines:
    ax.spines[s].set_visible(False)
ax.tick_params(axis='x',length=0)
ax.tick_params(axis='y',labelcolor='navy')
plt.tight_layout()
plt.show()

resulting plot

仅对 desired_xy 使用两个点,曲线将被线性拉伸。如果给出更多点,将应用平滑变换。下面是 [(0,99)] 的样子。请注意,0 %100 % 会导致问题,因为它们位于正无穷大处的负值。

fixing at 4 points

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...