कैसे करें scipy.interpolate इनपुट रेंज से परे एक अतिरिक्त परिणाम दें?


82

मैं एक प्रोग्राम को पोर्ट करने की कोशिश कर रहा हूं, जो हाथ से लुढ़का हुआ इंटरपोलर (एक गणितज्ञ सहयोगी द्वारा विकसित) का उपयोग करता है, जो स्काइप द्वारा प्रदान किए गए इंटरपोलर का उपयोग करता है। मैं स्कैपी इंटरपोलर का उपयोग करना या लपेटना चाहता हूं ताकि पुराने इंटरपोलर के पास यथासंभव व्यवहार हो।

दो कार्यों के बीच एक महत्वपूर्ण अंतर यह है कि हमारे मूल प्रक्षेपक में - यदि इनपुट मान इनपुट सीमा के ऊपर या नीचे है, तो हमारा मूल प्रक्षेपक परिणाम को एक्सट्रपलेट करेगा। यदि आप इसे scipy interpolator के साथ आज़माते हैं तो यह उठता है ValueError। इस कार्यक्रम को एक उदाहरण के रूप में देखें:

import numpy as np
from scipy import interpolate

x = np.arange(0,10)
y = np.exp(-x/3.0)
f = interpolate.interp1d(x, y)

print f(9)
print f(11) # Causes ValueError, because it's greater than max(x)

क्या इसे बनाने का एक समझदार तरीका है ताकि दुर्घटनाग्रस्त होने के बजाय, अंतिम पंक्ति बस एक रैखिक एक्सट्रपलेशन कर सकेगी, पहले और अंतिम दो बिंदुओं द्वारा परिभाषित अनन्तता को जारी रखेगी।

ध्यान दें, कि वास्तविक सॉफ़्टवेयर में मैं वास्तव में ऍक्स्प फ़ंक्शन का उपयोग नहीं कर रहा हूँ - यह केवल चित्रण के लिए यहाँ है!


2
scipy.interpolate.UnivariateSplineमुद्दों के बिना बाहर निकालने के लिए लगता है।
हेल्टनबीकर

जवाबों:


38

1. लगातार एक्सट्रपलेशन

आप interpस्कैपी से फ़ंक्शन का उपयोग कर सकते हैं , यह सीमा से परे निरंतर रूप में बाएं और दाएं मान को एक्सट्रपलेट करता है:

>>> from scipy import interp, arange, exp
>>> x = arange(0,10)
>>> y = exp(-x/3.0)
>>> interp([9,10], x, y)
array([ 0.04978707,  0.04978707])

2. रैखिक (या अन्य कस्टम) एक्सट्रपलेशन

आप एक प्रक्षेप फ़ंक्शन के चारों ओर एक आवरण लिख सकते हैं जो रैखिक एक्सट्रपलेशन की देखभाल करता है। उदाहरण के लिए:

from scipy.interpolate import interp1d
from scipy import arange, array, exp

def extrap1d(interpolator):
    xs = interpolator.x
    ys = interpolator.y

    def pointwise(x):
        if x < xs[0]:
            return ys[0]+(x-xs[0])*(ys[1]-ys[0])/(xs[1]-xs[0])
        elif x > xs[-1]:
            return ys[-1]+(x-xs[-1])*(ys[-1]-ys[-2])/(xs[-1]-xs[-2])
        else:
            return interpolator(x)

    def ufunclike(xs):
        return array(list(map(pointwise, array(xs))))

    return ufunclike

extrap1dएक इंटरपोलेशन फ़ंक्शन लेता है और एक फ़ंक्शन देता है जो एक्सट्रपलेशन भी कर सकता है। और आप इसे इस तरह से उपयोग कर सकते हैं:

x = arange(0,10)
y = exp(-x/3.0)
f_i = interp1d(x, y)
f_x = extrap1d(f_i)

print f_x([9,10])

आउटपुट:

[ 0.04978707  0.03009069]

1
पायथन 3.6 में, मुझे listवापसी को जोड़ना था : return array(list(map(pointwise, array(xs)))) पुनरावृत्ति को हल करने के लिए।
ज्यादातर

