Skip to content

Fitting

The fitting module provides a simple wrapper for scipy.curve_fit() that facilitates the rapid fitting to data held in a pandas.DataFrame and subsequent evaluation and plotting of these fits. The expected work flow is to call quantalyze.fit(...) and either retrieve the result of the fit from the attributes of the returned Fit object or call one of the Fit object's utility methods (e.g. evaluate(...) or plot(...)).

fit(function, df, x_column, y_column, x_min=None, x_max=None, y_min=None, y_max=None, p0=None, **kwargs)

Fits a given function to data in a DataFrame within an optional x and y range.

Parameters:

Name Type Description Default
function callable

The function to fit to the data. It should take x data as the first argument and parameters to fit as subsequent arguments.

required
df DataFrame

The input DataFrame containing the data.

required
x_column str

The name of the column in the DataFrame to use as the x data.

required
y_column str

The name of the column in the DataFrame to use as the y data.

required
x_min float

The minimum value of x to include in the fitting. Defaults to None.

None
x_max float

The maximum value of x to include in the fitting. Defaults to None.

None
y_min float

The minimum value of y to include in the fitting. Defaults to None.

None
y_max float

The maximum value of y to include in the fitting. Defaults to None.

None
p0 array - like

Initial guess for the parameters. Must have a length equal to that of the number of free parameters in function Defaults to None.

None
**kwargs

Additional keyword arguments passed to curve_fit.

{}

Returns:

Name Type Description
Fit Fit

An instance of the Fit class containing the fitted function and parameters.

Raises:

Type Description
RuntimeError

If there is no data in the specified x or y range to fit.

ValueError

If the initial guess p0 does not have the correct length.

Source code in src/quantalyze/core/fitting.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
def fit(
    function: callable, 
    df: pd.DataFrame, 
    x_column, 
    y_column, 
    x_min=None, 
    x_max=None, 
    y_min=None, 
    y_max=None, 
    p0=None,
    **kwargs,
) -> Fit:
    """
    Fits a given function to data in a DataFrame within an optional x and y range.

    Args:
        function (callable): The function to fit to the data. It should take x data as the first argument 
            and parameters to fit as subsequent arguments.
        df (pandas.DataFrame): The input DataFrame containing the data.
        x_column (str): The name of the column in the DataFrame to use as the x data.
        y_column (str): The name of the column in the DataFrame to use as the y data.
        x_min (float, optional): The minimum value of x to include in the fitting. Defaults to None.
        x_max (float, optional): The maximum value of x to include in the fitting. Defaults to None.
        y_min (float, optional): The minimum value of y to include in the fitting. Defaults to None.
        y_max (float, optional): The maximum value of y to include in the fitting. Defaults to None.
        p0 (array-like, optional): Initial guess for the parameters. Must have a length equal to that of the number of free parameters in `function` Defaults to None.
        **kwargs: Additional keyword arguments passed to `curve_fit`.

    Returns:
        Fit: An instance of the Fit class containing the fitted function and parameters.

    Raises:
        RuntimeError: If there is no data in the specified x or y range to fit.
        ValueError: If the initial guess `p0` does not have the correct length.
    """
    # Filter the dataframe based on x_min and x_max
    if x_min is not None:
        df = df[df[x_column] >= x_min]
    if x_max is not None:
        df = df[df[x_column] <= x_max]

    # Filter the dataframe based on y_min and y_max
    if y_min is not None:
        df = df[df[y_column] >= y_min]
    if y_max is not None:
        df = df[df[y_column] <= y_max]

    # Extract x and y data
    x_data = df[x_column].values
    y_data = df[y_column].values

    # Check if there is data to fit
    if len(x_data) == 0 or len(y_data) == 0:
        raise RuntimeError("No data in the specified x or y range to fit.")

    # Check if p0 is provided and has the correct length
    if p0 is not None:
        num_params = len(signature(function).parameters) - 1  # Subtract 1 for the x parameter
        if len(p0) != num_params:
            raise ValueError(f"Initial guess p0 must have length {num_params}, but got {len(p0)}.")

    # Perform curve fitting
    parameters, covariance = curve_fit(function, x_data, y_data, p0=p0, **kwargs)

    return Fit(function=function, parameters=parameters, covariance=covariance)

Fit(function, parameters, covariance)

Represents the result of a fitting operation.

Attributes:

Name Type Description
function callable

