简体   繁体   中英

How do we fit a sigmoid function in Python?

For reproducibility reasons, I am sharing the simple dataset I am working here .

To make it clear of what I am doing - from column 2, I am reading the current row and compare it with the value of the previous row. If it is greater, I keep comparing. If the current value is smaller than the previous row's value, I want to divide the current value (smaller) by the previous value (larger). Accordingly, below is my source code.

import numpy as np
import scipy.stats
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import beta

protocols = {}

types = {"data_v": "data_v.csv"}

for protname, fname in types.items():
    col_time,col_window = np.loadtxt(fname,delimiter=',').T
    trailing_window = col_window[:-1] # "past" values at a given index
    leading_window  = col_window[1:]  # "current values at a given index
    decreasing_inds = np.where(leading_window < trailing_window)[0]
    quotient = leading_window[decreasing_inds]/trailing_window[decreasing_inds]
    quotient_times = col_time[decreasing_inds]

    protocols[protname] = {
        "col_time": col_time,
        "col_window": col_window,
        "quotient_times": quotient_times,
        "quotient": quotient,
    }
    plt.figure(); plt.clf()
    plt.plot(quotient_times, quotient, ".", label=protname, color="blue")
    plt.ylim(0, 1.0001)
    plt.title(protname)
    plt.xlabel("quotient_times")
    plt.ylabel("quotient")
    plt.legend()
    plt.show()
    sns.distplot(quotient, hist=False, label=protname)

This gives the following plots.

在此处输入图片说明

在此处输入图片说明

As we can see from the plots

  • Data-V has a quotient of 0.8 when the quotient_times is less than 3 and the quotient remains 0.5 if the quotient_times is greater than 3.

I have also fitted it into a beta distribution using the following code

xt = plt.xticks()[0]  
xmin, xmax = min(xt), max(xt)  
lnspc = np.linspace(xmin, xmax, len(quotient))

alpha,beta,loc,scale = stats.beta.fit(quotient)  
pdf_beta = stats.beta.pdf(lnspc, alpha, beta,loc, scale)  
plt.plot(lnspc, pdf_beta, label="Data-V", color="darkblue", alpha=0.9)
plt.xlabel('$quotient$')
#plt.ylabel(r'$p(x|\alpha,\beta)$')
plt.title('Beta Distribution')
plt.legend(loc="best", frameon=False)

在此处输入图片说明

How can we fit the quotient (defined above) into a sigmoid function to have a plot something like the following?

在此处输入图片说明

You want to fit a sigmoid , or actually a logistic function . This can be varied in several ways, such as slope, midpoint, magnitude and offset.

Here's the code that defines that sigmoid function and utilizes the scipy.optimize.curve_fit function to minimize the error by tuning the parameters.

from scipy.optimize import curve_fit

def sigmoid (x, A, h, slope, C):
    return 1 / (1 + np.exp ((x - h) / slope)) *  A + C

# Fits the function sigmoid with the x and y data
#   Note, we are using the cumulative sum of your beta distribution!
p, _ = curve_fit(sigmoid, lnspc, pdf_beta.cumsum())

# Plots the data
plt.plot(lnspc, pdf_beta.cumsum(), label='original')
plt.plot(lnspc, sigmoid(lnspc, *p), label='sigmoid fit')
plt.legend()

# Show parameters for the fit
print(p)

This gives you the following plot:

比较原始数据和S形拟合

and the following parameter space (for the above used function):

[-1.82910694e+01  4.88870236e-01  6.15103201e-03  1.82895890e+01]

If you want to fit the variables quotient_time and quotient , you simply change the variables.

...
p, _ = curve_fit(sigmoid, quotient_times, quotient)
...

and plot it:

商和S形拟合

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM