互いにややシグモイド関係にある2つの変数(xとy)があり、xの値が与えられた場合に、yの値を予測できるような予測式を見つける必要があります。私の予測式は、2つの変数間のややシグモイド関係を示す必要があります。したがって、線を生成する線形回帰方程式を決定することはできません。 2つの変数のグラフの左右両方で発生する、勾配の緩やかな曲線変化を確認する必要があります。
曲線回帰とPythonをグーグルで調べた後、numpy.polyfitを使い始めましたが、以下のコードを実行すると、ひどい結果が得られました。 必要なタイプのシグモイド回帰方程式を取得するために、以下のコードを書き直す方法を教えてもらえますか?
以下のコードを実行すると、下向きの放物線が表示されることがわかります。これは、変数間の関係がどのように見えるかではありません。代わりに、2つの変数の間にシグモイド関係がもっとあるはずですが、以下のコードで使用しているデータと密接に適合しています。以下のコードのデータは、大規模なサンプルの調査研究からの平均であるため、5つのデータポイントが示唆するよりも多くの統計的検出力を備えています。大規模なサンプルの調査研究からの実際のデータはありませんが、以下の平均とそれらの標準偏差(表示していません)はあります。以下にリストされている平均データを使用して単純な関数をプロットすることをお勧めしますが、複雑さが大幅な改善をもたらす場合、コードはより複雑になる可能性があります。
コードを変更して、シグモイド関数に最適なものを表示するにはどうすればよいですか?できればscipy、numpy、pythonを使用しますか?これが私のコードの現在のバージョンであり、修正する必要があります:
import numpy as np
import matplotlib.pyplot as plt
# Create numpy data arrays
x = np.array([821,576,473,377,326])
y = np.array([255,235,208,166,157])
# Use polyfit and poly1d to create the regression equation
z = np.polyfit(x, y, 3)
p = np.poly1d(z)
xp = np.linspace(100, 1600, 1500)
pxp=p(xp)
# Plot the results
plt.plot(x, y, '.', xp, pxp, '-')
plt.ylim(140,310)
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)
plt.show()
あなたの反応とそのスピードはとても印象的です。ありがとう、うぬぶ。しかし、より有効な結果を生成するには、データ値を再構成する必要があります。これは、x値を最大x値のパーセンテージとして再キャストし、y値を元のデータのx値のパーセンテージとして再キャストすることを意味します。私はあなたのコードでこれをやろうとしました、そして次のことを思いつきました:
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize
# Create numpy data arrays
'''
# Comment out original data
#x = np.array([821,576,473,377,326])
#y = np.array([255,235,208,166,157])
'''
# Re-calculate x values as a percentage of the first (maximum)
# original x value above
x = np.array([1.000,0.702,0.576,0.459,0.397])
# Recalculate y values as a percentage of their respective x values
# from original data above
y = np.array([0.311,0.408,0.440,0.440,0.482])
def sigmoid(p,x):
x0,y0,c,k=p
y = c / (1 + np.exp(-k*(x-x0))) + y0
return y
def residuals(p,x,y):
return y - sigmoid(p,x)
p_guess=(600,200,100,0.01)
(p,
cov,
infodict,
mesg,
ier)=scipy.optimize.leastsq(residuals,p_guess,args=(x,y),full_output=1,warning=True)
'''
# comment out original xp to allow for better scaling of
# new values
#xp = np.linspace(100, 1600, 1500)
'''
xp = np.linspace(0, 1.1, 1100)
pxp=sigmoid(p,xp)
x0,y0,c,k=p
print('''\
x0 = {x0}
y0 = {y0}
c = {c}
k = {k}
'''.format(x0=x0,y0=y0,c=c,k=k))
# Plot the results
plt.plot(x, y, '.', xp, pxp, '-')
plt.ylim(0,1)
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)
plt.show()
この改訂されたコードを修正する方法を教えていただけますか?
注:データを再キャストすることにより、基本的に2d(x、y)シグモイドをz軸を中心に180度回転しました。また、1.000は実際には最大値ではありません。 x値。代わりに、1.000は、最大テスト条件でのさまざまなテスト参加者からの値の範囲の平均です。
ありがとう、ubuntu。私はあなたのコードを注意深く読み、scipyのドキュメントでその側面を調べました。あなたの名前はscipyドキュメントのライターとしてポップアップしているようですので、次の質問に答えていただければ幸いです。
1.)leastsq()はresiduals()を呼び出しますか?これにより、入力yベクトルとsigmoid()関数によって返されるyベクトルの差が返されますか?もしそうなら、それは入力yベクトルとsigmoid()関数によって返されるyベクトルの長さの違いをどのように説明しますか?
2.)残余関数を介してその数学方程式にアクセスし、次に数学関数を呼び出す限り、任意の数学方程式に対してleastsq()を呼び出すことができるように見えます。これは本当ですか?
3.)また、p_guessにはpと同じ数の要素があることに気付きました。これは、p_guessの4つの要素が、x0、y0、c、およびkによって返される値とそれぞれ順番に対応していることを意味しますか?
4.)residuals()およびsigmoid()関数に引数として送信されるpは、leastsq()によって出力されるpと同じであり、leastsq()関数はそのpを内部で使用してから返しますか?
5.)pの要素の数がp_guessの要素の数と等しい限り、モデルとして使用されている方程式の複雑さに応じて、pとp_guessは任意の数の要素を持つことができますか?
scipy.optimize.leastsq を使用する:
_import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize
def sigmoid(p,x):
x0,y0,c,k=p
y = c / (1 + np.exp(-k*(x-x0))) + y0
return y
def residuals(p,x,y):
return y - sigmoid(p,x)
def resize(arr,lower=0.0,upper=1.0):
arr=arr.copy()
if lower>upper: lower,upper=upper,lower
arr -= arr.min()
arr *= (upper-lower)/arr.max()
arr += lower
return arr
# raw data
x = np.array([821,576,473,377,326],dtype='float')
y = np.array([255,235,208,166,157],dtype='float')
x=resize(-x,lower=0.3)
y=resize(y,lower=0.3)
print(x)
print(y)
p_guess=(np.median(x),np.median(y),1.0,1.0)
p, cov, infodict, mesg, ier = scipy.optimize.leastsq(
residuals,p_guess,args=(x,y),full_output=1,warning=True)
x0,y0,c,k=p
print('''\
x0 = {x0}
y0 = {y0}
c = {c}
k = {k}
'''.format(x0=x0,y0=y0,c=c,k=k))
xp = np.linspace(0, 1.1, 1500)
pxp=sigmoid(p,xp)
# Plot the results
plt.plot(x, y, '.', xp, pxp, '-')
plt.xlabel('x')
plt.ylabel('y',rotation='horizontal')
plt.grid(True)
plt.show()
_
収量
シグモイドパラメータを使用
_x0 = 0.826964424481
y0 = 0.151506745435
c = 0.848564826467
k = -9.54442292022
_
新しいバージョンのscipy(0.9など)には、leastsq
よりも使いやすい scipy.optimize.curve_fit 関数もあることに注意してください。 _curve_fit
_を使用したシグモイドのフィッティングに関する関連する議論は ここ にあります。
編集:resize
関数が追加され、生データを再スケーリングおよびシフトして、任意の境界ボックスに合わせることができるようになりました。
「あなたの名前はscipyドキュメントのライターとしてポップアップするようです」
免責事項:私はscipyドキュメントの作成者ではありません。私はただのユーザーであり、その初心者です。 leastsq
について私が知っていることの多くは、Travis Oliphantによって書かれた このチュートリアル を読むことから来ています。
1.)leastsq()はresiduals()を呼び出しますか?これは、入力yベクトルとsigmoid()関数によって返されるyベクトルの差を返しますか?
はい!丁度。
もしそうなら、それは入力yベクトルとsigmoid()関数によって返されるyベクトルの長さの違いをどのように説明しますか?
長さは同じです:
_In [138]: x
Out[138]: array([821, 576, 473, 377, 326])
In [139]: y
Out[139]: array([255, 235, 208, 166, 157])
In [140]: p=(600,200,100,0.01)
In [141]: sigmoid(p,x)
Out[141]:
array([ 290.11439268, 244.02863507, 221.92572521, 209.7088641 ,
206.06539033])
_
Numpyのすばらしい点の1つは、配列全体を操作する「ベクトル」方程式を記述できることです。
_y = c / (1 + np.exp(-k*(x-x0))) + y0
_
フロートで動作するように見えるかもしれませんが(実際は動作します)、x
をnumpy配列にし、c
、k
、_x0
_、_y0
_が浮動する場合、方程式はy
をx
と同じ形状のnumpy配列として定義します。したがって、sigmoid(p,x)
はnumpy配列を返します。これがどのように機能するかについてのより完全な説明が numpybook (numpyの深刻なユーザーのために読む必要があります)にあります。
2.)残余関数を介してその数学方程式にアクセスし、次に数学関数を呼び出す限り、任意の数学方程式に対してleastsq()を呼び出すことができるように見えます。これは本当ですか?
本当。 leastsq
は、残差(差)の二乗和を最小化しようとします。パラメータ空間(p
のすべての可能な値)を検索して、その二乗和を最小化するp
を探します。 x
に送信されるy
とresiduals
は、生データ値です。それらは修正されています。それらは変わりません。 p
が最小化しようとするのは、leastsq
s(シグモイド関数のパラメーター)です。
3.)また、p_guessにはpと同じ数の要素があることに気付きました。これは、p_guessの4つの要素が、x0、y0、c、およびkによって返される値とそれぞれ順番に対応していることを意味しますか?
まさにそうです!ニュートン法と同様に、leastsq
にはp
の初期推定が必要です。 _p_guess
_として提供します。あなたが見るとき
_scipy.optimize.leastsq(residuals,p_guess,args=(x,y))
_
最初のパスとして、leastsqアルゴリズム(実際にはLevenburg-Marquardtアルゴリズム)の一部として、leastsqがresiduals(p_guess,x,y)
を呼び出すと考えることができます。間の視覚的な類似性に注意してください
_(residuals,p_guess,args=(x,y))
_
そして
_residuals(p_guess,x,y)
_
leastsq
への引数の順序と意味を覚えておくと役立つ場合があります。
residuals
は、sigmoid
のようにnumpy配列を返します。配列の値は2乗されてから、合計されます。これは打ち負かす数です。次に、leastsq
がresiduals(p_guess,x,y)
を最小化する値のセットを探すときに、_p_guess
_が変化します。
4.)residuals()およびsigmoid()関数に引数として送信されるpは、leastsq()によって出力されるpと同じであり、leastsq()関数はそのpを内部で使用してから返しますか?
まあ、正確ではありません。ご存知のように、leastsq
がresiduals(p,x,y)
を最小化するp
値を検索すると、_p_guess
_は変化します。 p
に送信されるleastsq
(er、_p_guess
_)は、p
によって返されるleastsq
と同じ形状です。あなたが推測者の地獄でない限り、明らかに値は異なるはずです:)
5.)pの要素の数がp_guessの要素の数と等しい限り、モデルとして使用されている方程式の複雑さに応じて、pとp_guessは任意の数の要素を持つことができますか?
はい。非常に多くのパラメーターについてleastsq
のストレステストを行っていませんが、これはスリル満点の強力なツールです。
すべての多項式は十分に大きいXと小さいXに対して無限大になりますが、シグモイド曲線は各方向である有限値に漸近的に近づくため、どの程度の多項式近似でも良い結果が得られるとは思いません。
私はPythonプログラマーではないので、numpyにもっと一般的なカーブフィッティングルーチンがあるかどうかはわかりません。自分でロールする必要がある場合は、おそらくこの記事 ロジスティック回帰 はあなたにいくつかのアイデアを与えるでしょう。
Pythonでのロジスティック回帰の場合、 scikits-learn は高性能のフィッティングコードを公開します。
http://scikit-learn.sourceforge.net/modules/linear_model.html#logistic-regression
上記の@unutbuで指摘されているように、scipy
は、より複雑でない呼び出しを持つ scipy.optimize.curve_fit を提供します。同じプロセスがこれらの用語でどのように見えるかについての簡単なバージョンが必要な場合は、以下に最小限の例を示します。
def sigmoid(x, k, x0):
return 1.0 / (1 + np.exp(-k * (x - x0)))
# Parameters of the true function
n_samples = 1000
true_x0 = 15
true_k = 1.5
sigma = 0.2
# Build the true function and add some noise
x = np.linspace(0, 30, num=n_samples)
y = sigmoid(x, k=true_k, x0=true_x0)
y_with_noise = y + sigma * np.random.randn(n_samples)
# Sample the data from the real function (this will be your data)
some_points = np.random.choice(1000, size=30) # take 30 data points
xdata = x[some_points]
ydata = y_with_noise[some_points]
# Fit the curve
popt, pcov = curve_fit(return_sigmoid, xdata, ydata)
estimated_k, estimated_x0 = popt
# Plot the fitted curve
y_fitted = sigmoid(x, k=estimated_k, x0=estimated_x0)
# Plot everything for illustration
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y_fitted, '--', label='fitted')
ax.plot(x, y, '-', label='true')
ax.plot(xdata, ydata, 'o', label='samples')
ax.legend()
この結果を次の図に示します。