如何可视化分布随时间的演变?

机器算法验证 时间序列 分布 Python 数据可视化
2022-04-04 20:12:10

假设您有某个时期内每一天的分布记录。例如,某些分布取决于随时间演变的参数。假设我们有几十天或几百天。你如何想象这种分布的变化?我希望情节包含尽可能多的信息。

我能想到的一种方法是:代理密度函数并绘制这些曲线在 2D 中的演变。这将是某种形式的同伦:初始分布以一些平滑的步骤收敛到最终分布。当然,这里我假设平滑。

谢谢你的帮助。

这个问题本质上是理论上的,但我的目标是实现 python,因此也欢迎对库的实现或建议。

3个回答

编辑 没有看到这是一个python问题。我认为这个想法成立,但不确定 python 实现是否现成。


您可能想使用Rggridges(和gganimate动画)查看所谓的 ridge-plots 。下面是一个例子(显然不必是动画):

在此处输入图像描述

此要点中提供了代码

始终考虑您的情况的性质:谁将成为这个情节的观众?我的目标是什么?我的数据是什么?

您声明您有一个“分布取决于随时间演变的参数”。如果您的受众相当复杂,并且这是一个已知的、研究过的分布(例如Weibull),那么您可以估计每天的变化参数,将其绘制在散点图上,并使用像 LOWESS 线这样简单的东西对其进行平滑处理。

这是一个例子。这些是用 R 编码的,但它们旨在让不使用 R 的人易于理解,并且应该可以翻译成 Python。

library(fitdistrplus)      # we'll use this package
set.seed(9234)             # this makes the example exactly reproducible

day = rep(1:16, each=100)  # 1 through 16, each repeated 100x
y   = c()                  # an empty vector to hold the data
for(i in 1:16){            # generates data from Weibull distributions w/ the
  y = c(y,                 #  shape parameter increasing (but decelerating) by day
        rweibull(n=100, shape=(.5 + .1*i - .002*(i^2)), scale=1))
}
# estimate Weibull shape & scale parameters by MLE for each day
d = t(sapply(split(y, day), function(x){ fitdist(x, distr="weibull")$estimate }))
d = data.frame(day=1:16, d)
d
#    day     shape     scale
# 1    1 0.6311143 0.9871380
# 2    2 0.7501392 1.0168905
# 3    3 0.7510426 0.8853516
# 4    4 0.8142484 0.8701132
# 5    5 0.9081937 1.1098466
# 6    6 0.9679144 1.0668120
# 7    7 1.0347746 1.0638731
# 8    8 1.1496184 0.9775989
# 9    9 1.1724681 1.0758072
# 10  10 1.2396152 0.9975250
# 11  11 1.2519313 0.8847656
# 12  12 1.4648643 1.0801915
# 13  13 1.3258313 0.9113326
# 14  14 1.4301392 0.9699252
# 15  15 1.5494493 1.0448072
# 16  16 1.5989056 1.0133831
windows()
  plot(shape~day, d)
  lines(lowess(d$day, d$shape), col="red")

在此处输入图像描述

如果数据不是来自已知分布,您可以绘制多条线随时间跟踪固定分位数。

dq = t(sapply(split(y, day), function(x){ quantile(x, probs=c(0.25, 0.5, 0.75, 0.95)) }))
dq = data.frame(day=1:16, dq)
names(dq) = c("day", "25%", "50%", "75%", "95%")
dq
#    day       25%       50%      75%
# 1    1 0.1447001 0.5212207 1.628061
# 2    2 0.2318992 0.6657878 1.394435
# 3    3 0.1868559 0.5122787 1.618891
# 4    4 0.1665822 0.6402280 1.259112
# 5    5 0.3038764 0.6778831 1.418966
# 6    6 0.2508331 0.7469482 1.447055
# 7    7 0.2759569 0.7411599 1.527585
# 8    8 0.2774774 0.7496496 1.421123
# 9    9 0.3630679 0.9203537 1.343523
# 10  10 0.3788195 0.6613015 1.263599
# 11  11 0.3514467 0.6411170 1.110531
# 12  12 0.4697239 0.8562416 1.253663
# 13  13 0.3281270 0.6732758 1.113507
# 14  14 0.4498140 0.7440592 1.143489
# 15  15 0.4391240 0.8440031 1.371128
# 16  16 0.4726235 0.8386493 1.210914
windows()
  plot(1,1, xlim=c(1,16), ylim=c(0, 7), xlab="day", ylab="value", type="n")
  lines(dq$day, dq$`25%`, col="red",    lty=2)
  lines(dq$day, dq$`50%`, col="black",  lty=1)
  lines(dq$day, dq$`75%`, col="blue",   lty=3)
  lines(dq$day, dq$`95%`, col="purple", lty=4)
  legend("topright", legend=c("95%", "75%", "50%", "25%"), lty=c(4,3,1,2),
         col=c("purple", "blue", "black", "red"))

在此处输入图像描述

如果您的观众不那么老练,不知道“Weibull”是什么,或者因为试图遵循“75 th percentile”的想法而被甩掉,并且您想要一些更有活力的东西,那就做一个小组核密度图。(不可否认,阿迪宾德的情节比这更精彩。)

windows()
  par(mfrow=c(4,4))
  for(i in 1:16){
    plot(density(y[day==i]), main=paste("day", i), xlab="", xlim=range(y),
         ylim=c(0, .8), ylab="", axes=FALSE);  box()
  }

在此处输入图像描述

假设您每天都有一个经验分布,例如一家商店每天查看每个客户的总付款。您可以将其视为直方图的时间序列,并且可以以各种方式绘制,可能是一系列箱线图。如果您有一些示例数据,我们可以尝试各种选项!

在这里提出并回答了一个类似的问题: https ://stackoverflow.com/questions/11690194/time-series-histogram