Я хочу создать массив с неравномерно распределенными значениями. Расстояние должно определяться суперпозицией (например) двух нормальных распределений с разными средними значениями и значениями ширины. Для одиночного (нормального) дистрибутива мне удалось получить то, что я хочу с помощью этого поста: python, взвешенный linspace
Используя этот код:
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
dist = stats.norm(loc=1.2, scale=0.6)
bounds = dist.cdf([0, 2])
pp = np.linspace(*bounds, num=21)
vals = dist.ppf(pp)
plt.plot(vals, [1]*vals.size, 'o')
plt.show()
Я получаю результат, который хочу для одного дистрибутива:
Однако мне нужно то же самое для суперпозиции двух нормальных распределений, например:
dist1 = stats.norm(loc=3, scale=2)
dist2 = stats.norm(loc=1.2, scale=0.6)
Вот как выглядит гистограмма наложенных распределений:
В качестве временного решения я создал массивы для каждого дистрибутива отдельно и добавил их вместе. Однако это не совсем то, что я хочу, потому что добавление двух отдельных массивов приводит к колебаниям размера шага между добавленными массивами (например, может случиться так, что два значения из двух разных (отдельных) массивов почти или точно идентичны).
Я также попытался определить новый дистрибутив, который наследуется от класса rv_continuous
от класса scipy.stats
, но мне не удалось реализовать два разных параметра среднего/ширины.
Я почти уверен, что это должно работать, добавляя отдельные функции плотности вероятности, но, к сожалению, я также потерпел неудачу с этим подходом.
Заранее спасибо за любую помощь и/или комментарий!
Вы можете создать подкласс rv_continuous
и предоставить PDF-файл, который является средним значением двух заданных PDF-файлов.
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
class sum_gaussians_gen(stats.rv_continuous):
def _pdf(self, x):
return (stats.norm.pdf(x, loc=3, scale=2) + stats.norm.pdf(x, loc=1.2, scale=0.6)) / 2
dist = sum_gaussians_gen()
bounds = dist.cdf([0, 7])
pp = np.linspace(*bounds, num=21)
vals = dist.ppf(pp)
plt.plot(vals, [0.5] * vals.size, 'o')
xs = np.linspace(0, 7, 500)
plt.plot(xs, dist.pdf(xs))
plt.ylim(ymin=0)
plt.show()
спасибо за ваш ответ кстати. Мне очень помог! Для подобного приложения мне нужно получить случайные числа из такого распределения. К сожалению, использование dist.rvs(size=n)
для этого ОЧЕНЬ медленно. Я создал новый вопрос для этого Ускорить рисование случайных значений из наложенных усеченных нормальных распределений и подумал, что вы могли бы помочь и здесь? Еще раз спасибо!
Когда вы говорите «сложили их вместе», вы имели в виду добавление массивов numpy или их наложение, например, так vals = np.array(list(dist1.ppf(pp)) + list(dist2.ppf(pp)))? Кажется, это то, что вы ищете (при необходимости можно добавить обработку идентичных записей)?