Моделирование распределения вероятностей как нечеткого множества в Python3

Я пытаюсь построить нечеткий набор из ряда примеров значений с python3,

Например, учитывая [6, 7, 8, 9, 27] Я хотел бы получить функцию, которая:

  • возвращается 0.0 от 0 до 5ca,
  • постепенно доходит до 1.0 от 5 до 6,
  • остается в 1.0 с 6 до 9,
  • постепенно снижается до 0.0 от 9 до 10 лет,
  • остается в 0.0 от 10 до 26,
  • постепенно доходит до 1.0 от 26 до 27 лет,
  • постепенно снижается до 0.0 от 27 до 28 лет,
  • возвращается 0.0 с 28ca и позже.

Обратите внимание, что y значения всегда в диапазоне [0.0, 1.0] и если в серии отсутствует значение, y из этого значения 0,0.

Пожалуйста, учтите, что в самом общем случае входные значения могут быть [9, 41, 20, 13 ,11, 12, 14, 40, 4, 4, 4, 3, 34, 22] (значения всегда можно отсортировать, но обратите внимание, что в этой серии значение 4 повторяется 3 раза, поэтому я ожидаю, что вероятность будет 1, а все остальные значения будут иметь более низкое значение вероятности - не обязательно 1/3, как в этом случае).

Желаемый результат

В верхней части этого рисунка показана желаемая функция, построенная до x=16 (нарисованный от руки). Я был бы более чем счастлив получить что-нибудь подобное. В нижней части рисунка показаны некоторые дополнительные функции, которые хотелось бы иметь, но не являются строго обязательными:

  • лучше сглаживание, чем показано на моем рисунке (A),
  • совокупный эффект (Б) при условии, что...
  • функция никогда не поднимается выше 1 (C) и...
  • функция никогда не опускается ниже 0 (D).

Я пробовал некоторые подходы, адаптированные, например, из полифита, Безье, Гаусса или других, но результаты оказались не такими, как я ожидал. Я также попробовал с пакетомfuzzpy но я не мог заставить его работать из-за его зависимости от epydoc который, кажется, не совместим с python3, Не повезло и с StatModels.

Кто-нибудь может подсказать, как добиться желаемой функции? Заранее спасибо.

Если вам интересно, я планирую использовать результирующую функцию для прогнозирования вероятности заданного значения; в отношении нечеткого множества, описанного выше, например, 4.0 возвращает 0.0, 6.5 возвращает 1.0 и 5.8 что-то вроде 0,85. Может быть, есть еще один более простой способ сделать это?


Вот как я обычно обрабатываю входные значения (не уверен, что часть, которая добавляет 0s нужно), какое шоу у меня вместо ??? вычислить желаемое f?

def prepare(values, normalize=True):
    max = 0
    table = {}
    for value in values:
        table[value] = (table[value] if value in table else 0) + 1
        if normalize and table[value] > max:
            max = table[value]

    if normalize:
        for value in table:
           table[value] /= float(max)

    for value in range(sorted(table)[-1] + 2):
        if value not in table:
            table[value] = 0

    x = sorted(table)
    y = [table[value] for value in x]
    return x, y

if __name__ == '__main__':
    # get x and y vectors
    x, y = prepare([9, 41, 20, 13, 11, 12, 14, 40, 4, 4, 4, 3, 34, 22], normalize=True)

    # calculate fitting function
    f = ???

    # calculate new x's and y's
    x_new = np.linspace(x[0], x[-1], 50)
    y_new = f(x_new)

    # plot the results
    plt.plot(x, y, 'o', x_new, y_new)
    plt.xlim([x[0] - 1, x[-1] + 1])
    plt.show()

    print("Done.")

Практический пример, просто чтобы прояснить мотивы для этого... Рядом значений может быть количество минут, после которых люди перестают стоять в очереди перед киоском... С такой моделью мы могли бы попытаться предсказать насколько вероятно, что кто-то покинет очередь, зная, сколько времени ждал. Значение, прочитанное таким образом, может быть затем обезврежено, например, в happily waiting [0,00, 0,33], just waiting (0,33, 0,66] и about to leave (0,66, 1,00]. В случае about to leave что кто-то может быть занят чем-то (и рекламой?), чтобы убедить его остаться.

2 ответа

Это работает только (из-за np.bincount) с набором целых чисел.

def fuzzy_interp(x, vals):
    vmn, vmx = np.amin(vals), np.amax(vals)
    v = vals - vmn + 1
    b = np.bincount(v, minlength = vmx - vmn + 2)
    b = b / np.amax(b)
    return np.interp(x - vmn - 1, np.arange(b.size), b, left = 0, right = 0)
def pulse(x):
    return np.maximum(0, 1 - abs(x))

def fuzzy_in_unscaled(x, xs):
    return pulse(np.subtract.outer(x, xs)).sum(axis=-1)

def fuzzy_in(x, xs):
    largest = fuzzy_in_unscaled(xs, xs).max()
    return fuzzy_in_unscaled(x, xs) / largest
>>> fuzzy_in(1.5, [1, 3, 4, 5])  # single membership
0.5
>>> fuzzy_in([[1.5, 3], [3.5, 10]], [1, 3, 4, 5])  # vectorized in the first argument
array([[0.5, 1], [1, 0]])

Это использует тот факт, что пиковые значения должны лежать на элементах. Это не правда для всех pulse функции.

Вы бы хорошо, чтобы предварительно вычислить largest, так как это O(N^2)

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