Как я могу создать собственную сигмовидную функцию?

Я пытаюсь создать собственную функцию сигмовидной формы, потому что хочу масштабировать данные во время предварительной обработки. По сути, цель состоит в том, чтобы получить функцию сигмовидной формы, которая выводит значения от 0 до 1 и принимает только положительные входные значения (она приближается к 0, когда входные данные приближаются к 0, и к 1, если входные данные приближаются к + бесконечности). Ключевым моментом является то, что я хочу иметь возможность выбирать точки перегиба S-образной формы по своему желанию. У меня есть небольшой набросок (простите за умение рисовать) .

  1. Точки, которые я хочу выбрать, отмечены как A и B, и в идеале они находятся где-то посередине кривой, соединяющей линейную часть функции к асимптотам.

    Вот как я это сделал на данный момент; Я попытался вписать классическую логистику функция в двух точках.

Вот функция =:

def sigmoid(x,x0, k):
y = 1 / (1 + np.exp(-k * (x - x0)))
return y

И вот подходит:

ydata = [0.1, 0.9]
xdata = [0.22, 1.34]
p0 = [np.median(xdata), 1]  # this is a mandatory initial guess
from scipy.optimize import curve_fit

popt, pcov = curve_fit(sigmoid, xdata, ydata, p0=p0, method='dogbox')

Здесь xdata соответствует точкам A и B на оси x (которые я хочу иметь возможность изменять), а ydata — это произвольные точки, на которые я хочу сопоставить A и B, чтобы они примерно находились в точках перегиба оси. S-кривая (возможно, я не знаю, есть ли лучший способ сделать это).

Далее сюжет:

x = np.linspace(0, 5, 1000)
y = sigmoid(x,*popt)

plt.figure()
plt.plot(xdata, ydata, 'o', label='10th/90th percentiles')
plt.plot(x, y, label='sigmoid curve')
plt.ylim(0, 1.3)
plt.legend(loc='best')
plt.show()

дает цифру: (игнорируйте метку процентилей в легенде, это мои баллы A/b)

Это не очень хорошая форма. Особенно к 0, переход не такой плавный и постепенный. Я бы хотел сдвинуть функцию вправо, чтобы кривая была более плавной, но при этом перехватывать точки A и B в точках перегиба. Есть ли у вас какие-либо предложения о том, как мне этого добиться? Добавление сдвига в определение сигмовидной функции не сработает, поскольку смещение будет просто перезаписано аппроксимацией кривой. Есть ли более разумный способ решить эту проблему, чем мой подход, которого я не вижу?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
78
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам нужно использовать стандартную сигмовидную функцию? Пробовали ли вы что-то вроде плавной версии сдвинутой абсолютной функции?

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-2,5,100)
a = 1

f = lambda x, eps : ((x-a)/np.sqrt((x-a)**2+eps) + 1)/2

plt.figure()
for eps in np.logspace(-3,0,4):
    plt.plot(x,f(x,eps),"--", label = str(eps))
plt.legend()
plt.show()

Вывод примера кода

Нет, мне не обязательно использовать стандартную функцию, мне подходит любая функция, подобная той, что вы предложили. Но как мне тогда выбрать точки перегиба? Думаю, я не понимаю, как это могло бы решить мою проблему, хотя форма, возможно, лучше.

cercio 25.06.2024 13:22

Возможно, я неправильно понял вашу проблему. Кажется, что эта кривая растягивает ее еще больше (по крайней мере, для ваших A и B), но я не уверен, сможете ли вы растянуть ее еще дальше, поскольку у вас есть только две степени свободы и две точки, которые вы хотите перехватить, пока принуждение хвостов к 0 и 1. Для моей маленькой функции «a» будет значением x для точки, где вторая производная равна нулю, а eps заставит хвост работать (увеличение отталкивает его), но вы не будете иметь возможность менять эпсилон без потери эффекта интерполяции для точек А и В.

jkguttormsen 25.06.2024 13:43
Ответ принят как подходящий

Проблема вашей модели в ее симметрии. Для вашего набора данных требуется сильная асимметричная сигмоида.

import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize, special, stats

Давайте добавим к вашим данным две почти безобидные точки, чтобы иметь достаточно точек для подгонки как минимум двух параметров и обеспечить прохождение кривой мимо начала координат.

ydata = [0, 0.1, 0.9, 1]
xdata = [0, 0.22, 1.34, 5]
p0 = [np.median(xdata), 1.]  # this is a mandatory initial guess
sigma=[0.1, 0.01, 0.01, 100]

Мы также добавляем веса (сигмы), чтобы отдать приоритет вашим точкам и началу координат.

Теперь мы можем сравнить вашу модель (которая симметрична):

def model1(x, k, x0):
    return special.expit(k * (x - x0))

popt1, pcov1 = optimize.curve_fit(model1, xdata, ydata, p0=p0, sigma=sigma)
# array([3.92654466, 0.78030023]

С двумя асимметричными сигмоидами (хорошим кандидатом для этого являются CDF асимметричных распределений). Мы соответственно выбрали: распределения Вейбулла и логарифмически нормальное:

def model2(x, c, loc):
    return stats.invweibull(c=c, loc=loc).cdf(x)

popt2, pcov2 = optimize.curve_fit(model2, xdata, ydata, p0=p0, sigma=sigma)
# array([ 3.48553148, -0.56719092]

def model3(x, s, loc):
    return stats.lognorm(s=s, loc=loc).cdf(x)

popt3, pcov3 = optimize.curve_fit(model3, xdata, ydata, p0=p0, sigma=sigma)
# array([ 0.41684656, -0.36610887]

Он отображается следующим образом:

Другие вопросы по теме