यह समाधान fill_value = "extrapolate" विकल्प की तुलना में अधिक लचीला है। मैं अपनी आवश्यकताओं के लिए आंतरिक फ़ंक्शन 'पॉइंटवाइज़' को अनुकूलित करने में सक्षम था, मैं ऊपर टिप्पणी करता हूं और आवश्यकता होने पर सूची सम्मिलित करता हूं। यह कहने के बाद, कभी-कभी आप केवल एक जनरेटर रखना चाहते हैं।
विल्मर ई। हेनो

1
ध्यान दें कि आधारित पहला समाधान scipy.interpअब अनुशंसित नहीं है क्योंकि यह पदावनत है और SciPy 2.0.0 में गायब हो जाएगा। वे numpy.interpइसके बजाय का उपयोग करने की
सलाह

86

आप InterpolatedUnivariateSpline पर एक नज़र डाल सकते हैं

यहाँ एक उदाहरण इसका उपयोग कर रहा है:

import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import InterpolatedUnivariateSpline

# given values
xi = np.array([0.2, 0.5, 0.7, 0.9])
yi = np.array([0.3, -0.1, 0.2, 0.1])
# positions to inter/extrapolate
x = np.linspace(0, 1, 50)
# spline order: 1 linear, 2 quadratic, 3 cubic ... 
order = 1
# do inter/extrapolation
s = InterpolatedUnivariateSpline(xi, yi, k=order)
y = s(x)

# example showing the interpolation for linear, quadratic and cubic interpolation
plt.figure()
plt.plot(xi, yi)
for order in range(1, 4):
    s = InterpolatedUnivariateSpline(xi, yi, k=order)
    y = s(x)
    plt.plot(x, y)
plt.show()

2
यह सबसे अच्छा जवाब है। वही मैंने किया। I used k=1 (order), तो यह एक रैखिक प्रक्षेप हो जाता है, औरI used bbox=[xmin-w, xmax+w] where w is my tolerance
eusoubrasileiro

78

SciPy संस्करण 0.17.0 के रूप में , scipy.interpolate.interp1d के लिए एक नया विकल्प है, जो ध्रुवीकरण की अनुमति देता है। बस कॉल में fill_value = 'extrapolate' सेट करें। इस तरह से अपने कोड को संशोधित करता है:

import numpy as np
from scipy import interpolate

x = np.arange(0,10)
y = np.exp(-x/3.0)
f = interpolate.interp1d(x, y, fill_value='extrapolate')

print f(9)
print f(11)

और आउटपुट है:

0.0497870683679
0.010394302658

क्या एक्सट्रपलेशन प्रकार प्रक्षेप के समान है? उदाहरण के लिए, क्या हम निकटतम बिंदु एक्सट्रपलेशन के साथ रैखिक प्रक्षेप कर सकते हैं?
a.sam

यदि तरह = 'घन', fill_value = 'extrapolate' काम नहीं करता है।
vlmercado

@ a.sam: मुझे यकीन नहीं है कि आपका क्या मतलब है ... संभवतः, अगर आप fill_value = 'प्रक्षेप' के साथ तरह = 'रैखिक' का उपयोग करते हैं तो आपको एक रैखिक प्रक्षेप मिलता है, और यदि आप इसे fill_value = 'एक्सट्रपलेशन' के साथ उपयोग करते हैं तो आप एक रैखिक एक्सट्रपलेशन, नहीं?
मूट

@vlmercado: क्या आप बता सकते हैं कि यह किस तरह से काम नहीं करता है? मैंने तरह के = 'घन' के साथ उपरोक्त उदाहरण को चलाने की कोशिश की, और यह मेरे लिए ठीक काम करता है।
मूट

@ लूट, scipy 0.18.1 का उपयोग करते हुए, मुझे निम्नलिखित मिलते हैं: ValueError:
एक्सट्रैपलेशन

8

क्या scipy.interpolate.splrep के बारे में (डिग्री 1 और कोई चौरसाई के साथ):

