Python 累积分布图
我正在用python做一个项目,我有两个数据数组。让我们称他们为pc和pnc。我被要求在同一张图上绘制这两个变量的累积分布。对于pc,它应该是一个小于的绘图,即在(x,y)处,pc中的y点的值必须小于x。对于pnc,它是一个大于的绘图,即在(x,y)处,pnc中的y点的值必须大于xPython 累积分布图,python,python-3.x,matplotlib,Python,Python 3.x,Matplotlib,我正在用python做一个项目,我有两个数据数组。让我们称他们为pc和pnc。我被要求在同一张图上绘制这两个变量的累积分布。对于pc,它应该是一个小于的绘图,即在(x,y)处,pc中的y点的值必须小于x。对于pnc,它是一个大于的绘图,即在(x,y)处,pnc中的y点的值必须大于x 我尝试过使用直方图函数-pyplot.hist。有更好更简单的方法来做我想做的事吗?此外,它必须以对数比例绘制在x轴上。你已经接近了。您不应将plt.hist用作numpy.histogram,因为它提供了值和存储单
我尝试过使用直方图函数-
pyplot.hist
。有更好更简单的方法来做我想做的事吗?此外,它必须以对数比例绘制在x轴上。你已经接近了。您不应将plt.hist用作numpy.histogram,因为它提供了值和存储单元,因此您可以轻松绘制累积值:
import numpy as np
import matplotlib.pyplot as plt
# some fake data
data = np.random.randn(1000)
# evaluate the histogram
values, base = np.histogram(data, bins=40)
#evaluate the cumulative
cumulative = np.cumsum(values)
# plot the cumulative function
plt.plot(base[:-1], cumulative, c='blue')
#plot the survival function
plt.plot(base[:-1], len(data)-cumulative, c='green')
plt.show()
使用直方图确实是不必要的繁重和不精确(装箱使数据变得模糊):您可以对所有x值进行排序:每个值的索引是较小值的数量。此较短且更简单的解决方案如下所示:
import numpy as np
import matplotlib.pyplot as plt
# Some fake data:
data = np.random.randn(1000)
sorted_data = np.sort(data) # Or data.sort(), if data can be modified
# Cumulative counts:
plt.step(sorted_data, np.arange(sorted_data.size)) # From 0 to the number of data points-1
plt.step(sorted_data[::-1], np.arange(sorted_data.size)) # From the number of data points-1 to 0
plt.show()
此外,更合适的打印样式实际上是plt.step()
,而不是plt.plot()
,因为数据位于离散位置
结果是:
您可以看到,它比EnricoGiampieri的答案的输出更加粗糙,但这是真实的直方图(而不是近似的、模糊的)
PS:正如塞巴斯蒂安·拉施卡所指出的,最后一点最好显示总计数(而不是总计数-1)。这可以通过以下方式实现:
plt.step(np.concatenate([sorted_data, sorted_data[[-1]]]),
np.arange(sorted_data.size+1))
plt.step(np.concatenate([sorted_data[::-1], sorted_data[[0]]]),
np.arange(sorted_data.size+1))
数据中有太多的点
,如果不进行缩放,效果就不可见,但是当数据只包含几个点时,总计数的最后一点确实很重要。在与@EOL进行结论性讨论后,我想发布我的解决方案(左上角),使用随机高斯样本作为总结:
import numpy as np
import matplotlib.pyplot as plt
from math import ceil, floor, sqrt
def pdf(x, mu=0, sigma=1):
"""
Calculates the normal distribution's probability density
function (PDF).
"""
term1 = 1.0 / ( sqrt(2*np.pi) * sigma )
term2 = np.exp( -0.5 * ( (x-mu)/sigma )**2 )
return term1 * term2
# Drawing sample date poi
##################################################
# Random Gaussian data (mean=0, stdev=5)
data1 = np.random.normal(loc=0, scale=5.0, size=30)
data2 = np.random.normal(loc=2, scale=7.0, size=30)
data1.sort(), data2.sort()
min_val = floor(min(data1+data2))
max_val = ceil(max(data1+data2))
##################################################
fig = plt.gcf()
fig.set_size_inches(12,11)
# Cumulative distributions, stepwise:
plt.subplot(2,2,1)
plt.step(np.concatenate([data1, data1[[-1]]]), np.arange(data1.size+1), label='$\mu=0, \sigma=5$')
plt.step(np.concatenate([data2, data2[[-1]]]), np.arange(data2.size+1), label='$\mu=2, \sigma=7$')
plt.title('30 samples from a random Gaussian distribution (cumulative)')
plt.ylabel('Count')
plt.xlabel('X-value')
plt.legend(loc='upper left')
plt.xlim([min_val, max_val])
plt.ylim([0, data1.size+1])
plt.grid()
# Cumulative distributions, smooth:
plt.subplot(2,2,2)
plt.plot(np.concatenate([data1, data1[[-1]]]), np.arange(data1.size+1), label='$\mu=0, \sigma=5$')
plt.plot(np.concatenate([data2, data2[[-1]]]), np.arange(data2.size+1), label='$\mu=2, \sigma=7$')
plt.title('30 samples from a random Gaussian (cumulative)')
plt.ylabel('Count')
plt.xlabel('X-value')
plt.legend(loc='upper left')
plt.xlim([min_val, max_val])
plt.ylim([0, data1.size+1])
plt.grid()
# Probability densities of the sample points function
plt.subplot(2,2,3)
pdf1 = pdf(data1, mu=0, sigma=5)
pdf2 = pdf(data2, mu=2, sigma=7)
plt.plot(data1, pdf1, label='$\mu=0, \sigma=5$')
plt.plot(data2, pdf2, label='$\mu=2, \sigma=7$')
plt.title('30 samples from a random Gaussian')
plt.legend(loc='upper left')
plt.xlabel('X-value')
plt.ylabel('probability density')
plt.xlim([min_val, max_val])
plt.grid()
# Probability density function
plt.subplot(2,2,4)
x = np.arange(min_val, max_val, 0.05)
pdf1 = pdf(x, mu=0, sigma=5)
pdf2 = pdf(x, mu=2, sigma=7)
plt.plot(x, pdf1, label='$\mu=0, \sigma=5$')
plt.plot(x, pdf2, label='$\mu=2, \sigma=7$')
plt.title('PDFs of Gaussian distributions')
plt.legend(loc='upper left')
plt.xlabel('X-value')
plt.ylabel('probability density')
plt.xlim([min_val, max_val])
plt.grid()
plt.show()
为了增加我对社区的贡献,我在这里分享了绘制直方图的功能。这就是我理解问题的方式,同时绘制直方图和累积直方图:
def hist(data, bins, title, labels, range = None):
fig = plt.figure(figsize=(15, 8))
ax = plt.axes()
plt.ylabel("Proportion")
values, base, _ = plt.hist( data , bins = bins, normed=True, alpha = 0.5, color = "green", range = range, label = "Histogram")
ax_bis = ax.twinx()
values = np.append(values,0)
ax_bis.plot( base, np.cumsum(values)/ np.cumsum(values)[-1], color='darkorange', marker='o', linestyle='-', markersize = 1, label = "Cumulative Histogram" )
plt.xlabel(labels)
plt.ylabel("Proportion")
plt.title(title)
ax_bis.legend();
ax.legend();
plt.show()
return
如果有人想知道它是什么样子,请看一看(seaborn已激活):
另外,关于双格线(白线),我总是很难得到好的双格线。这里有一个有趣的方法来解决这个问题:生成此图的简单方法是使用seaborn:
import seaborn as sns
sns.ecdfplot()
以下是文件:
如果您展示了您迄今为止的尝试-样本输入数据、所需输出等,将会有所帮助。。。否则,这将被理解为“向我展示代码”问题。为了扩展Jon的评论,人们更乐于帮助您修复现有代码,而不是从头开始生成代码。无论您的代码有多么缺陷和不起作用,都要展示并解释a)您期望它做什么,b)它当前正在做什么。仅供参考,您忘记了在求和之前包含np,正如您的np.histogram命令所暗示的,这是必需的。@ehsteve修复了答案。使用直方图既不必要地沉重,又不精确。@EOL但对于大型数组是必需的,否则您将耗尽内存。确实,但我认为这不是问题的特殊情况,这更多的是关于如何获得累积分布,而不是在大数组的情况下,近似地获得累积分布。但是对于大数组,您希望使用直方图方法,因为它几乎不需要那么多内存。
plt.step
方法给了我一个6000万元素数组的内存错误。我不确定问题是否出在plt.step
上,或者这个精确的方法使用的内存可能是数组内存的3倍,或者两者兼而有之……我同意:plt.step可能是绘制“计数”更合适的方法。一个问题:你不需要使用plt.step(sorted_data,np.arange(1,data.size+1))
来获得正确的计数吗?@SebastianRaschka:这一点很好。你说得对。一个完美的解决方案会增加最后一点。这可以通过复制最后一个横坐标并在最后一个纵坐标处添加总计数(5)来实现。我更新了答案,谢谢!谢谢你的更新。你的解决方法看起来比我的要好:)如果你期望数组中有负值,你可能想取绝对值。。。否则,累积直方图将显示为不正确