[英]Scipy - How can I improve this curve fitting - finding the right function
我試圖找到兩個變量(pv_ratio,battery_ratio)和第三個變量“ value”之間的關系。 兩種比率的范圍從0到5,每0.0625點(81x81 = 6561點),並且“值”在[0,1]內。
可以在此處找到csv,如下所示:
battery_ratio pv_ratio value
0 0.0000 0 1
1 0.0625 0 1
2 0.1250 0 1
3 0.1875 0 1
4 0.2500 0 1
5 0.3125 0 1
6 0.3750 0 1
7 0.4375 0 1
8 0.5000 0 1
9 0.5625 0 1
這是使用sicpy.optimize.curve_fit並尋找指數關系來擬合曲線的代碼。 此代碼段將csv讀入pandas df,找到f函數的最佳參數,繪制結果並給出擬合度。
我一直以迭代的方式工作,嘗試了很多f的公式,並逐漸提高了分數。
from scipy.optimize import curve_fit
import pandas as pd
import numpy as np
import matplotlib.pylab as plt
%matplotlib inline
plt.rcParams['figure.figsize'] = (14.0, 8.0)
def f(X, a, b, c, d, e):
# the function I came up with after some trials, and which I'm trying to improve
bt_r = X[:,0] #battery_ratio
pv_r = X[:,1] #pv_ratio
return (1 - a * np.exp(- e * pv_r ** b)) * np.exp(- (d ** bt_r) * c * pv_r)
def fit():
#find optimal parameters and score fit
X = df[variables].values
y = df.value.values
popt, pcov = curve_fit(f, X, y)
y_real, y_fit = df['value'], f(df[variables].values, *popt)
score = np.round(np.sum(((y_fit - y_real)**2)),1)
return popt, score
def check_fit(values):
#Plot (y_fit, y) for all subsets
def plot_subset(ax, variable, r_value):
"""Scatter plot (y_fit and y) against 'variable' with the other variable set at ratio
- variable : string ['pv_ratio', 'battery_ratio']
- r_value : float
"""
# ratio stands for the second variable which is fixed
ratio = list(set(variables) - set([variable]))[0]
df_ = df.query("{} == {}".format(ratio, r_value))
# plot y and y fit
y_real, y_fit = df_['value'], f(df_[variables].values, *popt)
for y, c in zip([y_real, y_fit], ['b', 'r']):
ax.scatter(df_[variable], y, color=c, s=10, alpha=0.95)
ax.set_title('{} = {}'.format(ratio, r_value))
fig, ax = plt.subplots(nrows=2, ncols=len(values), sharex=True, sharey=True)
for icol, r_value in enumerate(values):
plot_subset(ax[0, icol], 'pv_ratio', r_value)
plot_subset(ax[1, icol], 'battery_ratio', r_value)
fig.tight_layout()
print 'Score: {}'.format(score)
df = pd.read_csv('data.csv', index_col=0)
variables = ['battery_ratio', 'pv_ratio']
popt, score = fit()
check_fit([0,3,5]) #plot y_real and y_fit for these ratios
上面的代碼產生以下圖片(藍色:真實,紅色:合適),並給出合適的分數。 我可以獲得的最高分數(
=sum((y_real - y_fit)²/len(y))
)是9.3e-4,在實踐中,尤其是在加速階段,這仍然不是很好。
現在,我陷入了嘗試重復過程顯示其局限性的地步。 我應該如何工作以更快,更有效地設計我的試衣功能? 我可以得到比6.1高的分數嗎?
謝謝你的幫助
歸一化分數
正如@ jon-custer所建議的那樣,我嘗試了n多項式擬合。 我的代碼是此 SO答案的略微修改版本。
import itertools
import numpy as np
import matplotlib.pyplot as plt
def polyfit2d(data, order=3):
x = data.pv_ratio
y = data.battery_ratio
z = data.value
ncols = (order + 1)**2
G = np.zeros((x.size, ncols))
ij = itertools.product(range(order+1), range(order+1))
for k, (i,j) in enumerate(ij):
G[:,k] = x**i * y**j
m, _, _, _ = np.linalg.lstsq(G, z)
y['fit'] = polyval2d(x, y, m)
return m, y_fit
def polyval2d(x, y, m):
order = int(np.sqrt(len(m))) - 1
ij = itertools.product(range(order+1), range(order+1))
z = np.zeros_like(x)
for a, (i,j) in zip(m, ij):
z += a * x**i * y**j
return z
m, y_fit = polyfit2d(df, 7)
上表顯示了最大殘差和歸一化分數。 我得到的最好結果是7級多項式。 我的分數下降到〜6.4e-5,殘差從未大於5.5%,這是我可以接受的精度。
謝謝。
我發現了這個舊線程,並且我認為它可以以某種方式幫助某人。
這不完全是與python相關的線程,您希望將數據放入表面。
還原數據。 將值做1 / x,並逐行繪制一條趨勢線。 你做到了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.