Skip to content

Commit

Permalink
Merge pull request #518 from GAA-UAM/feature/create_interpolation_exa…
Browse files Browse the repository at this point in the history
…mple

New example for creating interpolation/extrapolation methods.
  • Loading branch information
vnmabus committed Feb 27, 2023
2 parents 223f14d + 0445775 commit 48d1fae
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 10 deletions.
4 changes: 4 additions & 0 deletions examples/expand_skfda/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Expand scikit-fda
=================

Examples of how to expand the functionality of scikit-fda with custom behaviors.
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@

# %%
# In this example, we want to showcase how it is possible to make new
# functional basis compatible with :class:`~skfda.FDataBasis`, by
# subclassing the :class:`Basis` class.
# functional basis compatible with
# :class:`~skfda.representation.basis.FDataBasis`, by subclassing the
# :class:`~skfda.representation.basis.Basis` class.
#
# Suppose that we already know that our data belongs to (or can be
# reasonably approximated in) the functional space spanned by the basis
Expand All @@ -36,13 +37,15 @@ def g(t):


# %%
# Lets now define the functional basis. We create a subclass of :class:`Basis`
# containing the definition of our desired basis. We need to overload the
# ``__init__`` method in order to add the necessary parameters for the creation
# of the basis. :class:`Basis` requires both the domain range and the number of
# elements in the basis in order to work. As this particular basis has fixed
# size, we only expose the ``domain_range`` parameter in the constructor, but
# we still pass the fixed size to the parent class constructor.
# Lets now define the functional basis. We create a subclass of
# :class:`~skfda.representation.basis.Basis` containing the definition of our
# desired basis. We need to overload the ``__init__`` method in order to add
# the necessary parameters for the creation of the basis.
# :class:`~skfda.representation.basis.Basis` requires both the domain range and
# the number of elements in the basis in order to work. As this particular
# basis has fixed size, we only expose the ``domain_range`` parameter in the
# constructor, but we still pass the fixed size to the parent class
# constructor.
#
# It is also necessary to override the protected ``_evaluate`` method, that
# defines the evaluation of the basis elements.
Expand Down Expand Up @@ -82,7 +85,8 @@ def _evaluate(
#
# In this particular case, we are not interested in the derivatives, only in
# correct representation and evaluation. We can now test the conversion from
# :class:`FDataGrid` to :class:`~skfda.FDataBasis` for elements in this space.
# :class:`~skfda.representation.grid.FDataGrid` to
# :class:`~skfda.representation.basis.FDataBasis` for elements in this space.

# %%
# We first define a (discretized) function in the space spanned by :math:`f`
Expand Down
92 changes: 92 additions & 0 deletions examples/expand_skfda/plot_new_evaluator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# type: ignore
"""
Creating a new interpolation or extrapolation strategy
======================================================
Shows how to add new interpolation and extrapolation strategies.
"""

# Author: Carlos Ramos Carreño
# License: MIT

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

from skfda.representation import FDataGrid

# %%
# In this example, we want to showcase how it is possible to make new
# interpolation and extrapolation strategies.
# These are Python callables with the following prototype:


def evaluator_prototype(fdata, eval_points, *, aligned):
"""Prototype of a extrapolation/interpolation strategy."""
pass

# %%
# Here, ``fdata`` is a :class:`~skfda.representation.FData` object,
# ``èval_points`` is a NumPy array with the points at which this object
# will be evaluated, and ``aligned`` is a boolean parameter indicating if
# the points are common for all samples or different for each.

# %%
# For example, lets consider for illustration purposes only an
# interpolation/extrapolation strategy that uses the
# `Lagrange polynomial <https://en.wikipedia.org/wiki/Lagrange_polynomial>`_
# between the points of a :class:`~skfda.representation.grid.FDataGrid`.
# This is in general a bad idea, as when the number of points is high this
# polynomial has rapid oscillations between the measured points.
# Moreover, the implementation here is not vectorized and has low performance.


def evaluator_lagrange(fdata, eval_points, *, aligned):
"""Lagrange interpolation, for 1D FDataGrid only."""
grid_points = fdata.grid_points[0]
result = []

for i, data in enumerate(fdata.data_matrix):
polynomial = lagrange(grid_points, data)

if aligned:
# Same points for all observations.
# The dimension is n_points x dim_domain (1 in this case).
result.append(polynomial(eval_points))
else:
# Different points for every observation.
# The dimension is n_samples x n_points x dim_domain.
result.append(polynomial(eval_points[i]))

return np.array(result)

# %%
# We can now create a new :class:`~skfda.representation.grid.FDataGrid` and
# plot it. Note that the plot uses the specified interpolation between the
# measured points.
# Note also that is not necessary to specify the extrapolation, as by
# default for :class:`~skfda.representation.grid.FDataGrid` it already calls
# the interpolation if no extrapolation is defined.


X = FDataGrid(
[[0, 1, 2], [0, 1, 8], [0, 0, 0]],
grid_points=[0, 1, 2],
interpolation=evaluator_lagrange,
)

X.plot()
plt.show()

# %%
# We can try to evaluate the function at different points, including some
# between measurements or outside the original range, to test the
# interpolation and extrapolation.

X([-1, 0, 0.5, 1, 2, 3])

# %%
# We can also try to evaluate each observation at different points to test
# this behavior.

X([[-1, 0], [0.5, 1], [2, 3]], aligned=False)

0 comments on commit 48d1fae

Please sign in to comment.