>> tck = scipy.interpolate.splrep([1, 2, 3, 4, 5], [1, 4, 9, 16, 25], k=1, s=0)
>> scipy.interpolate.splev(6, tck)
34.0

ऐसा लगता है कि आप क्या चाहते हैं, क्योंकि 34 = 25 + (25 - 16)।


7

यहां एक वैकल्पिक विधि है जो केवल संख्यात्मक पैकेज का उपयोग करती है। यह सुपीरियर के सरणी फ़ंक्शंस का लाभ उठाता है, इसलिए बड़े सरणियों को प्रक्षेपित / एक्सट्रपलेट करते समय तेज हो सकता है:

import numpy as np

def extrap(x, xp, yp):
    """np.interp function with linear extrapolation"""
    y = np.interp(x, xp, yp)
    y = np.where(x<xp[0], yp[0]+(x-xp[0])*(yp[0]-yp[1])/(xp[0]-xp[1]), y)
    y = np.where(x>xp[-1], yp[-1]+(x-xp[-1])*(yp[-1]-yp[-2])/(xp[-1]-xp[-2]), y)
    return y

x = np.arange(0,10)
y = np.exp(-x/3.0)
xtest = np.array((8.5,9.5))

print np.exp(-xtest/3.0)
print np.interp(xtest, x, y)
print extrap(xtest, x, y)

संपादित करें: मार्क मिकोफ़्स्की ने "एक्सट्रा" फ़ंक्शन के संशोधित संशोधन का सुझाव दिया:

def extrap(x, xp, yp):
    """np.interp function with linear extrapolation"""
    y = np.interp(x, xp, yp)
    y[x < xp[0]] = yp[0] + (x[x<xp[0]]-xp[0]) * (yp[0]-yp[1]) / (xp[0]-xp[1])
    y[x > xp[-1]]= yp[-1] + (x[x>xp[-1]]-xp[-1])*(yp[-1]-yp[-2])/(xp[-1]-xp[-2])
    return y

2
एक वास्तविक उदाहरण के लिए +1, लेकिन आप बूलियन इंडेक्सिंग का उपयोग कर सकते हैं और यहां y[x < xp[0]] = fp[0] + (x[x < xp[0]] - xp[0]) / (xp[1] - xp[0]) * (fp[1] - fp[0]) और y[x > xp[-1]] = fp[-1] + (x[x > xp[-1]] - xp[-1]) / (xp[-2] - xp[-1]) * (fp[-2] - fp[-1])इसके बजाय np.where, Falseविकल्प के बाद से yपरिवर्तन नहीं होता है।
मार्क मिकोफ्कि

6

यह बड़े डेटासेट के साथ बूलियन इंडेक्सिंग का उपयोग करने के लिए तेज़ हो सकता है , क्योंकि एल्गोरिथ्म जांचता है कि क्या हर बिंदु अंतराल के बाहर है, जबकि बूलियन इंडेक्सिंग एक आसान और तेज़ तुलना की अनुमति देता है।

उदाहरण के लिए:

# Necessary modules
import numpy as np
from scipy.interpolate import interp1d

# Original data
x = np.arange(0,10)
y = np.exp(-x/3.0)

# Interpolator class
f = interp1d(x, y)

# Output range (quite large)
xo = np.arange(0, 10, 0.001)

# Boolean indexing approach

# Generate an empty output array for "y" values
yo = np.empty_like(xo)

# Values lower than the minimum "x" are extrapolated at the same time
low = xo < f.x[0]
yo[low] =  f.y[0] + (xo[low]-f.x[0])*(f.y[1]-f.y[0])/(f.x[1]-f.x[0])

# Values higher than the maximum "x" are extrapolated at same time
high = xo > f.x[-1]
yo[high] = f.y[-1] + (xo[high]-f.x[-1])*(f.y[-1]-f.y[-2])/(f.x[-1]-f.x[-2])

# Values inside the interpolation range are interpolated directly
inside = np.logical_and(xo >= f.x[0], xo <= f.x[-1])
yo[inside] = f(xo[inside])

