From eedd016e993eb933640d4705facafdefe742fcc2 Mon Sep 17 00:00:00 2001 From: Vanya Belyaev Date: Fri, 2 Aug 2024 16:38:01 +0200 Subject: [PATCH] add ROC-curve --- ostap/core/core.py | 8 ++ ostap/histos/graphs.py | 80 ++++++++++++++--- ostap/histos/histos.py | 166 +++++++++++++++++++++++++++++------- ostap/histos/roc.py | 135 +++++++++++++++++++++++++++++ ostap/math/interpolation.py | 50 ++++++----- 5 files changed, 367 insertions(+), 72 deletions(-) create mode 100644 ostap/histos/roc.py diff --git a/ostap/core/core.py b/ostap/core/core.py index 60c21ffb..500b01d6 100644 --- a/ostap/core/core.py +++ b/ostap/core/core.py @@ -476,6 +476,14 @@ def _TO_draw_ ( obj , option = '', *args , **kwargs ) : obj.SetFillColor ( color ) if 'FillStyle' in kw and hasattr ( obj , 'SetFillStyle' ) : obj.SetFillStyle ( kw.pop('FillStyle' ) ) + + if 'Opacity' in kw and \ + hasattr ( obj , 'SetFillColorAlpha' ) and \ + hasattr ( obj , 'GetFillStyle' ) : + fs = obj.GetFillStyle() + if 1001 == fs and hasattr ( obj , 'GetFillColor' ) : + fc = obj.GetFillColor() + if fc : obj.SetFillColorAlpha ( fc , kw.pop ('Opacity' ) ) ## Min/max values diff --git a/ostap/histos/graphs.py b/ostap/histos/graphs.py index 7ed3ea20..71c478f8 100755 --- a/ostap/histos/graphs.py +++ b/ostap/histos/graphs.py @@ -861,9 +861,11 @@ def _gre_setitem_ ( graph , ipoint , point ) : if not ipoint in graph : raise IndexError if not 2 == len ( point ) : raise AttributeError("Invalid dimension of 'point' %s" % str ( point ) ) + + x , y = point - x = VE ( point [ 0 ] ) - v = VE ( point [ 1 ] ) + x = VE ( x ) + v = VE ( y ) graph.SetPoint ( ipoint , x . value () , v . value () ) graph.SetPointError ( ipoint , x . error () , v . error () ) @@ -1731,16 +1733,36 @@ def _grae_transform_ ( graph , fun = lambda x , y : y ) : ## set color attributes # @author Vanya BELYAEV Ivan.Belyaev@itep.ru # @date 2013-01-21 -def _color_ ( self , color = 2 , marker = 20 , size = -1 ) : +def _color_ ( self , + color = 2 , + marker = 20 , + size = -1 , + opacity = -1 , + fill = -1 ) : """Set color attributes >>> h.color ( 3 ) """ # - if hasattr ( self , 'SetLineColor' ) : self.SetLineColor ( color ) - if hasattr ( self , 'SetFillColor' ) : self.SetFillColor ( color ) - if hasattr ( self , 'SetMarkerColor' ) : self.SetMarkerColor ( color ) - if hasattr ( self , 'SetMarkerStyle' ) : self.SetMarkerStyle ( marker ) + if hasattr ( self , 'SetLineColor' ) : self.SetLineColor ( color ) + if hasattr ( self , 'SetFillColor' ) : self.SetFillColor ( color ) + if hasattr ( self , 'SetMarkerColor' ) : self.SetMarkerColor ( color ) + if hasattr ( self , 'SetMarkerStyle' ) : self.SetMarkerStyle ( marker ) + + if hasattr ( self , 'SetFillStyle' ) : + if fill is True : self.SetFillStyle ( 1001 ) + elif fill is False : self.SetFillStyle ( 0 ) + elif insinstance ( fill , integer_types ) and 1000 < fill : + self.SetFillStyle ( fill ) + + if hasattr ( self , 'SetFillColorAlpha' ) and isinstance ( opacity , num_types ) and 0 <= opacity <= 1 : + if hasattr ( self , 'GetFillStyle' ) : + fs = self.GetFillStyle() + if 1001 == fs : + if hasattr ( self , 'GetFillColor' ) : + fc = self.GetFillColor () + if fc : self.SetFillColorAlpha ( fc , opacity ) + ## if 0 > size and hasattr ( self , 'GetMarkerSize' ) and not marker in ( 1 , 6 , 7 ) : size = self.GetMarkerSize() @@ -1756,32 +1778,62 @@ def _color_ ( self , color = 2 , marker = 20 , size = -1 ) : ## set color attributes # @author Vanya BELYAEV Ivan.Belyaev@itep.ru # @date 2013-01-21 -def _red_ ( self , marker = 20 ) : return _color_( self , 2 , marker ) +def _red_ ( self , + marker = 20 , + size = -1 , + opacity = -1 , + fill = False ) : + return _color_( self , color = 2 , marker = marker , size = size , opacity = opacity , fill = fill ) # ============================================================================= ## set color attributes # @author Vanya BELYAEV Ivan.Belyaev@itep.ru -# @date 2013-01-21 -def _blue_ ( self , marker = 25 ) : return _color_( self , 4 , marker ) +# @date 2013-01-21 +def _blue_ ( self , + marker = 25 , + size = -1 , + opacity = -1 , + fill = False ) : + return _color_( self , color = 4 , marker = marker , size = size , opacity = opacity , fill = fill ) # ============================================================================= ## set color attributes # @author Vanya BELYAEV Ivan.Belyaev@itep.ru # @date 2013-01-21 -def _magenta_ ( self , marker = 22 ) : return _color_( self , 6 , marker ) +def _magenta_ ( self , + marker = 22 , + size = -1 , + opacity = -1 , + fill = False ) : + return _color_( self , color = 6 , marker = marker , size = size , opacity = opacity , fill = fill ) # ============================================================================= ## set color attributes # @author Vanya BELYAEV Ivan.Belyaev@itep.ru # @date 2013-01-21 -def _cyan_ ( self , marker = 23 ) : return _color_( self , 7 , marker ) +def _cyan_ ( self , + marker = 23 , + size = -1 , + opacity = -1 , + fill = False ) : + return _color_( self , color = 7 , marker = marker , size = size , opacity = opacity , fill = fill ) # ============================================================================= ## set color attributes # @author Vanya BELYAEV Ivan.Belyaev@itep.ru # @date 2013-01-21 -def _green_ ( self , marker = 33 ) : return _color_( self , 8 , marker ) +def _green_ ( self , + marker = 33 , + size = -1 , + opacity = -1 , + fill = False ) : + return _color_( self , color = 8 , marker = marker , size = size , opacity = opacity , fill = fill ) # ============================================================================= ## set color attributes # @author Vanya BELYAEV Ivan.Belyaev@itep.ru # @date 2013-01-21 -def _yellow_ ( self , marker = 34 ) : return _color_( self , 92 , marker ) +def _yellow_ ( self , + marker = 34 , + size = -1 , + opacity = -1 , + fill = False ) : + return _color_( self , color = 92 , marker = marker , size = size , opacity = opacity , fill = fill ) for _t in ( ROOT.TH1D , ROOT.TH1F , ROOT.TGraph , ROOT.TGraphErrors ) : diff --git a/ostap/histos/histos.py b/ostap/histos/histos.py index 6c926910..a2e03740 100755 --- a/ostap/histos/histos.py +++ b/ostap/histos/histos.py @@ -50,7 +50,7 @@ from ostap.math.random_ext import poisson import ostap.stats.moment import ostap.plotting.draw_attributes -import ROOT, sys, math, ctypes, array +import ROOT, sys, math, ctypes, array, itertools # ============================================================================= # logging # ============================================================================= @@ -1565,6 +1565,26 @@ def _h1_iteritems_ ( h1 , low = 1 , high = sys.maxsize ) : ROOT.TH1D . iteritems = _h1_iteritems_ +# ============================================================================= +## Iterate over the values +# @cdoe +# histo = ... +# for v in histo.values() : ... +# @endcode +def _h1_values_ ( h1 ) : + """Iterate over the values + >>> histo = ... + >>> for v in histo.values() : ... + """ + for i , _ , y in h1.items() : + yield y + + +ROOT.TH1F . itervalues = _h1_values_ +ROOT.TH1D . itervalues = _h1_values_ +ROOT.TH1F . values = _h1_values_ +ROOT.TH1D . values = _h1_values_ + # ============================================================================= ## return information about the bin center and width # @author Vanya BELYAEV Ivan.Belyaev@itep.ru @@ -4111,41 +4131,56 @@ def _h1_add_function_integral_ ( h1 , func ) : ROOT.TH1F.addFunctionIntegral = _h1_add_function_integral_ ROOT.TH1D.addFunctionIntegral = _h1_add_function_integral_ - # ============================================================================= -## get the runnig sum over the histogram +## get the running sum over the histogram bins +# @code +# h = ... +# ht = h.sumv ( increasing = True ) +# hf = h.sumv ( increasing = False ) +# @endcode +# It creates a new historgma with the same binning +# such that each bini contains the sum over +# all bins `j` such as +# - \f$ j\le i \f$ if increasing=True +# - \f$ j\ge i \f$ if increasing=False # @author Vanya BELYAEV Ivan.Belyaev@itep.ru # @date 2011-06-07 -def _h1_sumv_ ( h , increasing = True ) : - """Create the ``runnig sum'' over the histogram +def h1_sumv ( histo , increasing = True ) : + """Create the `running sum' over the histogram bins >>> h = ... - >>> h1 = h.sumv() - """ - result = h.Clone ( hID() ) + >>> h1 = h.sumv( increasing = True ) + >>> h2 = h.sumv( increasing = False ) + It creates a new histogram with the same binning + such that each bin `i` contains the sum over all bins `j` such as + - `j<=i` if `increasing=True` + - `i<=j` if `increasing=False` + """ + assert isinstance ( histo , ROOT.TH1 ) and 1 == histo.dim() , \ + "Invalid `histo' type %s" % type ( histo ) + + result = histo.Clone ( hID () ) result.Reset() if not result.GetSumw2() : result.Sumw2() - + if increasing : - _s = VE ( 0 , 0 ) - for ibin in h : - _s += h [ibin] - result [ibin] = VE( _s ) - else : - - for ibin in h : - _s = VE(0,0) - for jbin in h : - if jbin < ibin : continue - _s += h [jbin] - - result [ibin] = VE( _s ) + sumi = VE ( 0 , 0 ) + for i , x , y in histo.items() : + sumi += y + result [ i ] = sumi + + return result + + sumi = VE ( 0 , 0 ) + for i in reversed ( histo ) : + sumi += histo [ i ] + result [ i ] = sumi return result # ============================================================================== -for t in (ROOT.TH1F , ROOT.TH1D ) : - t . sumv = _h1_sumv_ +for t in ( ROOT.TH1F , ROOT.TH1D ) : + t . sumv = h1_sumv # ============================================================================= ## Calculate the "cut-efficiency from the histogram @@ -4187,8 +4222,8 @@ def _h1_effic2_ ( h , value , increasing = True ) : >>> he = h.efficiency ( 14.2 ) """ - s1 = VE(0,0) - s2 = VE(0,0) + s1 = VE ( 0 , 0 ) + s2 = VE ( 0 , 0 ) for i,x,y in h.iteritems () : @@ -4201,13 +4236,13 @@ def _h1_effic2_ ( h , value , increasing = True ) : ## Convert historgam into "efficinecy" histogram # @code # histo = ... -# effic = histp.eff ( ... ) +# effic = histo.eff ( ... ) # @endcode # It adds two extra narrow fake bins! def _h1_effic3_ ( h1 , increasing = True ) : """Convert historgam into "efficinecy" histogram >>> histo = ... - >>> effic = histp.eff ( ... ) + >>> effic = histo.eff ( ... ) - It adds two extra narrow fake bins! """ @@ -4223,8 +4258,8 @@ def _h1_effic3_ ( h1 , increasing = True ) : bw = xa.GetBinUpEdge() - xa.GetBinLowEdge() if abs ( bw ) < minbin : minbin = abs ( bw ) - xf = edges[ 0] + 0.001 * minbin - xl = edges[-1] - 0.001 * minbin + xf = edges [ 0 ] + 0.001 * minbin + xl = edges [ -1 ] - 0.001 * minbin edges.insert ( 1 , xf ) edges.insert ( -1 , xl ) @@ -4273,13 +4308,61 @@ def _my_eff_ ( a , r , c ) : result [ -1 ] = VE ( 1.0 , 0.0 ) if increasing else VE ( 0.0 , 0.0 ) return result + +# =============================================================================== +## Get the cut effciency in form of graph +# - useful for efficincy visualisation +# - a bit better treatment of binnig effects +# @code +# histo = ... +# eff_graph = histo.eff_graph ( increasing = True ) +# @endcode +def _h1_effic4_ ( histo , increasing = True ) : + """Get the cut effciency in form fo graph + - useful for drawing, + - better treatment of binnig effects + >>> histo = ... + >>> eff_graph = histo.eff_graph ( increasing = True ) + """ + + c1 = [ histo [ i ] for i in histo ] + c2 = c1.copy() + c2.reverse () + s1 = [ VE () ] + [ s for s in itertools.accumulate ( c1 ) ] + s2 = [ VE () ] + [ s for s in itertools.accumulate ( c2 ) ] + s2.reverse () + + import ostap.histos.graphs + + np = len ( s1 ) + graph = ROOT.TGraphErrors ( np ) + + the_eff = lambda a,b : a.frac ( b ) + + ## special treatment of the first point + e0 = the_eff ( s1 [ 0 ] , s2 [ 0 ] ) if increasing else the_eff ( s2 [ 0 ] , s1 [ 0 ] ) + xmin , _ = histo.xminmax() + + graph.SetPoint ( 0 , xmin , e0.value () ) + graph.SetPointError ( 0 , 0 , e0.error () ) + + for i, x , _ in histo.items() : + xx = x.value() + x.error() + ei = the_eff ( s1 [ i ] , s2 [ i ] ) if increasing else the_eff ( s2 [ i ] , s1 [ i ] ) + graph.SetPoint ( i , xx , ei.value () ) + graph.SetPointError ( i , 0 , ei.error () ) + + return graph + ROOT.TH1F.effic = _h1_effic_ ROOT.TH1D.effic = _h1_effic_ ROOT.TH1F.efficiency = _h1_effic2_ ROOT.TH1D.efficiency = _h1_effic2_ ROOT.TH1F.eff = _h1_effic3_ ROOT.TH1D.eff = _h1_effic3_ +ROOT.TH1F.eff_graph = _h1_effic4_ +ROOT.TH1D.eff_graph = _h1_effic4_ # ================================================================================ if (2,7) <= python_info : _erfc_ = math.erfc @@ -8253,6 +8336,24 @@ def histo_book ( ranges , kwargs , title = '' ) : # ============================================================================= +# ============================================================================= +## Get a kind of ROC-like curve/graph from two histograms +def _h1_roc_ ( h1 , h2 ) : + + h1sum = h1.sumv () + h2sum= h2.sumv () + + import ostap.histos.graphs + graph = ROOT.TGraphErrors ( len ( h1 ) + 2 ) + + graph [ 0 ] = h1sum [ 0 ] , h2sum [ 0 ] + graph [ -1 ] = h1sum [ -1 ] , h2sum [ -1 ] + + for i , x , y1 in h1s.items() : + y2 = h2s ( x.value () ) + graph [ i ] = y1 , y2 + + return graph # ============================================================================= _decorated_classes_ = ( @@ -8626,8 +8727,9 @@ def histo_book ( ranges , kwargs , title = '' ) : # ROOT.TH1F.addFunctionIntegral , ROOT.TH1D.addFunctionIntegral , - # - _h1_sumv_ , + ### + h1_sumv , + ## ROOT.TH1F.eff , ROOT.TH1D.eff , ROOT.TH1F.effic , diff --git a/ostap/histos/roc.py b/ostap/histos/roc.py new file mode 100644 index 00000000..24263c99 --- /dev/null +++ b/ostap/histos/roc.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# ============================================================================= +## @file +# Simple utility to creat ROC-like curves/gpaphs +# - signal effciency vs background efficiency +# - signal effciency vs background retention +# @author Vanya BELYAEV Ivan.Belyaev@cern.ch +# @date 2011-06-07 +# ============================================================================= +""" Simple utility to creat ROC-like curves/gpaphs + - signal effciency vs background efficiency + - signal effciency vs background retention +""" +# ============================================================================= +__version__ = "$Revision$" +__author__ = "Vanya BELYAEV Ivan.Belyaev@cern.ch" +__date__ = "2024-08-02" +__all__ = ( + 'makeGraph' , # make graph from primitive data + ) +# ============================================================================= +from ostap.core.ostap_types import string_types +import ostap.histos.histos +import ostap.histos.graphs +import ROOT +# ============================================================================= +# logging +# ============================================================================= +from ostap.logger.logger import getLogger +if '__main__' == __name__ : logger = getLogger( 'ostap.histos.roc' ) +else : logger = getLogger( __name__ ) +# ============================================================================= +## Build the ROC-curve from signal and background disctributuions +# @param signal (histogram) of signal distribution +# @param backgrund (histogram) of background distribution +# @return ROC-curve +# @code +# hsignal = ... ## signal distribution +# hbkg = ... ## background distribution +# roc = roc_curve ( signal = hsig , +# backgrund = hbkg , +# increasing = True , ## "keep valeus less than cut value" +# show_sinal = 'efficiency' , +# show_backgrund = 'rejection' ) +# ## get AUC +# import ostap.math,integral as I +# auc = I.integral ( roc , xmin = 0 , xmax = 1.0 ) +# @endcode +def roc_curve ( signal , + background , + increasing , + show_signal = 'efficiency' , + show_background = 'rejection' ) : + + """Build the ROC-curve from signal and background disctributuions + - signal : (histogram) of signal distribution + - backgrund : (histogram) of background distribution + + >>> hsignal = ... ## signal distribution + >>> hbkg = ... ## background distribution + >>> roc = roc_curve ( signal = hsig , + ... backgrund = hbkg , + ... increasing = True , ## "keep vaues that are less than the cut value" + ... show_sinal = 'efficiency' , + ... show_backgrund = 'rejection' ) + + >>> import ostap.math,integral as I + >>> auc = I.integral ( roc , xmin = 0 , xmax = 1.0 ) + + """ + assert isinstance ( signal , ROOT.TH1 ) and 1 == signal .dim() , \ + "Invalid `signal' type: %s" % type ( signal ) + assert isinstance ( background , ROOT.TH1 ) and 1 == background.dim() , \ + "Invalid `background' type: %s" % type ( background ) + + sig_fun = show_signal + if callable ( sig_fun ) : pass + else : + assert isinstance ( sig_fun , string_types ) , "Invalid type of `show_signal' %s" % type ( sig_fun ) + sig_fun = str(sig_fun).strip().lower() + if sig_fun in ( 'e' , 'eff' , 'effic' , 'efficiency' ) : sig_fun = lambda s : s + elif sig_fun in ( 'r' , 'rej' , 'rejec' , 'reject' , 'rejection' ) : sig_fun = lambda s : 1-s + else : + raise TypeError ("Unknown `show_signal' :%s" % show_signal ) + + bkg_fun = show_background + if callable ( bkg_fun ) : pass + else : + assert isinstance ( bkg_fun , string_types ) , "Invalid type of `show_background' %s" % type ( bkg_fun ) + bkg_fun = str(bkg_fun).strip().lower() + if bkg_fun in ( 'e' , 'eff' , 'effic' , 'efficiency' ) : bkg_fun = lambda s : s + elif bkg_fun in ( 'r' , 'rej' , 'rejec' , 'reject' , 'rejection' ) : bkg_fun = lambda s : 1-s + else : + raise TypeError ("Unknown `show_background' :%s" % show_backgrund ) + + + hs = signal + hb = background + + a## signal efficiency + hse = hs.eff ( increasing = increasing ) + + ## background efficiency + hbe = hb.eff ( increasing = increasing ) + + ## output graph: ROC curve + np = len ( hse ) + graph = ROOT.TGraphErrors ( np ) + + ## loop over signal efficiency + for i , xs , es in hse.items() : + + ## backrgiund efficiency + eb = hbe ( xs.value() ) + + ## tarnsform if requested: + + es = sig_fun ( es ) + eb = bkg_fun ( eb ) + + graph [ i - 1 ] = es , eb + + return graph + + +## ============================================================================ +if '__main__' == __name__ : + + from ostap.utils.docme import docme + docme ( __name__ , logger = logger ) + +# ============================================================================= +## The END +# ============================================================================= diff --git a/ostap/math/interpolation.py b/ostap/math/interpolation.py index 70db0fb5..2a87c4c6 100644 --- a/ostap/math/interpolation.py +++ b/ostap/math/interpolation.py @@ -4,10 +4,10 @@ ## @file ostap/math/interpolation.py # Module with some useful utilities for dealing with interpolation. # -# It providesl follwoing interpolations (C++ fast) -# - Lagrange polynomial interpolation (relativelu slow) +# It provides following interpolations (C++/fast) +# - Lagrange polynomial interpolation (relatively slow) # - Neville polynomial interpolartion aka Nevile-Aitken interpolaton (slow) -# - Newton polynimial interpolation (fastest) +# - Newton polynomial interpolation (fastest) # - True Barycentric polymomial interpolation (relatively fast) # - Berrut's 1st rational interpoaltion (fast) # - Berrut's 2nd rational interpoaltion (fast) @@ -23,14 +23,14 @@ # @see Ostap::Math::FloaterHormann # # Features -# - Lagrange scheme allows to calcualet also the derivative with respect to \f$y_i\f$ +# - Lagrange scheme allows to calculate also the derivative with respect to \f$y_i\f$ # - Neville scheme allows to calculate also the derivative with respect to \f$x\f$ # - Newton, Berrut 1st, Berrut's 2nd, true-Barycentric and Floater-Hormann are very fast, -# but they require some tiem for initialization adn thie time can be large. +# but they require some time for initialization and this time can be large. # - All polymonial interpoaltion behaves badly for largde degrees and unform/random grids -# - Usage of dedicated Chebyshev and/or Lobatto grids partly solved this issue, butonly partly -# - For large nmber of pointes rational interpolants behaves more stable, particularly -# Floater-Hormann wwith relatively small value of parameter \f$d\f$ +# - Usage of dedicated Chebyshev and/or Lobatto grids partly solves this issue, but only partly +# - For large number of pointes rational interpolants behave more stable, particularly +# Floater-Hormann with relatively small value of parameter \f$d\f$ # # # @see Jean-Paul Berrut and Lloyd N. Trefethen, @@ -48,7 +48,7 @@ # - Lagrange algorithm is not stable numerically, and Neville algorithm is more stable # # For completeness see also: -# - interpolation with Bersntein polynomials using on Newton-Bernstein algorithm +# - interpolation with Bersntein polynomials using Newton-Bernstein algorithm # - interpolation with B-splines # # In addition purely python interpolators are provided @@ -62,11 +62,11 @@ # ============================================================================= """Useful utilities for dealing with interpolation. - It providesl follwoing interpolations (C++ fast) + It provides following interpolations (C++, fast) - Lagrange polynomial interpolation (relativelu slow) - Neville polynomial interpolartion aka Nevile-Aitken interpolaton (slow) - - Newton polynimial interpolation (fastest) - - True Barycentric polymomial interpolation (relatively fast) + - Newton polynomial interpolation (fastest) + - True Barycentric polynomial interpolation (relatively fast) - Berrut's 1st rational interpoaltion (fast) - Berrut's 2nd rational interpoaltion (fast) - Floater-Hormann rational interpolation (fast) @@ -81,14 +81,14 @@ - see Ostap.Math.FloaterHormann Features - - Lagrange scheme allows to calcualet also the derivative with respect to \f$y_i\f$ + - Lagrange scheme allows to calculate also the derivative with respect to \f$y_i\f$ - Neville scheme allows to calculate also the derivative with respect to \f$x\f$ - Newton, Berrut 1st, Berrut's 2nd, true-Barycentric and Floater-Hormann are very fast, - but they require some tiem for initialization adn thie time can be large. - - All polymonial interpoaltion behaves badly for largde degrees and unform/random grids - - Usage of dedicated Chebyshev and/or Lobatto grids partly solved this issue, butonly partly - - For large nmber of pointes rational interpolants behaves more stable, particularly - Floater-Hormann wwith relatively small value of parameter \f$d\f$ + but they require some time for initialization adn this time can be large. + - All polynonial interpoaltion behaves badly for large degrees and unform/random grids + - Usage of dedicated Chebyshev and/or Lobatto grids partly solves this issue, but only partly + - For large number of points rational interpolants behave more stable, particularly + Floater-Hormann with relatively small value of parameter \f$d\f$ - see Jean-Paul Berrut and Lloyd N. Trefethen, @@ -103,7 +103,7 @@ - Lagrange algorithm is not stable numerically, while Neville algorithm is more stable For completeness see also: - - interpolation with bersntein polynomials using on Newton-Bernstein algorithm + - interpolation with bersntein polynomials using Newton-Bernstein algorithm - interpolation with B-splines In addition purely python interpolators are provided @@ -1013,7 +1013,7 @@ def weight ( self , index ) : # ============================================================================= -## true Barycentric polymnomial interpolant +## true Barycentric polynomial interpolant class Barycentric(BaseInterpolant) : """True barycentric polynomial interpolant """ @@ -1043,8 +1043,7 @@ def __init__ ( self , def weight ( self , index ) : """Get the weigth for the given interpolation node""" - - return self.__weigths[index] + return self.__weigths [ index ] @property def weights ( self ) : @@ -1052,9 +1051,9 @@ def weights ( self ) : return self.__weights # ============================================================================= -## FloaterHormann rational interpolant +## Floater-Hormann rational interpolant class FloaterHormann(BaseInterpolant) : - """FloaterHormann rational interpolant + """Floater-Hormann rational interpolant """ def __init__ ( self , data , @@ -1102,8 +1101,7 @@ def __init__ ( self , def weight ( self , index ) : """Get the weigth for the given interpolation node""" - - return self.__weights[index] + return self.__weights [ index ] @property def weights ( self ) :