The fitted function.

parameters array - like

Optimal values for the parameters.

covariance 2D array

The estimated covariance of parameters.

Initialize a Fit instance.

Parameters:

Name Type Description Default
function callable

The fitted function.

required
parameters array - like

Optimal values for the parameters.

required
covariance 2D array

The estimated covariance of parameters.

required
Source code in src/quantalyze/core/fitting.py
16
17
18
19
20
21
22
23
24
25
26
27
def __init__(self, function, parameters, covariance):
    """
    Initialize a Fit instance.

    Args:
        function (callable): The fitted function.
        parameters (array-like): Optimal values for the parameters.
        covariance (2D array): The estimated covariance of `parameters`.
    """
    self.function = function
    self.parameters = parameters
    self.covariance = covariance

__getitem__(key)

Get the parameter value by name.

Parameters:

Name Type Description Default
key str

The name of the parameter.

required

Returns:

Name Type Description
float

The value of the parameter.

Source code in src/quantalyze/core/fitting.py
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def __getitem__(self, key):
    """
    Get the parameter value by name.

    Args:
        key (str): The name of the parameter.

    Returns:
        float: The value of the parameter.
    """

    if isinstance(key, str):
        if key in self._function_args():
            return self.parameters[self._function_args().index(key)]
        else:
            raise KeyError(f"Parameter '{key}' not found in fitted function.")
    elif isinstance(key, int):
        if 0 <= key < len(self.parameters):
            return self.parameters[key]
        else:
            raise IndexError(f"Index {key} out of range for parameters.")
    else:
        raise TypeError(f"Unsupported key type: {type(key)}")

evaluate(x)

Evaluate the fitted function at given data points.

Parameters:

Name Type Description Default
x array - like

The input data points where the function should be evaluated.

required

Returns:

Type Description

array-like: The evaluated values of the fitted function at the given data points.

Source code in src/quantalyze/core/fitting.py
29
30
31
32
33
34
35
36
37
38
39
def evaluate(self, x):
    """
    Evaluate the fitted function at given data points.

    Args:
        x (array-like): The input data points where the function should be evaluated.

    Returns:
        array-like: The evaluated values of the fitted function at the given data points.
    """
    return self.function(x, *self.parameters)

plot(ax, x, **kwargs)

Plot the evaluated function on the given axes.

Parameters:

Name Type Description Default
ax Axes

The axes on which to plot.

required
x array - like

The x values to evaluate the function.

required
**kwargs

Additional keyword arguments passed to ax.plot().

{}

Returns:

Type Description
None

None

Source code in src/quantalyze/core/fitting.py
41
42
43
44
45
46
47
48
49
50
51
52
53
def plot(self, ax, x, **kwargs) -> None:
    """
    Plot the evaluated function on the given axes.

    Args:
        ax (matplotlib.axes.Axes): The axes on which to plot.
        x (array-like): The x values to evaluate the function.
        **kwargs: Additional keyword arguments passed to ax.plot().

    Returns:
        None
    """
    ax.plot(x, self.evaluate(x), **kwargs)

Examples

Example data

import pandas as pd
import numpy as np


# Example DataFrame - a straight line with noise
df = pd.DataFrame({
    'x': np.linspace(0, 10, 100),
    'y': 3 * np.linspace(0, 10, 100), + 0.5 * np.random.randn(100)
})

Fit and print parameters

from quantalyze.core import fit


# Define a function to fit
f = lambda x, a, b: a + b*x

# Perform the fit
result = fit(f, df, 'x', 'y')

# Print the fitted parameters
print("Fitted parameters:", result.parameters)

Fit and evaluate

from quantalyze.core import fit


# Define a function to fit
f = lambda x, a, b: a + b*x

# Perform the fit and evaluate the function at x=20
result = fit(f, df, 'x', 'y').evaluate(20)

print("result:", result)

Fit and plot

from quantalyze.core import fit
from matplotlib import pyplot as plt

# Create a figure and plot the test data.
fig, ax = plt.subplots()
ax.plot(df['x'], df['y'], 'o')

# Define a function to fit
f = lambda x, a, b: a + b*x

# Perform the fit and plot the result onto pyplot axes
result = fit(f, df, 'x', 'y').plot(ax, np.linspace(0, 20, 10), color='k', linewidth=0.75, linestyle='--')

# Show the figure
fig.show()