मेरे मामले में, 300000 अंकों के डेटा सेट के साथ, इसका मतलब 25.8 से 0.094 सेकंड तक की गति है, यह 250% से अधिक तेज है


यह अच्छा है, लेकिन यह काम नहीं करता है अगर x0 एक फ्लोट है, अगर y [0] np.nan है, या यदि y [-1] np.nan है।
स्ट्रेच

2

मैंने अपने प्रारंभिक सरणियों में एक बिंदु जोड़कर ऐसा किया। इस तरह मैं स्व-निर्मित कार्यों को परिभाषित करने से बचता हूं, और रैखिक एक्सट्रपलेशन (नीचे दिए गए उदाहरण में: सही एक्सट्रपलेशन) ठीक दिखता है।

import numpy as np  
from scipy import interp as itp  

xnew = np.linspace(0,1,51)  
x1=xold[-2]  
x2=xold[-1]  
y1=yold[-2]  
y2=yold[-1]  
right_val=y1+(xnew[-1]-x1)*(y2-y1)/(x2-x1)  
x=np.append(xold,xnew[-1])  
y=np.append(yold,right_val)  
f = itp(xnew,x,y)  

1

मुझे डर है कि मेरी जानकारी के लिए Scipy में ऐसा करना आसान नहीं है। आप कर सकते हैं, जैसा कि मुझे पूरा यकीन है कि आप जागरूक हैं, सीमा त्रुटियों को बंद करें और सीमा से परे सभी फ़ंक्शन मानों को एक स्थिर के साथ भरें, लेकिन यह वास्तव में मदद नहीं करता है। कुछ और विचारों के लिए मेलिंग सूची पर इस प्रश्न को देखें । हो सकता है कि आप किसी प्रकार के टुकड़े-टुकड़े समारोह का उपयोग कर सकें, लेकिन यह एक प्रमुख दर्द की तरह लगता है।


यही निष्कर्ष है कि मैं कम से कम स्किपी 0.7 के साथ आया था, हालांकि 21 महीने पहले लिखे गए इस ट्यूटोरियल से पता चलता है कि इंटरप 1 डी फ़ंक्शन में एक उच्च और निम्न विशेषता है, जिसे "रैखिक" पर सेट किया जा सकता है, यह ट्यूटोरियल स्पष्ट नहीं है कि यह स्कैपी के किस संस्करण में है : के लिए लागू होता projects.scipy.org/scipy/browser/branches/Interpolate1D/docs/...
सलीम Fadhley

ऐसा लगता है कि यह एक शाखा का हिस्सा है जिसे मुख्य संस्करण में आत्मसात नहीं किया गया है, इसलिए अभी भी इसके साथ कुछ समस्याएं हो सकती हैं। इसके लिए वर्तमान कोड प्रोजेक्ट्स पर है। scipy.org/scipy/browser/branches/interpolate/… हालांकि आप पृष्ठ के नीचे स्क्रॉल करना चाहते हैं और इसे सादे पाठ के रूप में डाउनलोड करने के लिए क्लिक कर सकते हैं। मुझे लगता है कि यह आशाजनक लग रहा है, हालांकि मैंने इसे अभी तक खुद करने की कोशिश नहीं की है।
जस्टिन पील

1

नीचे दिया गया कोड आपको सरल एक्सट्रपलेशन मॉड्यूल देता है। कश्मीर मान डेटा सेट जो करने के लिए है y पर डेटा सेट आधारित वाग्विस्तार हो गया है एक्स। numpyमॉड्यूल की आवश्यकता है।

 def extrapol(k,x,y):
        xm=np.mean(x);
        ym=np.mean(y);
        sumnr=0;
        sumdr=0;
        length=len(x);
        for i in range(0,length):
            sumnr=sumnr+((x[i]-xm)*(y[i]-ym));
            sumdr=sumdr+((x[i]-xm)*(x[i]-xm));

        m=sumnr/sumdr;
        c=ym-(m*xm);
        return((m*k)+c)

0

