Ответ 1
Поскольку у вас нет особого распределения, но у вас может быть много образцов данных, я предлагаю использовать метод непараметрической оценки плотности. Один из типов данных, которые вы описываете (время в мс), явно непрерывный, и один метод непараметрического оценивания функции плотности вероятности (PDF) для непрерывных случайных величин - это гистограмма, о которой вы уже упоминали. Однако, как вы увидите ниже, Оценка плотности ядра (KDE) может быть лучше. Второй тип данных, которые вы описываете (количество символов в последовательности), имеет дискретный вид. Здесь оценка плотности ядра также может быть полезна и может рассматриваться как метод сглаживания для ситуаций, когда у вас нет достаточного количества выборок для всех значений дискретной переменной.
Оценка плотности
В следующем примере показано, как сначала сгенерировать образцы данных из смеси из двух гауссовых распределений, а затем применить оценку плотности ядра, чтобы найти функцию плотности вероятности:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
from sklearn.neighbors import KernelDensity
# Generate random samples from a mixture of 2 Gaussians
# with modes at 5 and 10
data = np.concatenate((5 + np.random.randn(10, 1),
10 + np.random.randn(30, 1)))
# Plot the true distribution
x = np.linspace(0, 16, 1000)[:, np.newaxis]
norm_vals = mlab.normpdf(x, 5, 1) * 0.25 + mlab.normpdf(x, 10, 1) * 0.75
plt.plot(x, norm_vals)
# Plot the data using a normalized histogram
plt.hist(data, 50, normed=True)
# Do kernel density estimation
kd = KernelDensity(kernel='gaussian', bandwidth=0.75).fit(data)
# Plot the estimated densty
kd_vals = np.exp(kd.score_samples(x))
plt.plot(x, kd_vals)
# Show the plots
plt.show()
Это приведет к следующему графику, где истинное распределение отображается синим цветом, гистограмма отображается зеленым цветом, а PDF, оцененный с использованием KDE, отображается красным:
Как вы можете видеть, в этой ситуации PDF, аппроксимированный гистограммой, не очень полезен, в то время как KDE обеспечивает гораздо лучшую оценку. Однако при большом количестве выборок данных и правильном выборе размера бункера гистограмма может также дать хорошую оценку.
Параметры, которые вы можете настроить в случае KDE, - это ядро и пропускная способность. Вы можете думать о ядре как о строительном блоке для оцененного PDF, а в Scikit Learn доступны несколько функций ядра: гауссовский, тофат, epanechnikov, экспоненциальный, линейный, косинус. Изменение полосы пропускания позволяет вам корректировать компромисс между отклонениями. Увеличенная полоса пропускания приведет к увеличению смещения, что хорошо, если у вас меньше выборок данных. Меньшая полоса пропускания увеличит дисперсию (в оценку будет включено меньше выборок), но даст более точную оценку, когда доступно больше образцов.
Расчет вероятности
Для PDF вероятность получается путем вычисления интеграла по диапазону значений. Как вы заметили, это приведет к вероятности 0 для определенного значения.
Scikit Learn, похоже, не имеет встроенной функции для вычисления вероятности. Однако легко оценить интеграл PDF по диапазону. Мы можем это сделать, оценивая PDF несколько раз в пределах диапазона и суммируя полученные значения, умноженные на размер шага между каждой точкой оценки. В приведенном ниже примере образцы N
получены с шагом step
.
# Get probability for range of values
start = 5 # Start of the range
end = 6 # End of the range
N = 100 # Number of evaluation points
step = (end - start) / (N - 1) # Step size
x = np.linspace(start, end, N)[:, np.newaxis] # Generate values in the range
kd_vals = np.exp(kd.score_samples(x)) # Get PDF values for each x
probability = np.sum(kd_vals * step) # Approximate the integral of the PDF
print(probability)
Обратите внимание, что kd.score_samples
генерирует лог-правдоподобие образцов данных. Поэтому для получения правдоподобия требуется np.exp
.
То же вычисление может быть выполнено с использованием встроенных методов интеграции SciPy, что даст немного более точный результат:
from scipy.integrate import quad
probability = quad(lambda x: np.exp(kd.score_samples(x)), start, end)[0]
Например, для одного прогона первый метод вычислял вероятность как 0.0859024655305
, а второй - 0.0850974209996139
.