31

互いにシグモイド関係にある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は、最大テスト条件でのさまざまなテスト参加者からの値の範囲の平均です。


以下の2番目の編集:

ありがとう、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は任意の数の要素を持つことができますか?

4

4 に答える 4

42

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 など) には、よりも使いやすいscipy.optimize.curve_fitleastsq関数もあることに注意してください。を使用したシグモイドのフィッティングに関する関連する議論は、ここcurve_fitで見つけることができます。

編集:resize生データを再スケーリングして任意のバウンディング ボックスに合わせてシフトできるように機能が追加されました。


「あなたの名前は、scipy ドキュメントのライターとして表示されるようです」

免責事項: 私は scipy ドキュメントのライターではありません。私はただのユーザーであり、初心者です。私が知っていることの多くは、Travis Oliphant によって書かれたこのチュートリアルleastsqを読むことから得ています。

1.) leastsq() は、入力 y ベクトルと sigmoid() 関数によって返された y ベクトルの差を返すresiduals() を呼び出しますか?

はい!まさに。

もしそうなら、入力 y-vector と sigmoid() 関数によって返された y-vector の長さの違いはどのように説明されますか?

長さは同じです:

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 配列を作成するとckx0y0フロートの場合、方程式はyと同じ形状の numpy 配列であると定義されxます。したがってsigmoid(p,x)、numpy 配列を返します。これがnumpybookでどのように機能するかについてのより完全な説明があります(numpy の本格的なユーザーは必読)。

2.) 数学関数を呼び出すresiduals関数を介してその数学方程式にアクセスする限り、任意の数学方程式に対して leastsq() を呼び出すことができるようです。これは本当ですか?

真実。leastsq残差 (差) の二乗和を最小化しようとします。パラメータ空間 ( のすべての可能な値) を検索して、平方和を最小化する をp探します。pxy送信されるresidualsは、生データ値です。それらは固定されています。彼らは変わりません。最小化しようとするのはps (シグモイド関数のパラメーター) です。leastsq

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 乗され、合計されます。これは打つべき数です。次に、 を最小化する一連の値を探すようにp_guess変化させます。leastsqresiduals(p_guess,x,y)

4.)residuals() および sigmoid() 関数に引数として送信される p は、leastsq() によって出力される同じ p であり、leastsq() 関数は、それを返す前にその p を内部的に使用していますか?

まあ、正確ではありません。ご存じのとおり、はを最小化する値を検索するときにp_guess変化します。に送信される(er, ) は、によって返されると同じ形をしています。あなたが推測の地獄でない限り、明らかに値は異なるはずです:)leastsqpresiduals(p,x,y)pp_guessleastsqpleastsq

5.) p と p_guess は、p の要素数が p_guess の要素数と等しい限り、モデルとして使用される方程式の複雑さに応じて、任意の数の要素を持つことができますか?

はい。leastsq非常に多くのパラメーターのストレス テストは行っていませんが、非常に強力なツールです。

于 2010-11-29T22:06:12.367 に答える
2

どの程度の多項式近似でも良い結果が得られるとは思いません-すべての多項式は十分に大きいXと小さいXに対して無限大になりますが、シグモイド曲線は漸近的に各方向の有限値に近づきます。

私は Python プログラマーではないので、numpy にもっと一般的なカーブ フィッティング ルーチンがあるかどうかはわかりません。自作する必要がある場合は、ロジスティック回帰に関するこの記事でアイデアが得られるかもしれません。

于 2010-11-29T21:34:55.907 に答える
2

Python でのロジスティック回帰の場合、scikits-learnは高性能フィッティング コードを公開します。

http://scikit-learn.sourceforge.net/modules/linear_model.html#logistic-regression

于 2011-04-28T10:02:26.697 に答える