簡體   English   中英

將R中的曲線擬合到方程

[英]Fitting a curve in R to an equation

我一直在嘗試在R上擬合曲線,但是有一些問題。 我正在處理組成x和y坐標的幾個大數據集。 當使用ggplot的geom_point或任何其他繪圖函數進行繪圖時,存在一種趨勢,該繪圖趨於類似於平方根函數的圖。

這將是使用我使用的geom_smooth進行擬合的代碼:

plt = ggplot(data = data2, aes(x = x, y = y)) + geom_point() +geom_smooth()

這基本上讓我明白了這一點:

曲線圖

有沒有一種方法可以使曲線更像紅色平方根曲線(y = x ^ 0.5)-基本上使它更平滑並相應地適合某個公式? 以最小的數據集為例。

數據集CSV格式示例

我也嘗試過將方法擬合為黃土,這使曲線接近我想要的,但對於更大(約500,000-700,000點)或某些點非常密集地封裝在某些點中的數據集區域黃土似乎不起作用。 均值存在某種偏斜的趨勢,這是有道理的,因為該區域的大量點將其推高了。 但是我需要擬合曲線並迫使其接近平方根曲線。 我也嘗試過弄亂跨度值,但這並沒有真正影響曲線的平滑度。

我想到的一件事是以下內容。 最好的圖形可能是通過最小化卡方來評估的。 您可以對此附加標准,即,該擬合度與平方根行為的偏離量為多少。 這可以通過使用sqrt()擬合解決方案並將加權卡方平方添加到對擬合質量的總體評估中來完成。 不知道如何執行R ,但是在python中,您得到的是這樣的: 增加sqrt的重量 藍色圖將是最合適的sqrt() 黃色的是最好的二次樣條,其結點為[0,0,.1,.2,.3,.4,.6,.9,.9,.9] ,即weight=0 (您還可以優化結位置,在此不做)。 然后,我們增加權重以通過sqrt()分別擬合weights = 0.5,1,2weights = 0.5,1,2分別weights = 0.5,1,2

代碼如下:

import matplotlib
matplotlib.use('Qt4Agg')

from matplotlib import pyplot as plt
import numpy as np
from scipy.optimize import leastsq,curve_fit

###from the scipy doc page as I have scipy 0.16 and no build in BSpline, yet
def B(x, k, i, t):
    if k == 0:
        return 1.0 if t[i] <= x < t[i+1] else 0.0
    if t[i+k] == t[i]:
        c1 = 0.0
    else:
        c1 = (x - t[i])/(t[i+k] - t[i]) * B(x, k-1, i, t)
    if t[i+k+1] == t[i+1]:
        c2 = 0.0
    else:
        c2 = (t[i+k+1] - x)/(t[i+k+1] - t[i+1]) * B(x, k-1, i+1, t)
    return c1 + c2


def bspline(x, t, c, k):
    n = len(t) - k - 1
    assert (n >= k+1) and (len(c) >= n)
    return sum(c[i] * B(x, k, i, t) for i in range(n))


def mixed_res(params,points,weight):
    [xList,yList] = zip(*points)
    bSplList=[bspline(x,[0,0,.1,.2,.3,.4,.6,.9,.9,.9],params,2) for x in xList]
    ###standard chisq
    diffTrue=[y-b for y,b in zip(yList,bSplList)]
    ###how good can the spline be fitted with sqrt
    locfit,_=curve_fit(sqrtfunc,xList,bSplList)
    sqrtList=[sqrtfunc(x,locfit[0]) for x in xList]
    diffWeight=[ weight*(s-b) for s,b in zip(sqrtList,bSplList)]
    return diffTrue+diffWeight

def sqrtfunc(x,a):
    return a*np.sqrt(x)


xList,yList=np.loadtxt("PHOQSTACK.csv", unpack=True, delimiter=',')
xListSorted=sorted(xList)
zipData=zip(xList,yList)

fig=plt.figure(1)
ax=fig.add_subplot(1,1,1)

knotList=[0,0,.1,.2,.3,.4,.6,.9,.9,.9]
order=2

sqrtvalues,_=curve_fit(sqrtfunc,xList,yList)
th_sqrt_y=[sqrtfunc(x,sqrtvalues[0]) for x in xListSorted]

ax.scatter(xList,yList,s=1)
ax.plot(xListSorted,th_sqrt_y)

fitVals=[.2,.3,.4,.2,.3,.4,.2]
for s in [0,.5,1,2]:
    print s
    fitVals,ier=leastsq(mixed_res,fitVals,args=( zipData, s ) )
    th_b_y=[bspline(x,knotList,fitVals,order) for x in xListSorted]
    ax.plot(xListSorted,th_b_y)

plt.show()

問題在於,對於較大的權重,擬合要比將實際數據擬合sqrt更多的時間將其轉換為sqrt ,您可能會遇到收斂問題。

第二種選擇是直接使sqrt成為擬合的一部分,並提供其相對貢獻作為卡方的一部分。 包括sqrt 與以前一樣,藍色和黃色圖形。 其他均采用與上述相同的權重進行擬合。

為此,我將殘差函數更改為

def mixed_res(params,points,weight):
    a=params[0]
    coffs=params[1:]
    [xList,yList] = zip(*points)
    sqrtList=[a*np.sqrt(x) for x in xList]
    bSplList=[bspline(x,[0,0,.1,.2,.3,.4,.6,.9,.9,.9],coffs,2) for x in xList]
    diffTrue=[y-s-b for y,s,b in zip(yList,sqrtList,bSplList)]
    diffWeight=[ weight*(s-b)/(s+.001) for s,b in zip(sqrtList,bSplList)]

    return diffTrue+diffWeight

並呼吁適合

fitVals=[.4]+[.2,.3,.4,.2,.3,.4,.4]
for s in [0,.5,1,2]:
    print s
    fitVals,ier=leastsq(mixed_res,fitVals,args=( zipData, s ) )
    th_b_y=[fitVals[0]*np.sqrt(x)+bspline(x,knotList,fitVals[1:],order) for x in xListSorted]
    ax.plot(xListSorted,th_b_y)

剩下的大問題是:您如何確定要采用的權重? 更像平方根是什么意思?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM