7

I am currently writing a python definition called f_from_data which uses interpolation find point on a line so far I have written this:

def f_from_data(xs, ys, x):
    xfine = np.linspace(min(xs), max(xs), 10000)
    y0 = inter.interp1d(xs, ys, kind = 'linear')
    ans = (y0(xfine))[numpy.searchsorted(xfine, x)]
    ans =  round(ans,2)
    return ans

This is giving me what I want to I need to make it so I can enter:

f = f_from_data([3, 4, 6], [0, 1, 2])
print f(3)
>>>0.0

How do I go about doing this? I've looked around but can't seem to find anything as I think its really trivial but I'm just missing somthing.

smci
  • 32,567
  • 20
  • 113
  • 146
GBA13
  • 205
  • 1
  • 2
  • 9
  • FYI, this process is called [partial function application](http://en.m.wikipedia.org/wiki/Partial_application). – Kevin Dec 22 '14 at 05:25

5 Answers5

13

Using functools.partial:

from functools import partial

f = partial(f_from_data, [3, 4, 6], [0, 1, 2])

partial will create a callable object with the first 2 arguments already set.

tmr232
  • 1,171
  • 14
  • 23
3

interpolate.interp1d returns a callable:

import scipy.interpolate as interpolate

f_from_data = interpolate.interp1d
f = f_from_data([3, 4, 6], [0, 1, 2])
print(f(3))

yields

0.0

Since f_from_data can be assigned to interpolate.interp1d, you may not need f_from_data at all. Now, it is true that this does not chop the x-range into 10000 grid points, and use searchsorted to snap the x value to a nearby grid point, but in general you wouldn't want to do that anyway since interp1d gives you a better linear interpolation without it.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
2

Perhaps something like this?

def f_from_data(xs, ys):
    def interpolate(x):
       xfine = np.linspace(min(xs), max(xs), 10000)
       y0 = inter.interp1d(xs, ys, kind = 'linear')
       ans = (y0(xfine))[numpy.searchsorted(xfine, x)]
       ans =  round(ans,2)
       return ans
    return interpolate

Warning - I don't know matplotlib well enough to say whether the code is correct.

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
2

If what you want is simple, here it is a simple solution

>>> f = lambda x: f_from_data([3, 4, 6], [0, 1, 2], x)
>>> print f(3)
0.0
>>> 

If you dislike lambda

>>> def f(x): return f_from_data([3, 4, 6], [0, 1, 2], x)

In both cases you must be sure that f_from_data is in scope when you define the auxiliary function.

gboffi
  • 22,939
  • 8
  • 54
  • 85
1

The more general approach would be to create a class with a __call__ method, so something like this:

class f_from_data(object):
    def __init__(self, xs, ys):
        self.xfine = np.linspace(min(xs), max(xs), 10000)
        self.y0 = inter.interp1d(xs, ys, kind = 'linear')
    def __call__(self, x):
        ans = (self.y0(self.xfine))[numpy.searchsorted(self.xfine, x)]
        return round(ans, 2)
Jaime
  • 65,696
  • 17
  • 124
  • 159
  • While this may be common in other contexts, it'd be *extremely* unusual in numpy code. – sapi Dec 22 '14 at 00:57
  • What makes it unusual in numpy code? It is the way, e.g. `scipy.interpolate` makes all its function-returning 1D interpolators work, see [here](https://github.com/scipy/scipy/blob/v0.14.0/scipy/interpolate/polyint.py#L21), how `numpy.poly1d` handles polynomial-evaluating functions, see [here](https://github.com/numpy/numpy/blob/3ef77eea0d9c2cd76bc9b89b04a32f1322f842d5/numpy/lib/polynomial.py#L939), or `numpy.vectorize` makes vectorized functions, see [here](https://github.com/numpy/numpy/blob/3ef77eea0d9c2cd76bc9b89b04a32f1322f842d5/numpy/lib/function_base.py#L1577). – Jaime Dec 22 '14 at 20:19