Невозможно уместить ECDF с помощью scipy.optimize.curve_fit - PullRequest
0 голосов
/ 31 августа 2018

Я пытаюсь приблизить эмпирическую интегральную функцию распределения ( ECDF, которую я хочу приблизительно ) с гладкой функцией (с менее чем 5 параметрами), такой как обобщенная логистическая функция .

Однако, используя scipy.optimize.curve_fit, операция подгонки дает действительно плохие приближения или не работает вообще (в зависимости от начальных значений). Переменная series представляет мои данные, хранящиеся как pandas.Series.

from scipy.optimize import curve_fit

def fit_ecdf(x):
    x = np.sort(x)
    def result(v):
        return np.searchsorted(x, v, side='right') / x.size
    return result

ecdf = fit_ecdf(series)

def genlogistic(x, B, M, Q, v):
    return 1 / (1 + Q * np.exp(-B * (x - M))) ** (1 / v)

params = curve_fit(genlogistic, xdata = series, ydata = ecdf(series), p0 = (0.1, 10.0, 0.1, 0.1))[0]

Должен ли я использовать другой тип функции для подгонки? Есть ли ошибки в коде?

ОБНОВЛЕНИЕ - 1

Как и просили, я ссылаюсь на CSV, содержащий данные .

ОБНОВЛЕНИЕ - 2

После долгих поисков, проб и ошибок я нахожу эту функцию

f(x; a, b, c) = 1 - 1 / (1 + (x / b) ** a) ** c
with a = 4.61320000, b = 2.94570952, c = 0.5886922

, который подходит намного лучше, чем другой. Единственная проблема - маленький шаг, который показывает ECDF около x=1. Как я могу изменить f, чтобы улучшить качество посадки? Я думал о добавлении какой-то функции, которая «актуальна» только в таких точках. Вот графические результаты подгонки, где сплошная синяя линия - ECDF, а пунктирная линия представляет (x, f(x)) точек.

Here are the graphical results of the fit

Ответы [ 2 ]

0 голосов
/ 02 сентября 2018

Я получил ОК для 5-параметрического логистического уравнения (см. Изображение и код), используя уникальные значения, не уверен, что для ваших нужд достаточно кривой нижнего предела, пожалуйста, проверьте. enter image description here

import numpy as np

def Sigmoidal_FiveParameterLogistic_model(x_in): # from zunzun.com

    # coefficients
    a = 9.9220221252324947E-01
    b = -3.1572339989462903E+00
    c = 2.2303376075685142E+00
    d = 2.6271495036080207E-02
    f = 3.4399008905318986E+00

    return d + (a - d) / np.power(1.0 + np.power(x_in / c, b), f)
0 голосов
/ 01 сентября 2018

Я узнаю, как справиться с этим маленьким шагом рядом с x=1. Как выражено в вопросе, добавление некоторой функции, которая важна только в этом интервале, изменило игру. «Шаг» заканчивается примерно на (1.7, 0.04), поэтому мне потребовалась какая-то функция, которая выравнивается для x > 1.7 и имеет y = 0.04 в качестве асимптоты. Естественный выбор (просто для того, чтобы остаться на месте) состоял в том, чтобы взять функцию типа f(x) = 1/exp(x). Благодаря JamesPhillips я также выбрал правильные данные для регрессии (без двойных значений = без переоцененных точек).

Код Python

from scipy.optimize import curve_fit

def fit_ecdf(x):
    x = np.sort(x)
    def result(v):
        return np.searchsorted(x, v, side = 'right') / x.size
    return result

ecdf = fit_ecdf(series)

unique_series = series.unique().tolist()

def cdf_interpolation(x, a, b, c, d):
    f_1 = 0.95 + (0 - 0.95) / (1 + (x / b) ** a) ** c + 0.05
    f_2 = (0 - 0.05)/(np.exp(d * x))
    return f_1 + f_2

params = curve_fit(cdf_interpolation, 
                   xdata = unique_series , 
                   ydata = ecdf(unique_series), 
                   p0 = (6.0, 3.0, 0.4, 1.0))[0]

Параметры

a = 6.03256462 
b = 2.89418871 
c = 0.42997956
d = 1.06864006

Графические результаты ECDF & Inferred CDF

...