Python 平方误差和分布拟合 (SSE)
Python Distribution Fitting with Sum of Square Error (SSE)
我正在尝试找到适合我的数据的最佳分布曲线,其中包含
y-axis = [0, 0, 0, 0, 0.24, 0.53, 0.49, 0.64, 0.54, 0.78, 0.59, 0.44,
0.34, 0.88, 0.2, 0.49, 0.39, 0.39, 0.29, 0.2, 0.05, 0.05,
0.25, 0.05, 0.1, 0.15, 0.1, 0.1, 0.1, 0, 0, 0, 0, 0]
y 轴是事件在 x 轴时间段内发生的概率:
x-axis = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0,
12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0,
22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0,
32.0, 33.0, 34.0]
我在 python 中按照 Fitting empirical distribution to theoretical ones with Scipy (Python)?
上提供的示例执行此操作
具体来说,我正在尝试重新创建名为 'Distribution Fitting with Sum of Square Error (SSE)' 的部分,您可以在其中 运行 通过不同的分布找到适合数据的部分。
如何修改该示例以使其适用于我的数据输入?已回答
根据 Bill 的响应更新版本,但现在尝试根据数据绘制拟合曲线并发现有问题:
%matplotlib inline
import matplotlib.pyplot as plt
import scipy
import scipy.stats
import numpy as np
from scipy.stats import gamma, lognorm, loglaplace
from scipy.optimize import curve_fit
x_axis = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0]
y_axis = [0, 0, 0, 0, 0.24, 0.53, 0.49, 0.64, 0.54, 0.78, 0.59, 0.44, 0.34, 0.88, 0.2, 0.49, 0.39, 0.39, 0.29, 0.2, 0.05, 0.05, 0.25, 0.05, 0.1, 0.15, 0.1, 0.1, 0.1, 0, 0, 0, 0, 0]
matplotlib.rcParams['figure.figsize'] = (16.0, 12.0)
matplotlib.style.use('ggplot')
def f(x, a, loc, scale):
return gamma.pdf(x, a, loc, scale)
result, pcov = curve_fit(f, x_axis, y_axis)
# get curve shape, location, scale
shape = result[:-2]
loc = result[-2]
scale = result[-1]
# construct the curve
x = np.linspace(0, 36, 100)
y = f(x, *result)
plt.bar(x_axis, y_axis, width, alpha=0.75)
plt.plot(x, y, c='g')
您的情况与您引用的问题中处理的情况不一样。您同时拥有数据点的纵坐标和横坐标,而不是通常的 i.i.d。样本。我建议您使用 scipy curve_fit
。这是一个示例。
x_axis = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0]
y_axis = [0, 0, 0, 0, 0.24, 0.53, 0.49, 0.64, 0.54, 0.78, 0.59, 0.44, 0.34, 0.88, 0.2, 0.49, 0.39, 0.39, 0.29, 0.2, 0.05, 0.05, 0.25, 0.05, 0.1, 0.15, 0.1, 0.1, 0.1, 0, 0, 0, 0, 0]
## y_axis values must be normalised
sum_ys = sum(y_axis)
y_axis = [_/sum_ys for _ in y_axis]
print (sum(y_axis))
from scipy.stats import gamma, norm
from scipy.optimize import curve_fit
def gamma_f(x, a, loc, scale):
return gamma.pdf(x, a, loc, scale)
def norm_f(x, loc, scale):
return norm.pdf(x, loc, scale)
fitting = norm_f
result = curve_fit(fitting, x_axis, y_axis)
print (result)
import matplotlib.pyplot as plt
plt.plot(x_axis, y_axis, 'ro')
plt.plot(x_axis, [fitting(_, *result[0]) for _ in x_axis], 'b-')
plt.axis([0,35,0,.5])
plt.show()
此版本展示了如何绘制一个图,以正常拟合数据。 (gamma 拟合不佳。)法线只需要两个参数。一般来说,您只需要输出结果的第一部分,即参数、形状、位置和比例的估计值。
(array([ 2.3352639 , -3.08105104, 10.15024823]), array([[ 5954.86532869, -27818.92220973, -19675.22421994],
[ -27818.92220973, 133161.76500251, 90741.43608615],
[ -19675.22421994, 90741.43608615, 66054.79087992]]))
请注意,伽玛分布的 pdf 也可以在 scipy 中找到,我认为您需要的其他内容也可以,这样可以节省您编写代码的工作。
我从第一个代码中省略的最重要的事情是需要标准化 y 值,也就是说,使它们总和为 1,因为它们应该接近直方图高度。
我使用 OpenTURNS 平台尝试了您的示例
这是我得到的。
在导入 openturns 和 openturs.viewer.View 绘图后,我开始使用与您相同的数据
import openturns as ot
from openturns.viewer import View
x_axis = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0,
12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0,
22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0,
32.0, 33.0, 34.0]
y_axis = [0, 0, 0, 0, 0.24, 0.53, 0.49, 0.64, 0.54, 0.78, 0.59, 0.44,
0.34, 0.88, 0.2, 0.49, 0.39, 0.39, 0.29, 0.2, 0.05, 0.05,
0.25, 0.05, 0.1, 0.15, 0.1, 0.1, 0.1, 0, 0, 0, 0, 0]
第一步:我们可以定义对应的分布
distribution = ot.UserDefined(ot.Sample([[s] for s in x_axis]), y_axis)
graph = distribution.drawPDF()
graph.setColors(["black"])
graph.setLegends(["your input"])
在这个阶段,如果你View(graph)
你会得到:
第二步:我们可以从获得的分布中推导出样本
sample = distribution.getSample(10000)
此示例将用于拟合任何类型的分布。我尝试使用 WeibullMin 和 Gamma 分布
# WeibullMin Factory
distribution2 = ot.WeibullMinFactory().build(sample)
print(distribution2)
graph2 = distribution2.drawPDF() ; graph2.setLegends(["Best WeibullMin"])
>>> WeibullMin(beta = 8.83969, alpha = 1.48142, gamma = 4.76832)
# Gamma Factory
distribution3 = ot.GammaFactory().build(sample)
print(distribution3)
>>> Gamma(k = 2.08142, lambda = 0.25157, gamma = 4.9995)
graph3 = distribution3.drawPDF() ; graph3.setLegends(["Best Gamma"]) ;
graph3.setColors(["blue"])
# plotting all the results
graph.add(graph2) ; graph.add(graph3)
View(graph)
我认为这是计算误差平方和的最好最简单的方法:
#编写函数
def SSE(y_true, y_pred):
sse= np.sum((y_true-y_pred)**2)
print(sse)
#now call the function and get results
SSE(y_true, y_pred)
我正在尝试找到适合我的数据的最佳分布曲线,其中包含
y-axis = [0, 0, 0, 0, 0.24, 0.53, 0.49, 0.64, 0.54, 0.78, 0.59, 0.44,
0.34, 0.88, 0.2, 0.49, 0.39, 0.39, 0.29, 0.2, 0.05, 0.05,
0.25, 0.05, 0.1, 0.15, 0.1, 0.1, 0.1, 0, 0, 0, 0, 0]
y 轴是事件在 x 轴时间段内发生的概率:
x-axis = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0,
12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0,
22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0,
32.0, 33.0, 34.0]
我在 python 中按照 Fitting empirical distribution to theoretical ones with Scipy (Python)?
上提供的示例执行此操作具体来说,我正在尝试重新创建名为 'Distribution Fitting with Sum of Square Error (SSE)' 的部分,您可以在其中 运行 通过不同的分布找到适合数据的部分。
如何修改该示例以使其适用于我的数据输入?已回答
根据 Bill 的响应更新版本,但现在尝试根据数据绘制拟合曲线并发现有问题:
%matplotlib inline
import matplotlib.pyplot as plt
import scipy
import scipy.stats
import numpy as np
from scipy.stats import gamma, lognorm, loglaplace
from scipy.optimize import curve_fit
x_axis = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0]
y_axis = [0, 0, 0, 0, 0.24, 0.53, 0.49, 0.64, 0.54, 0.78, 0.59, 0.44, 0.34, 0.88, 0.2, 0.49, 0.39, 0.39, 0.29, 0.2, 0.05, 0.05, 0.25, 0.05, 0.1, 0.15, 0.1, 0.1, 0.1, 0, 0, 0, 0, 0]
matplotlib.rcParams['figure.figsize'] = (16.0, 12.0)
matplotlib.style.use('ggplot')
def f(x, a, loc, scale):
return gamma.pdf(x, a, loc, scale)
result, pcov = curve_fit(f, x_axis, y_axis)
# get curve shape, location, scale
shape = result[:-2]
loc = result[-2]
scale = result[-1]
# construct the curve
x = np.linspace(0, 36, 100)
y = f(x, *result)
plt.bar(x_axis, y_axis, width, alpha=0.75)
plt.plot(x, y, c='g')
您的情况与您引用的问题中处理的情况不一样。您同时拥有数据点的纵坐标和横坐标,而不是通常的 i.i.d。样本。我建议您使用 scipy curve_fit
。这是一个示例。
x_axis = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, 34.0]
y_axis = [0, 0, 0, 0, 0.24, 0.53, 0.49, 0.64, 0.54, 0.78, 0.59, 0.44, 0.34, 0.88, 0.2, 0.49, 0.39, 0.39, 0.29, 0.2, 0.05, 0.05, 0.25, 0.05, 0.1, 0.15, 0.1, 0.1, 0.1, 0, 0, 0, 0, 0]
## y_axis values must be normalised
sum_ys = sum(y_axis)
y_axis = [_/sum_ys for _ in y_axis]
print (sum(y_axis))
from scipy.stats import gamma, norm
from scipy.optimize import curve_fit
def gamma_f(x, a, loc, scale):
return gamma.pdf(x, a, loc, scale)
def norm_f(x, loc, scale):
return norm.pdf(x, loc, scale)
fitting = norm_f
result = curve_fit(fitting, x_axis, y_axis)
print (result)
import matplotlib.pyplot as plt
plt.plot(x_axis, y_axis, 'ro')
plt.plot(x_axis, [fitting(_, *result[0]) for _ in x_axis], 'b-')
plt.axis([0,35,0,.5])
plt.show()
此版本展示了如何绘制一个图,以正常拟合数据。 (gamma 拟合不佳。)法线只需要两个参数。一般来说,您只需要输出结果的第一部分,即参数、形状、位置和比例的估计值。
(array([ 2.3352639 , -3.08105104, 10.15024823]), array([[ 5954.86532869, -27818.92220973, -19675.22421994],
[ -27818.92220973, 133161.76500251, 90741.43608615],
[ -19675.22421994, 90741.43608615, 66054.79087992]]))
请注意,伽玛分布的 pdf 也可以在 scipy 中找到,我认为您需要的其他内容也可以,这样可以节省您编写代码的工作。
我从第一个代码中省略的最重要的事情是需要标准化 y 值,也就是说,使它们总和为 1,因为它们应该接近直方图高度。
我使用 OpenTURNS 平台尝试了您的示例 这是我得到的。
在导入 openturns 和 openturs.viewer.View 绘图后,我开始使用与您相同的数据
import openturns as ot
from openturns.viewer import View
x_axis = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0,
12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0,
22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0,
32.0, 33.0, 34.0]
y_axis = [0, 0, 0, 0, 0.24, 0.53, 0.49, 0.64, 0.54, 0.78, 0.59, 0.44,
0.34, 0.88, 0.2, 0.49, 0.39, 0.39, 0.29, 0.2, 0.05, 0.05,
0.25, 0.05, 0.1, 0.15, 0.1, 0.1, 0.1, 0, 0, 0, 0, 0]
第一步:我们可以定义对应的分布
distribution = ot.UserDefined(ot.Sample([[s] for s in x_axis]), y_axis)
graph = distribution.drawPDF()
graph.setColors(["black"])
graph.setLegends(["your input"])
在这个阶段,如果你View(graph)
你会得到:
第二步:我们可以从获得的分布中推导出样本
sample = distribution.getSample(10000)
此示例将用于拟合任何类型的分布。我尝试使用 WeibullMin 和 Gamma 分布
# WeibullMin Factory
distribution2 = ot.WeibullMinFactory().build(sample)
print(distribution2)
graph2 = distribution2.drawPDF() ; graph2.setLegends(["Best WeibullMin"])
>>> WeibullMin(beta = 8.83969, alpha = 1.48142, gamma = 4.76832)
# Gamma Factory
distribution3 = ot.GammaFactory().build(sample)
print(distribution3)
>>> Gamma(k = 2.08142, lambda = 0.25157, gamma = 4.9995)
graph3 = distribution3.drawPDF() ; graph3.setLegends(["Best Gamma"]) ;
graph3.setColors(["blue"])
# plotting all the results
graph.add(graph2) ; graph.add(graph3)
View(graph)
我认为这是计算误差平方和的最好最简单的方法:
#编写函数
def SSE(y_true, y_pred):
sse= np.sum((y_true-y_pred)**2)
print(sse)
#now call the function and get results
SSE(y_true, y_pred)