用Python拟合直方图
我有一个直方图
H=hist(my_data,bins=my_bin,histtype='step',color='r')
我发现这个直方图的形状看起来差不多是个高斯分布,但我想用一个高斯函数来拟合这个直方图,并打印出我得到的平均值和标准差。你能帮我吗?
5 个回答
10
从 Python 3.8
开始,标准库里新增了一个叫 NormalDist
的对象,它是 statistics
模块的一部分。
你可以通过一组数据来创建 NormalDist
对象,使用的方法是 NormalDist.from_samples
。这个对象可以让你获取它的 平均值 (NormalDist.mean
) 和 标准差 (NormalDist.stdev
):
from statistics import NormalDist
# data = [0.7237248252340628, 0.6402731706462489, -1.0616113628912391, -1.7796451823371144, -0.1475852030122049, 0.5617952240065559, -0.6371760932160501, -0.7257277223562687, 1.699633029946764, 0.2155375969350495, -0.33371076371293323, 0.1905125348631894, -0.8175477853425216, -1.7549449090704003, -0.512427115804309, 0.9720486316086447, 0.6248742504909869, 0.7450655841312533, -0.1451632129830228, -1.0252663611514108]
norm = NormalDist.from_samples(data)
# NormalDist(mu=-0.12836704320073597, sigma=0.9240861018557649)
norm.mean
# -0.12836704320073597
norm.stdev
# 0.9240861018557649
30
这里有一个例子,使用了scipy.optimize这个工具来拟合像高斯这样的非线性函数。即使数据是以直方图的形式呈现,而且范围不太好,这种方法也能有效工作,因为简单的平均值估计在这种情况下可能会失败。此外,如果有一个偏移常数,简单的统计方法也会失效(如果是普通的高斯数据,可以去掉p[3]和c[3])。
from pylab import *
from numpy import loadtxt
from scipy.optimize import leastsq
fitfunc = lambda p, x: p[0]*exp(-0.5*((x-p[1])/p[2])**2)+p[3]
errfunc = lambda p, x, y: (y - fitfunc(p, x))
filename = "gaussdata.csv"
data = loadtxt(filename,skiprows=1,delimiter=',')
xdata = data[:,0]
ydata = data[:,1]
init = [1.0, 0.5, 0.5, 0.5]
out = leastsq( errfunc, init, args=(xdata, ydata))
c = out[0]
print "A exp[-0.5((x-mu)/sigma)^2] + k "
print "Parent Coefficients:"
print "1.000, 0.200, 0.300, 0.625"
print "Fit Coefficients:"
print c[0],c[1],abs(c[2]),c[3]
plot(xdata, fitfunc(c, xdata))
plot(xdata, ydata)
title(r'$A = %.3f\ \mu = %.3f\ \sigma = %.3f\ k = %.3f $' %(c[0],c[1],abs(c[2]),c[3]));
show()
输出结果:
A exp[-0.5((x-mu)/sigma)^2] + k
Parent Coefficients:
1.000, 0.200, 0.300, 0.625
Fit Coefficients:
0.961231625289 0.197254597618 0.293989275502 0.65370344131
83
这里有一个在py2.6和py3.2上运行的示例:
from scipy.stats import norm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
# read data from a text file. One number per line
arch = "test/Log(2)_ACRatio.txt"
datos = []
for item in open(arch,'r'):
item = item.strip()
if item != '':
try:
datos.append(float(item))
except ValueError:
pass
# best fit of data
(mu, sigma) = norm.fit(datos)
# the histogram of the data
n, bins, patches = plt.hist(datos, 60, normed=1, facecolor='green', alpha=0.75)
# add a 'best fit' line
y = mlab.normpdf( bins, mu, sigma)
l = plt.plot(bins, y, 'r--', linewidth=2)
#plot
plt.xlabel('Smarts')
plt.ylabel('Probability')
plt.title(r'$\mathrm{Histogram\ of\ IQ:}\ \mu=%.3f,\ \sigma=%.3f$' %(mu, sigma))
plt.grid(True)
plt.show()