Python 正态分布曲线不';t使用matplotlib在子批次中很好地拟合直方图
我使用“plt.subplot(2,2,sharex=True,sharey=True)”来绘制一个2*2的子图。每个子批次有两个Y轴,并包含直方图上的正态分布曲线。注意,我在这里特别设置了“sharex=True,sharey=True”,以使所有子地块共享相同的X轴和Y轴 运行我的代码后,除了第二、三和第四个子图之外,一切都很好,其中正态分布曲线与柱状图拟合得不是很好(请参见这里的图) 我用谷歌搜索了一下,但没能解决这个问题。但是,如果我在代码中设置了“sharex=True,sharey=False”,那么该图看起来是正确的,但是所有子地块都使用自己的Y轴,这不是我想要的。请看这里的数字 希望StackOverflow的专家能解决这个问题。非常感谢 下面是我的代码:Python 正态分布曲线不';t使用matplotlib在子批次中很好地拟合直方图,python,matplotlib,histogram,subplot,normal-distribution,Python,Matplotlib,Histogram,Subplot,Normal Distribution,我使用“plt.subplot(2,2,sharex=True,sharey=True)”来绘制一个2*2的子图。每个子批次有两个Y轴,并包含直方图上的正态分布曲线。注意,我在这里特别设置了“sharex=True,sharey=True”,以使所有子地块共享相同的X轴和Y轴 运行我的代码后,除了第二、三和第四个子图之外,一切都很好,其中正态分布曲线与柱状图拟合得不是很好(请参见这里的图) 我用谷歌搜索了一下,但没能解决这个问题。但是,如果我在代码中设置了“sharex=True,sharey
import matplotlib.pyplot as plt
from scipy.stats import norm
def align_yaxis(ax1, v1, ax2, v2):
#adjust ax2 ylimit so that v2 in ax2 is aligned to v1 in ax1
_, y1 = ax1.transData.transform((0, v1))
_, y2 = ax2.transData.transform((0, v2))
inv = ax2.transData.inverted()
_, dy = inv.transform((0, 0)) - inv.transform((0, y1-y2))
miny, maxy = ax2.get_ylim()
ax2.set_ylim(miny+dy, maxy+dy)
def drawSingle(myax, mydf , title, offset):
num_bins = 200
xs = mydf["gap"]
x = np.linspace(-1,1,1000)
mu =np.mean(x)
sigma =np.std(xs)
n, bins, patche = myax.hist(xs, num_bins, alpha=0.8, facecolor='blue', density=False)
myax.set_ylabel('frequency',color="black",fontsize=12, weight = "bold")
myax.set_xlabel('X', fontsize=12, weight = "bold",horizontalalignment='center')
ax_twin = myax.twinx()
y_normcurve = norm.pdf(bins, mu, sigma)
ax_twin.plot(bins, y_normcurve, 'r--')
align_yaxis(myax,0,ax_twin,0)
peakpoint = norm.pdf(mu,loc=mu,scale=sigma)
plt.vlines(mu, 0, peakpoint, 'y', '--', label='example')
ax_twin.set_ylabel("probablility dense",color="black",fontsize=12, weight = "bold")
def drawSubplots(mydf1,mydf2,mydf3,mydf4, pos1,pos2,pos3,pos4, title, filename):
plt.rcParams['figure.figsize'] = (18,15 )
my_x_ticks = np.arange(-0.8, 0.8,0.1)
rows, cols = 2, 2
fig, ax = plt.subplots(2, 2, sharex=True, sharey=True)
drawSingle(ax[0][0], mydf1, "Subplot1", pos1)
drawSingle(ax[0][1], mydf2, "Subplot2", pos2)
drawSingle(ax[1][0], mydf3, "Subplot3", pos3)
drawSingle(ax[1][1], mydf4, "Subplot4", pos4)
plt.text(-1, -1, title, horizontalalignment='center', fontsize=18)
plt.show()
drawSubplots(df1, df2,df3,df4,3.2,3.1,2.7,2.85,"test9", "test9")
以下是一个尝试:
- 使左y轴为“频率”(在当前箱子宽度的情况下,这是非常没有信息的),并在4个子批次之间共享
- 右y轴是否为“概率密度”;注意所有高斯函数的顶部是如何在y=0.02左右的(双轴只能在末尾设置,因为共享的y轴可以通过后面的子批次进行更新)
- 使直方图和法线曲线对齐
导入matplotlib.pyplot作为plt
作为pd进口熊猫
将numpy作为np导入
从scipy.stats导入norm
def drawSingle(myax、mydf、标题):
数量=200
xs=mydf[“差距”]
x=np.linspace(-1,1,1000)
mu=np.平均值(x)
西格玛=np.std(xs)
n、 容器,补丁=myax.hist(xs,num_容器,alpha=0.8,facecolor='blue',density=False)
myax.set_ylabel('frequency',color=“black”,fontsize=12,weight=“bold”)
myax.set_xlabel('X',fontsize=12,weight=“bold”,horizontalalignment='center'))
归一化系数=len(xs)*(料仓[1]-料仓[0])
y_normcrove=norm.pdf(x,mu,sigma)*归一化系数
myax.plot(x,y_曲线,'r--')
myax.vlines(mu,0,y_normcrove.max(),'y','--',color='lime',label='example')
返回归一化因子
def绘图子批次(mydf1、mydf2、mydf3、mydf4、标题):
plt.rcParams['figure.figsize']=(18,15)
图,ax=plt.子批次(nrows=2,ncols=2,sharex=True,sharey=True)
dfs=[mydf1、mydf2、mydf3、mydf4]
标准系数=[drawSingle(ax_i,df,title)
对于ax_i,df,zip中的标题(ax.ravel(),dfs,[“Subplot1”、“Subplot2”、“Subplot3”、“Subplot4”])]
对于ax_i,zip中的norm_因子(ax.ravel(),norm_因子):
ax_twin=ax_i.twinx()
ymax=ax_i.get_ylim()[1]
ax_twin.set_ylim(0,ymax/norm_因子)
plt.suptitle(标题,字体大小=18)
plt.紧_布局()
plt.show()
df1,df2,df3,df4=[6000,4000,1800,1200]中n的[pd.数据帧({“gap”:np.random.normal(0,0.2,n)}]
图纸子图(df1、df2、df3、df4,“标题”)
非常感谢约翰,你太棒了 基于您的代码,我刚刚在DrawSubplot函数中添加了几行代码,以便使95%的高斯曲线区域在每个子图的下限和上限之间着色。以下是我的尝试。看来ax_twin.fill_between在这里不正常工作。从图中可以看出,阴影区域超出了高斯曲线。我想要的只是在高斯曲线下的下限和上限之间对区域进行着色。如果你不介意的话,请你检查一下我的错误好吗?多谢各位
import matplotlib.pyplot as plt
import math
from scipy.stats import norm
def align_yaxis(ax1, v1, ax2, v2):
#adjust ax2 ylimit so that v2 in ax2 is aligned to v1 in ax1
_, y1 = ax1.transData.transform((0, v1))
_, y2 = ax2.transData.transform((0, v2))
inv = ax2.transData.inverted()
_, dy = inv.transform((0, 0)) - inv.transform((0, y1-y2))
miny, maxy = ax2.get_ylim()
ax2.set_ylim(miny+dy, maxy+dy)
def drawSingle(myax, mydf , title):
num_bins = 200
xs = mydf["gap"]
x = np.linspace(-1,1,1000)
mu =np.mean(xs)
sigma =np.std(xs)
n, bins, patches = myax.hist(xs, num_bins, alpha=0.8, facecolor='blue', density=False)
myax.set_ylabel('Frequency', color="black", fontsize=12, weight="bold")
myax.set_xlabel(title, fontsize=12, weight="bold", horizontalalignment='center')
normalization_factor = len(xs) * (bins[1] - bins[0])
y_normcurve = norm.pdf(x, mu, sigma) * normalization_factor
myax.plot(x, y_normcurve, 'r--')
myax.vlines(mu, 0, y_normcurve.max(), 'y', '--', color='lime', label='example')
plt.xlim(-0.8,0.8)
my_x_ticks = np.arange(-0.8, 0.8,0.1)
plt.xticks(my_x_ticks)
return normalization_factor, mu, sigma
def drawSubplots(mydf1,mydf2,mydf3,mydf4, title):
plt.rcParams['figure.figsize'] = (18,15 )
norm_factors = []
mus = []
sigmas = []
my_x_ticks = np.arange(-0.8, 0.8,0.1)
rows, cols = 2, 2
fig, ax = plt.subplots(nrows=rows, ncols=cols, sharex=True, sharey=True)
dfs = [mydf1, mydf2, mydf3, mydf4]
#norm_factors = [drawSingle(ax_i, df, title)
#for ax_i, df, title in zip(ax.ravel(), dfs, ["Subplot1", "Subplot2", "Subplot3", "Subplot4"])]
for ax_i, df, title in zip(ax.ravel(), dfs, ["Subplot1", "Subplot2", "Subplot3", "Subplot4"]):
norm_factor, mu, sigma = drawSingle(ax_i, df, title)
norm_factors.append(norm_factor)
mus.append(mu)
sigmas.append(sigma)
for ax_i, norm_factor, mu, sigma in zip(ax.ravel(), norm_factors, mus, sigmas ):
ax_twin = ax_i.twinx()
xmax = ax_i.get_xlim()[1]
ax_twin.set_ylim(0, xmax / norm_factor)
ax_twin.set_ylabel("probablility dense",color="black",fontsize=12, weight = "bold")
CI_95_lower = mu - (1.96*sigma)
CI_95_upper = mu + (1.96*sigma)
px_shaded = np.arange(CI_95_lower,CI_95_upper,0.1)
ax_twin.fill_between(px_shaded,norm.pdf(px_shaded,loc=mu,scale=sigma) * norm_factor,alpha=0.75, color='pink')
area_shaded_95_CI = norm.cdf(x=CI_95_upper, loc=mu, scale=sigma)-norm.cdf(x=CI_95_lower, loc=mu, scale=sigma)
ax_twin.text(-0.06,0.01,str(round(area_shaded_95_CI*100,1))+"%", fontsize=20)
ax_twin.annotate(s=f'lower bound= {CI_95_lower:.3f}',xy=(CI_95_lower,norm.pdf(CI_95_lower,loc=mu,scale=sigma)),xytext=(-0.75,0.01),weight='bold',color='blue',\
arrowprops=dict(arrowstyle='-|>',connectionstyle='arc3',color='green'),\
fontsize=12
)
ax_twin.annotate(s=f'upper bound= {CI_95_upper:.3f}',xy=(CI_95_upper,norm.pdf(CI_95_upper,loc=mu,scale=sigma)),xytext=(0.28,0.01),weight='bold',color='blue',\
arrowprops=dict(arrowstyle='-|>',connectionstyle='arc3',color='green'),\
fontsize=12
)
ax_twin.text(0.05, 0.03, r"$\mu=" + f'{mu:.6f}' + ", \sigma=" + f'{sigma:.6f}' + "$" + ", confidence interval=95%" ,
horizontalalignment='center', fontsize=15)
plt.suptitle(title, fontsize=18)
plt.tight_layout()
plt.show()
df1, df2, df3, df4 = [pd.DataFrame({"gap": np.random.normal(0, 0.2, n)}) for n in [6000, 4000, 1800, 1200]]
drawSubplots(df1, df2, df3, df4, "Title")
请注意,使用
sharey=True
,行数较少的数据帧的直方图将更小。如果希望这些具有相似高度,则需要使用hist(…,density=True)
(将其面积缩放为1)对高度进行规格化。需要density=True
以正确拟合法线曲线。或者,用y\u normcrove
乘以len(xs)
,再乘以binwidth(y\u normcrove*len(xs)*(bins[1]-bins[0)
),使它们的面积相等。最好省去twinx()
并在同一ax
上绘制所有内容。此外,mu=np.mean(xs)
比mu=np.mean(x)更合适
。最后,使用y\u normcrove=norm.pdf(x,mu,sigma)
将曲线绘制为myax.plot(x,…)
Hi JohanC,非常感谢您的帮助!。我按照您的建议,在drawSingle函数中修改了代码。(设置密度=真)现在,正态分布曲线看起来比直方图更适合,但是每个图中的左Y轴不是频率。我还能有两个Y轴吗(左一个表示频率,右一个表示概率密度)?再次感谢!另外,我不太理解你的意思(Y_正态曲线*len(xs)*(bin[1]-bin[0))请您告诉我如何在代码中执行此操作?再次感谢!使用density=True
,y轴将是“概率分布函数”的高度。请注意“频率”只有当您有一个明确定义的箱子宽度时,才是有用的度量。如果您使用bins=200
,箱子宽度将(xs.max()-xs.min())/200
,这在4个图中是不同的。乘以(y_normcurve*len(xs)*(箱子[1]-箱子[0])
仅当您使用density=False
时才需要。嗨,JohanC,我找到了它。正确的方法是将我添加的所有代码移动到drawSingle函数中,在该函数中我使用myax绘制阴影区域并添加注释。非常感谢您的帮助!非常感谢!嗨,JohanC,关于正确的Y轴刻度还有一个困惑。我运行了Y我们的代码并指出,右Y轴刻度不反映概率密度的正确值。请您建议如何调整代码,使其准确显示概率密度的值。具体而言,所有高斯数的顶部约为Y=0.02,但请使用“norm.pdf(mu,loc=mu,scale=sigm