Моделирование распределения вероятностей как нечеткого множества в 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. Может быть, есть еще один более простой способ сделать это?
Вот как я обычно обрабатываю входные значения (не уверен, что часть, которая добавляет 0
s нужно), какое шоу у меня вместо ???
вычислить желаемое 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)