9

I'm trying to plot some visualisations with matplotlib, and in one of my functions, I check if waves are logarithmic. This is my current working version:

import numpy as np
def is_logarithmic(waves):

    def expfunc(x, a, b, c):
        return a*np.exp(b*x) + c

    wcopy = list(waves)
    wcopy.sort()

    # If the ratio of x-max : x-min < 10, don't use a logarithmic scale
    # (at least in matplotlib)
    if (wcopy[-1] / wcopy[0]) < 10:
        return False

    # Take a guess at whether it is logarithmic by seeing how well the x-scale
    # fits an exponential curve
    diffs = []
    for ii in range(len(wcopy) - 1):
        diffs.append(wcopy[ii + 1] - wcopy[ii])

    # Fit the diffs to an exponential curve
    x = np.arange(len(wcopy)-1)
    try:
        popt, pcov = curve_fit(expfunc, x, diffs)
    except Exception as e:
        print e
        popt = [0.0, 0.0, 0.0]
        pcov = np.inf

    # If a > 0.5 and covsum < 1000.0
    # use a logarithmic scale.
    if type(pcov) == float:
        # It's probably np.inf
        covsum = pcov
    else:
        covsum = pcov.diagonal().sum()
    res = (covsum < 1000.0) & (popt[0] > 0.5)
    return res

I'm trying to find an alternative to scipy's curve_fit(), because I don't want to install such a big library just to use that one function. Is there something else I can use, or a combination of other functions from using ideally just numpy and matplotlib, to get a similar result?

Andrew
  • 1,000
  • 1
  • 17
  • 33
  • 1
    Well, `curve_fit` uses the [Levenberg-Marquardt](https://en.wikipedia.org/wiki/Levenberg%E2%80%93Marquardt_algorithm) algorithm to do the minimization of errors. You can always implement it yourself. – hitzg Jul 08 '15 at 07:46
  • 1
    Unless you are working with embedded systems, `46 MB` (installed on linux) for scipy is not that much. Matplotlib is `72 MB` in comparison. – rth Jul 08 '15 at 09:02

2 Answers2

7

Numpy can do linear (numpy.linalg.lstsq) and polynomial fits (numpy.polyfit). In general you need scipy for fitting to functions you define yourself (scipy uses the fortran minpack while numpy is built only with C).

However, for your example, you could use a similar approach to this question to fit an exp. Basically, take the logatithm of both sides of the equation and use numpy.polyfit.

Community
  • 1
  • 1
Ed Smith
  • 12,716
  • 2
  • 43
  • 55
  • 1
    Taking the `log` of both sides will not work in this case because of the constant term `c` in the `a*np.exp(b*x) + c`. – tom10 Jul 10 '15 at 13:24
1

You can also use the lmfit.models library which has a lot of predefined models.

https://lmfit.github.io/lmfit-py/

https://lmfit.github.io/lmfit-py/builtin_models.html#exponential-and-power-law-models

It also supports custom functions.

Joni
  • 69
  • 1
  • 3
  • 1
    The goal of the questioner is to avoid installing a large library like scipy for a singular function. lmfit doesn't really fulfill that requirement, since it requires scipy as a dependency. – merlyn Nov 09 '18 at 09:49