डिस्क्लेमर: मैं इस पोस्ट को ज्यादातर वाक्यात्मक विचारों और सामान्य व्यवहार को ध्यान में रखकर लिख रहा हूं। मैं वर्णित विधियों की मेमोरी और सीपीयू पहलू से परिचित नहीं हूं, और मैं इस उत्तर को उन लोगों के लिए लक्षित करता हूं जिनके पास डेटा के बहुत छोटे सेट हैं, जैसे कि प्रक्षेप की गुणवत्ता पर विचार करने के लिए मुख्य पहलू हो सकता है। मुझे पता है कि बहुत बड़े डेटा सेट के साथ काम करते समय, बेहतर प्रदर्शन करने वाले तरीके (अर्थात् griddata
और Rbf
) संभव नहीं हैं।
मैं तीन प्रकार के बहुआयामी प्रक्षेप तरीकों ( interp2d
/ splines, griddata
और Rbf
) की तुलना करने जा रहा हूं । मैं उन्हें दो प्रकार के प्रक्षेप कार्यों और दो प्रकार के अंतर्निहित कार्यों (जिन बिंदुओं से प्रक्षेपित किया जाना है) के अधीन करूंगा। विशिष्ट उदाहरण द्वि-आयामी प्रक्षेप प्रदर्शित करेंगे, लेकिन व्यवहार्य विधियाँ मनमाने आयामों में लागू होती हैं। प्रत्येक विधि विभिन्न प्रकार के प्रक्षेप प्रदान करती है; सभी मामलों में मैं घन प्रक्षेप (या कुछ करीब 1 ) का उपयोग करूंगा । यह ध्यान रखना महत्वपूर्ण है कि जब भी आप प्रक्षेप का उपयोग करते हैं तो आप अपने कच्चे डेटा की तुलना में पूर्वाग्रह का परिचय देते हैं, और उपयोग किए जाने वाले विशिष्ट तरीके उन कलाकृतियों को प्रभावित करते हैं जिन्हें आप समाप्त करेंगे। हमेशा इसके बारे में जागरूक रहें, और जिम्मेदारी से इंटरपोल करें।
दो प्रक्षेप कार्य होंगे
- अपसंस्कृति (इनपुट डेटा एक आयताकार ग्रिड पर है, आउटपुट डेटा एक सघन ग्रिड पर है)
- एक नियमित ग्रिड पर बिखरे हुए डेटा का प्रक्षेप
दो कार्य (डोमेन पर [x,y] in [-1,1]x[-1,1]
) होंगे
- एक चिकनी और मैत्रीपूर्ण समारोह:
cos(pi*x)*sin(pi*y)
; में रेंज[-1, 1]
- एक बुराई (और विशेष रूप से, गैर-निरंतर) फ़ंक्शन:
x*y/(x^2+y^2)
मूल के पास 0.5 के मूल्य के साथ; में रेंज[-0.5, 0.5]
यहाँ है कि वे कैसे दिखते हैं:
मैं पहले यह प्रदर्शित करूंगा कि इन चार परीक्षणों के तहत तीन तरीके कैसे व्यवहार करते हैं, फिर मैं तीनों के वाक्य विन्यास का विस्तार करूँगा। यदि आप जानते हैं कि आपको किसी विधि से क्या उम्मीद करनी चाहिए, तो आप अपने वाक्यविन्यास (आप को देखकर interp2d
) को सीखने में अपना समय बर्बाद नहीं करना चाहेंगे ।
परीक्षण डेटा
खोजकर्ता के लिए, यहां वह कोड है जिसके साथ मैंने इनपुट डेटा उत्पन्न किया है। हालांकि इस विशिष्ट मामले में मुझे स्पष्ट रूप से डेटा अंतर्निहित फ़ंक्शन के बारे में पता है, मैं केवल प्रक्षेप विधियों के लिए इनपुट उत्पन्न करने के लिए इसका उपयोग करूंगा। मैं सुविधा के लिए (और अधिकतर डेटा उत्पन्न करने के लिए) सुन्न का उपयोग करता हूं, लेकिन अकेले चीखना भी पर्याप्त होगा।
import numpy as np
import scipy.interpolate as interp
# auxiliary function for mesh generation
def gimme_mesh(n):
minval = -1
maxval = 1
# produce an asymmetric shape in order to catch issues with transpositions
return np.meshgrid(np.linspace(minval,maxval,n), np.linspace(minval,maxval,n+1))
# set up underlying test functions, vectorized
def fun_smooth(x, y):
return np.cos(np.pi*x)*np.sin(np.pi*y)
def fun_evil(x, y):
# watch out for singular origin; function has no unique limit there
return np.where(x**2+y**2>1e-10, x*y/(x**2+y**2), 0.5)
# sparse input mesh, 6x7 in shape
N_sparse = 6
x_sparse,y_sparse = gimme_mesh(N_sparse)
z_sparse_smooth = fun_smooth(x_sparse, y_sparse)
z_sparse_evil = fun_evil(x_sparse, y_sparse)
# scattered input points, 10^2 altogether (shape (100,))
N_scattered = 10
x_scattered,y_scattered = np.random.rand(2,N_scattered**2)*2 - 1
z_scattered_smooth = fun_smooth(x_scattered, y_scattered)
z_scattered_evil = fun_evil(x_scattered, y_scattered)
# dense output mesh, 20x21 in shape
N_dense = 20
x_dense,y_dense = gimme_mesh(N_dense)
चिकना कार्य और अपशगुन
सबसे आसान काम से शुरू करते हैं। यहां बताया गया है कि स्मूथ टेस्ट फंक्शन के लिए आकृति के जाल से [6,7]
लेकर किसी एक [20,21]
कार्य तक का उत्थान
भले ही यह एक सरल कार्य है, लेकिन आउटपुट के बीच पहले से ही सूक्ष्म अंतर हैं। पहली नज़र में सभी तीन आउटपुट वाजिब हैं। नोट करने के लिए दो विशेषताएं हैं, अंतर्निहित फ़ंक्शन के हमारे पूर्व ज्ञान के आधार पर: griddata
डेटा को सबसे अधिक विकृत करता है। y==-1
भूखंड की सीमा पर ध्यान दें ( x
लेबल के निकटतम ): फ़ंक्शन सख्ती से शून्य होना चाहिए (चूंकि y==-1
चिकनी फ़ंक्शन के लिए एक नोडल लाइन है), फिर भी यह मामला नहीं है griddata
। इसके अलावा x==-1
, भूखंडों की सीमा (पीछे, बाईं ओर) पर ध्यान दें : अंतर्निहित फ़ंक्शन में एक स्थानीय अधिकतम (सीमा के पास शून्य ढाल) है [-1, -0.5]
, फिर भी griddata
आउटपुट इस क्षेत्र में स्पष्ट रूप से गैर-शून्य ढाल दिखाता है। प्रभाव सूक्ष्म है, लेकिन यह एक पूर्वाग्रह है कम नहीं है। (की निष्ठाRbf
रेडियल फ़ंक्शंस की डिफ़ॉल्ट पसंद के साथ और भी बेहतर है, डब किया गया multiquadratic
।)
दुष्ट कार्य और अपसरण
एक कठिन काम हमारे बुरे कार्य पर उतार-चढ़ाव करना है:
तीन तरीकों के बीच स्पष्ट अंतर दिखाई देने लगे हैं। सतह के भूखंडों को देखते हुए, आउटपुट में दिखने वाले स्पष्ट स्पष्ट एक्स्ट्रेमा हैं interp2d
(ध्यान दें कि प्लॉट की सतह के दाईं ओर दो कूबड़ हैं)। जबकि griddata
और Rbf
पहली नज़र में इसी तरह के परिणाम का उत्पादन करने के लिए लगता है, बाद वाले के पास एक गहरी न्यूनतम उत्पादन लगता है [0.4, -0.4]
जो अंतर्निहित फ़ंक्शन से अनुपस्थित है।
हालांकि, इसमें एक महत्वपूर्ण पहलू है जो Rbf
कहीं बेहतर है: यह अंतर्निहित फ़ंक्शन की समरूपता का सम्मान करता है (जो कि निश्चित रूप से नमूना जाल की समरूपता द्वारा भी संभव बनाया गया है)। griddata
नमूना बिंदुओं की समरूपता से आउटपुट टूट जाता है, जो पहले से ही कमजोर मामले में कमजोर दिखाई देता है।
चिकना कार्य और बिखरे हुए डेटा
ज्यादातर अक्सर बिखरे हुए डेटा पर प्रक्षेप करना चाहते हैं। इस कारण से मुझे उम्मीद है कि ये परीक्षण अधिक महत्वपूर्ण होंगे। जैसा कि ऊपर दिखाया गया है, नमूना बिंदु ब्याज के क्षेत्र में छद्म समान रूप से चुने गए थे। यथार्थवादी परिदृश्यों में आपके पास प्रत्येक माप के साथ अतिरिक्त शोर हो सकता है, और आपको विचार करना चाहिए कि क्या यह आपके कच्चे डेटा को शुरू करने के लिए प्रक्षेपित करने के लिए समझ में आता है।
चिकनी फ़ंक्शन के लिए आउटपुट:
अब पहले से ही थोड़ा सा हॉरर शो चल रहा है। मैंने कम से कम जानकारी को संरक्षित करने के लिए आउटपुट को प्लॉटिंग के लिए विशेष रूप interp2d
से बीच से काट दिया [-1, 1]
। यह स्पष्ट है कि जब कुछ अंतर्निहित आकृति मौजूद है, तो विशाल शोर क्षेत्र हैं जहां विधि पूरी तरह से टूट जाती है। दूसरा मामला griddata
आकार को अच्छी तरह से पुन: पेश करता है, लेकिन समोच्च साजिश की सीमा पर सफेद क्षेत्रों पर ध्यान दें। यह इस तथ्य के कारण है कि griddata
केवल इनपुट डेटा बिंदुओं के उत्तल पतवार के अंदर काम करता है (दूसरे शब्दों में, यह कोई एक्सट्रपलेशन नहीं करता है )। मैंने उत्तल पतवार के बाहर पड़े आउटपुट बिंदुओं के लिए डिफ़ॉल्ट NaN मान रखा। 2 इन विशेषताओं को देखते हुए, Rbf
सबसे अच्छा प्रदर्शन करना प्रतीत होता है।
ईविल फ़ंक्शन और बिखरे हुए डेटा
और जिस पल का हम सब इंतजार कर रहे हैं:
यह कोई बड़ा आश्चर्य नहीं है जो interp2d
देता है। वास्तव में, interp2d
आपको कॉल के दौरान कुछ अनुकूल RuntimeWarning
एस से उम्मीद करनी चाहिए कि निर्माण की जाने वाली सीमा की असंभवता के बारे में शिकायत करना। अन्य दो तरीकों के लिए, Rbf
सबसे अच्छा आउटपुट का उत्पादन करने के लिए लगता है, यहां तक कि डोमेन की सीमाओं के पास भी जहां परिणाम का एक्सट्रपलेशन किया जाता है।
तो मुझे वरीयता के घटते क्रम में, तीन तरीकों के बारे में कुछ शब्द बताएं (ताकि किसी के साथ पढ़ने की संभावना सबसे कम हो)।
scipy.interpolate.Rbf
Rbf
वर्ग "रेडियल आधार कार्यों" के लिए खड़ा है। सच कहूं तो मैंने इस दृष्टिकोण पर कभी विचार नहीं किया, जब तक कि मैंने इस पद के लिए शोध शुरू नहीं किया, लेकिन मुझे पूरा यकीन है कि मैं भविष्य में इनका उपयोग करूंगा।
स्पलाइन-आधारित विधियों (बाद में देखें) की तरह, उपयोग दो चरणों में होता है: पहला Rbf
इनपुट डेटा के आधार पर एक कॉल करने योग्य श्रेणी का उदाहरण बनाता है , और फिर किसी दिए गए आउटपुट मेष के लिए इस ऑब्जेक्ट को इंटरपोलित परिणाम प्राप्त करने के लिए कॉल करता है। चिकनी अपक्षय परीक्षण से उदाहरण:
import scipy.interpolate as interp
zfun_smooth_rbf = interp.Rbf(x_sparse, y_sparse, z_sparse_smooth, function='cubic', smooth=0) # default smooth=0 for interpolation
z_dense_smooth_rbf = zfun_smooth_rbf(x_dense, y_dense) # not really a function, but a callable class instance
नोट दोनों इनपुट और आउटपुट अंक इस मामले में 2 डी सरणियों थे, और आउटपुट z_dense_smooth_rbf
के रूप में ही आकार है x_dense
और y_dense
बिना किसी प्रयास के। यह भी ध्यान दें कि Rbf
प्रक्षेप के लिए मनमाना आयामों का समर्थन करता है।
इसलिए, scipy.interpolate.Rbf
- पागल इनपुट डेटा के लिए भी अच्छी तरह से व्यवहार उत्पादन करता है
- उच्च आयामों में प्रक्षेप का समर्थन करता है
- इनपुट बिंदुओं के उत्तल पतवार के बाहर एक्सट्रपलेट्स (निश्चित रूप से एक्सट्रपलेशन हमेशा एक जुआ है, और आपको आमतौर पर इस पर भरोसा नहीं करना चाहिए)
- पहले कदम के रूप में एक इंटरपोलर बनाता है, इसलिए विभिन्न आउटपुट बिंदुओं में इसका मूल्यांकन कम अतिरिक्त प्रयास है
- मनमाने आकार के आउटपुट पॉइंट हो सकते हैं (जैसा कि आयताकार जालियों के लिए विवश होने का विरोध किया जाता है, बाद में देखें)
- इनपुट डेटा की समरूपता को संरक्षित करने के लिए प्रवण
- कीवर्ड के लिए रेडियल कार्यों के कई प्रकार का समर्थन करता है
function
: multiquadric
, inverse
, gaussian
, linear
, cubic
, quintic
, thin_plate
और उपयोगकर्ता-निर्धारित मनमाना
scipy.interpolate.griddata
मेरा पूर्व पसंदीदा, griddata
मनमाना आयामों में प्रक्षेप के लिए एक सामान्य वर्कहॉर्स है। यह नोडल बिंदुओं के उत्तल पतवार के बाहर के बिंदुओं के लिए एक पूर्व निर्धारित मूल्य से परे एक्सट्रपलेशन नहीं करता है, लेकिन चूंकि एक्सट्रपलेशन एक बहुत ही चंचल और खतरनाक चीज है, यह जरूरी नहीं कि एक कॉन है। उपयोग उदाहरण:
z_dense_smooth_griddata = interp.griddata(np.array([x_sparse.ravel(),y_sparse.ravel()]).T,
z_sparse_smooth.ravel(),
(x_dense,y_dense), method='cubic') # default method is linear
थोड़ा कर्लिंग सिंटैक्स पर ध्यान दें। इनपुट बिंदुओं को आयामों [N, D]
में आकार की एक सरणी में निर्दिष्ट किया जाना है D
। इसके लिए हमें सबसे पहले अपने 2d निर्देशांक सरणियों (उपयोग करने ravel
) को समतल करना होगा , फिर सरणियों को समतल करना होगा और परिणाम को स्थानांतरित करना होगा। ऐसा करने के कई तरीके हैं, लेकिन वे सभी भारी प्रतीत होते हैं। इनपुट z
डेटा को भी समतल करना होगा। जब हम आउटपुट पॉइंट की बात करते हैं तो हमें थोड़ी अधिक स्वतंत्रता होती है: किसी कारण से इन्हें बहुआयामी सरणियों के रूप में भी निर्दिष्ट किया जा सकता है। ध्यान दें कि help
की griddata
, भ्रामक है यह पता चलता है के रूप में है कि एक ही के लिए सच है इनपुट अंक (कम से कम संस्करण 0.17.0 के लिए):
griddata(points, values, xi, method='linear', fill_value=nan, rescale=False)
Interpolate unstructured D-dimensional data.
Parameters
----------
points : ndarray of floats, shape (n, D)
Data point coordinates. Can either be an array of
shape (n, D), or a tuple of `ndim` arrays.
values : ndarray of float or complex, shape (n,)
Data values.
xi : ndarray of float, shape (M, D)
Points at which to interpolate data.
संक्षेप में, scipy.interpolate.griddata
- पागल इनपुट डेटा के लिए भी अच्छी तरह से व्यवहार उत्पादन करता है
- उच्च आयामों में प्रक्षेप का समर्थन करता है
- एक्सट्रपलेशन नहीं करता है, इनपुट बिंदुओं के उत्तल पतवार के बाहर आउटपुट के लिए एक एकल मान सेट किया जा सकता है (देखें
fill_value
)
- एकल कॉल में प्रक्षेपित मानों की गणना करता है, इसलिए आउटपुट बिंदुओं के कई सेटों की जांच खरोंच से शुरू होती है
- मनमाना आकार के आउटपुट अंक हो सकते हैं
- 1d और 2d में क्यूबिक, मनमाना आयामों में निकटतम-पड़ोसी और रैखिक प्रक्षेप का समर्थन करता है। निकटतम-पड़ोसी और रैखिक प्रक्षेप का उपयोग
NearestNDInterpolator
और LinearNDInterpolator
हुड के नीचे, क्रमशः। 1 डी क्यूबिक इंटरपोलेशन एक स्पलाइन का उपयोग करता है, 2 डी क्यूबिक इंटरपोलेशन CloughTocher2DInterpolator
एक निरंतर विभेदक टुकड़ा-क्यूबिक इंटरपोलर के निर्माण के लिए उपयोग करता है।
- इनपुट डेटा की समरूपता का उल्लंघन हो सकता है
scipy.interpolate.interp2d
/scipy.interpolate.bisplrep
एकमात्र कारण interp2d
जिसकी मैं चर्चा कर रहा हूं और उसके रिश्तेदारों का यह है कि इसका एक भ्रामक नाम है, और लोग इसका उपयोग करने की कोशिश कर सकते हैं। स्पॉइलर अलर्ट: इसका इस्तेमाल न करें (स्कैपी संस्करण 0.17.0 के रूप में)। यह पहले से मौजूद विषयों की तुलना में अधिक विशेष है, क्योंकि यह विशेष रूप से द्वि-आयामी प्रक्षेप के लिए उपयोग किया जाता है, लेकिन मुझे संदेह है कि यह बहुभिन्नरूपी प्रक्षेप के लिए अब तक का सबसे आम मामला है।
जहाँ तक सिंटैक्स जाता है, इसमें interp2d
समान है Rbf
कि इसे पहले एक प्रक्षेप उदाहरण के निर्माण की आवश्यकता है, जिसे वास्तविक प्रक्षेपित मान प्रदान करने के लिए कहा जा सकता है। हालांकि, एक पकड़ है: आउटपुट पॉइंट्स को एक आयताकार जाल पर स्थित होना होता है, इसलिए इंटरपोलर को कॉल में जाने वाले इनपुट में 1d वैक्टर होना चाहिए जो आउटपुट ग्रिड का विस्तार करता है, जैसे कि numpy.meshgrid
:
# reminder: x_sparse and y_sparse are of shape [6, 7] from numpy.meshgrid
zfun_smooth_interp2d = interp.interp2d(x_sparse, y_sparse, z_sparse_smooth, kind='cubic') # default kind is 'linear'
# reminder: x_dense and y_dense are of shape [20, 21] from numpy.meshgrid
xvec = x_dense[0,:] # 1d array of unique x values, 20 elements
yvec = y_dense[:,0] # 1d array of unique y values, 21 elements
z_dense_smooth_interp2d = zfun_smooth_interp2d(xvec,yvec) # output is [20, 21]-shaped array
सबसे आम गलतियों में से एक का उपयोग करते समय interp2d
अपने पूरे 2d meshes को इंटरपोलेशन कॉल में डाल दिया जाता है, जिससे विस्फोटक मेमोरी खपत होती है, और उम्मीद है कि जल्दबाजी में MemoryError
।
अब, सबसे बड़ी समस्या interp2d
यह है कि यह अक्सर काम नहीं करता है। इसे समझने के लिए, हमें हूड के नीचे देखना होगा। यह पता चला है कि interp2d
निचले स्तर के कार्यों के लिए एक आवरण है bisplrep
+ bisplev
, जो कि FITPACK रूटीन (फोरट्रान में लिखे गए) के लिए बदले में आवरण हैं। पिछले उदाहरण के बराबर कॉल होगा
kind = 'cubic'
if kind=='linear':
kx=ky=1
elif kind=='cubic':
kx=ky=3
elif kind=='quintic':
kx=ky=5
# bisplrep constructs a spline representation, bisplev evaluates the spline at given points
bisp_smooth = interp.bisplrep(x_sparse.ravel(),y_sparse.ravel(),z_sparse_smooth.ravel(),kx=kx,ky=ky,s=0)
z_dense_smooth_bisplrep = interp.bisplev(xvec,yvec,bisp_smooth).T # note the transpose
अब, यहाँ के बारे में बात है interp2d
(scipy संस्करण 0.17.0 में) वहाँ एक अच्छा है: में टिप्पणीinterpolate/interpolate.py
के लिए interp2d
:
if not rectangular_grid:
# TODO: surfit is really not meant for interpolation!
self.tck = fitpack.bisplrep(x, y, z, kx=kx, ky=ky, s=0.0)
और वास्तव में interpolate/fitpack.py
, bisplrep
वहाँ कुछ सेटअप और अंततः है
tx, ty, c, o = _fitpack._surfit(x, y, z, w, xb, xe, yb, ye, kx, ky,
task, s, eps, tx, ty, nxest, nyest,
wrk, lwrk1, lwrk2)
और बस। अंतर्निहित दिनचर्या interp2d
वास्तव में प्रक्षेप करने के लिए नहीं है। वे पर्याप्त रूप से अच्छी तरह से व्यवहार किए गए डेटा के लिए पर्याप्त हो सकते हैं, लेकिन यथार्थवादी परिस्थितियों में आप शायद कुछ और उपयोग करना चाहेंगे।
सिर्फ निष्कर्ष निकालने के लिए, interpolate.interp2d
- अच्छी तरह से टेम्पर्ड डेटा के साथ भी कलाकृतियों को जन्म दे सकता है
- विशेष रूप से द्विभाजित समस्याओं के लिए है (हालांकि
interpn
ग्रिड पर परिभाषित इनपुट बिंदुओं के लिए सीमित है )
- एक्सट्रपलेशन करता है
- पहले कदम के रूप में एक इंटरपोलर बनाता है, इसलिए विभिन्न आउटपुट बिंदुओं में इसका मूल्यांकन कम अतिरिक्त प्रयास है
- केवल एक आयताकार ग्रिड पर उत्पादन का उत्पादन कर सकते हैं, बिखरे हुए आउटपुट के लिए आपको एक लूप में इंटरपोलर को कॉल करना होगा
- रैखिक, घन और क्विंटिक प्रक्षेप का समर्थन करता है
- इनपुट डेटा की समरूपता का उल्लंघन हो सकता है
1 मैं काफी हद तक निश्चित है कि कर रहा हूँ cubic
और linear
एक तरह से आधार कार्यों का Rbf
वास्तव में एक ही नाम के अन्य interpolators के अनुरूप नहीं है।
2 ये NaN भी इस कारण से हैं कि सतह का प्लॉट इतना अजीब क्यों लगता है: matplotlib को ऐतिहासिक रूप से उचित गहराई की जानकारी के साथ जटिल 3D ऑब्जेक्ट्स को प्लॉट करने में कठिनाइयाँ होती हैं। डेटा में NaN मान रेंडरर को भ्रमित करते हैं, इसलिए सतह के कुछ हिस्सों को पीछे होना चाहिए जो सामने की ओर स्थित हैं। यह दृश्य के साथ एक मुद्दा है, और प्रक्षेप नहीं है।