मानक प्रक्षेप + रैखिक अतिरिक्त:

    def interpola(v, x, y):
        if v <= x[0]:
            return y[0]+(y[1]-y[0])/(x[1]-x[0])*(v-x[0])
        elif v >= x[-1]:
            return y[-2]+(y[-1]-y[-2])/(x[-1]-x[-2])*(v-x[-2])
        else:
            f = interp1d(x, y, kind='cubic') 
            return f(v)

1
हे फेडेरिको! यदि आप आश्चर्य करते हैं कि आप क्यों निराश हो गए, तो कृपया ध्यान रखें कि प्रश्नों का उत्तर देते समय आपको वास्तव में यह समझाने की आवश्यकता है कि यह समस्या को हल कैसे करता है। यह उत्तर, जैसा कि यह है, केवल एक कोड डंप है और इसमें कम से कम कुछ वाक्यों की व्याख्या होनी चाहिए कि यह क्यों और / या कैसे उपयोगी है। धन्यवाद!
फेलिक्स गगनोन-ग्रेनियर

0

मेरे पास टिप्पणी करने के लिए पर्याप्त प्रतिष्ठा नहीं है, लेकिन यदि कोई व्यक्ति स्कैपी के साथ रैखिक 2d-प्रक्षेप के लिए एक एक्सट्रपलेशन आवरण की तलाश कर रहा है, तो मैंने उस उत्तर को अनुकूलित कर दिया है जो यहां 1d प्रक्षेप के लिए दिया गया था।

def extrap2d(interpolator):
xs = interpolator.x
ys = interpolator.y
zs = interpolator.z
zs = np.reshape(zs, (-1, len(xs)))
def pointwise(x, y):
    if x < xs[0] or y < ys[0]:
        x1_index = np.argmin(np.abs(xs - x))
        x2_index = x1_index + 1
        y1_index = np.argmin(np.abs(ys - y))
        y2_index = y1_index + 1
        x1 = xs[x1_index]
        x2 = xs[x2_index]
        y1 = ys[y1_index]
        y2 = ys[y2_index]
        z11 = zs[x1_index, y1_index]
        z12 = zs[x1_index, y2_index]
        z21 = zs[x2_index, y1_index]
        z22 = zs[x2_index, y2_index]

        return (z11 * (x2 - x) * (y2 - y) +
        z21 * (x - x1) * (y2 - y) +
        z12 * (x2 - x) * (y - y1) +
        z22 * (x - x1) * (y - y1)
       ) / ((x2 - x1) * (y2 - y1) + 0.0)


    elif x > xs[-1] or y > ys[-1]:
        x1_index = np.argmin(np.abs(xs - x))
        x2_index = x1_index - 1
        y1_index = np.argmin(np.abs(ys - y))
        y2_index = y1_index - 1
        x1 = xs[x1_index]
        x2 = xs[x2_index]
        y1 = ys[y1_index]
        y2 = ys[y2_index]
        z11 = zs[x1_index, y1_index]
        z12 = zs[x1_index, y2_index]
        z21 = zs[x2_index, y1_index]
        z22 = zs[x2_index, y2_index]#

        return (z11 * (x2 - x) * (y2 - y) +
        z21 * (x - x1) * (y2 - y) +
        z12 * (x2 - x) * (y - y1) +
        z22 * (x - x1) * (y - y1)
        ) / ((x2 - x1) * (y2 - y1) + 0.0)
    else:
        return interpolator(x, y)
def ufunclike(xs, ys):
    if  isinstance(xs, int) or isinstance(ys, int) or isinstance(xs, np.int32) or isinstance(ys, np.int32):
        res_array = pointwise(xs, ys)
    else:
        res_array = np.zeros((len(xs), len(ys)))
        for x_c in range(len(xs)):
            res_array[x_c, :] = np.array([pointwise(xs[x_c], ys[y_c]) for y_c in range(len(ys))]).T

    return res_array
return ufunclike

मैंने बहुत टिप्पणी नहीं की है और मुझे पता है, कि कोड सुपर क्लीन नहीं है। अगर किसी को कोई त्रुटि दिखाई देती है, तो कृपया मुझे बताएं। मेरे वर्तमान उपयोग के मामले में यह एक समस्या के बिना काम कर रहा है :)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.