Плотность ядра Python Gaussian вычисляет оценку для новых значений

это мой код:

import numpy as np
from scipy.stats.kde import gaussian_kde
from scipy.stats import norm
from numpy import linspace,hstack
from pylab import plot,show,hist

import re
import json

attribute_file="path"

attribute_values = [line.rstrip('\n') for line in open(attribute_file)]

obs=[]

#Assume the list obs as loaded

obs=np.asarray(osservazioni)
obs=np.sort(obs,kind='mergesort')
x_min=osservazioni[0]
x_max=osservazioni[len(obs)-1]



# obtaining the pdf (my_pdf is a function!)
my_pdf = gaussian_kde(obs)

# plotting the result
x = linspace(0,x_max,1000)

plot(x,my_pdf(x),'r') # distribution function

hist(obs,normed=1,alpha=.3) # histogram
show()

new_values = np.asarray([-1, 0, 2, 3, 4, 5, 768])[:, np.newaxis]
for e in new_values:
    print (str(e)+" - "+str(my_pdf(e)*100*2))

Проблема. Массив obs содержит список всех obs. Мне нужно рассчитать оценку (от 0 до 1) для новых значений

[-1, 0, 2, 3, 4, 500, 768]

Таким образом, значение -1 должно иметь дискретную оценку, потому что оно не появляется в распределении, но находится рядом со значением 1, которое очень часто встречается в наблюдениях.


person Usi Usi    schedule 19.08.2015    source источник
comment
Что должна представлять ваша оценка? Используя KDE, вы получите высокие оценки для значений, близких к частым в вашем наборе данных. Если вас интересует другой результат, возможно, вам следует подумать об использовании другой модели.   -  person liborm    schedule 21.08.2015


Ответы (2)


Причина этого в том, что в ваших наблюдениях гораздо больше единиц, чем 768. Таким образом, даже если -1 не совсем равно 1, оно получает высокое прогнозируемое значение, потому что гистограмма имеет гораздо большее значение при 1, чем при 768.

С точностью до мультипликативной константы формула для прогнозирования выглядит следующим образом:

введите здесь описание изображения

где K — ваше ядро, D — ваши наблюдения, а h — пропускная способность. Глядя на документ для gaussian_kde, мы обратите внимание, что если для bw_method не указано значение, оно каким-то образом оценивается, что здесь вас не устраивает.

Таким образом, вы можете попробовать несколько разных значений: чем больше пропускная способность, тем больше точек, удаленных от ваших новых данных, учитывается, предельный случай — это почти постоянная прогнозируемая функция.

С другой стороны, очень маленькая пропускная способность учитывает только очень близкие точки, а это то, что вам нужно.

Несколько графиков, иллюстрирующих влияние пропускной способности: введите здесь описание изображения

Используемый код:

import matplotlib.pyplot as plt
f, axarr = plt.subplots(2, 2, figsize=(10, 10))
for i, h in enumerate([0.01, 0.1, 1, 5]):
    my_pdf = gaussian_kde(osservazioni, h)
    axarr[i//2, i%2].plot(x, my_pdf(x), 'r') # distribution function
    axarr[i//2, i%2].set_title("Bandwidth: {0}".format(h))
    axarr[i//2, i%2].hist(osservazioni, normed=1, alpha=.3) # histogram

С вашим текущим кодом для x=-1 значение K((x-x_i)/h) для всех x_i, равных 1, меньше 1, но вы суммируете много этих значений (есть 921 1 с в ваших наблюдениях, а также 357 2 с)

С другой стороны, для x = 768 значение ядра равно 1 для всех x_i, равных 768, но таких точек не так много (39, если быть точным). Так что здесь множество «маленьких» терминов составляют большую сумму, чем небольшое количество более крупных терминов.

Если вы не хотите такого поведения, вы можете уменьшить размер вашего гауссовского ядра: таким образом штраф (K (-2)), выплачиваемый из-за расстояния между -1 и 1, будет выше. Но я думаю, что это было бы переобучением ваших наблюдений.

Формула для определения того, является ли новая выборка приемлемой (по сравнению с вашим эмпирическим распределением) или нет, является скорее статистической проблемой, вы можете взглянуть на stats.stackexchange.com

Вы всегда можете попытаться использовать низкое значение для полосы пропускания, что даст вам прогнозируемую функцию с пиком. Затем вы можете нормализовать эту функцию, разделив ее на максимальное значение.

После этого все предсказанные значения будут между 0 и 1:

maxDensityValue = np.max(my_pdf(x))
for e in new_values:
    print("{0} {1}".format(e, my_pdf(e)/maxDensityValue))
person P. Camilleri    schedule 21.08.2015
comment
Хорошее объяснение, спасибо и вам... что вы предлагаете для достижения того, что мне нужно? - person Usi Usi; 22.08.2015
comment
Спасибо за точные улучшения вашего ответа ... Не могли бы вы также привести мне пример последней части? Как найти максимальное значение для нормализации функции? - person Usi Usi; 23.08.2015
comment
@UsiUsi Не уверен, но кажется, что всегда будет my_pdf(1). В противном случае просто используйте np.max(my_pdf(x)). - person P. Camilleri; 23.08.2015
comment
Извините, я отсутствовал на короткий отпуск. вроде нормально... А как насчет нормализации оценок? трудно найти порог... Мне нужно что-то более изощренное. Это мои результаты.. оценка для [-1] составляет [ 0,59625501] оценка для [1] составляет [ 0,98929683] оценка для [0] составляет [ 0,84244511] оценка для [10] составляет [ 0,00987971] оценка для [128] составляет [ 0,05891493] оценка для [256] составляет [ 0,10650007] оценка для [300] составляет [ 1,00605929e-08] оценка для [4] составляет [ 0,5433299] оценка для [500] составляет [ 3,18585441e-07] оценка для [768] составляет [0,02945747] оценка для [512] равна [0,43053219] - person Usi Usi; 28.08.2015
comment
Это похоже на статистическую проблему, а не на проблему программирования... Я бы предложил 1e-2 в качестве порога, но полностью по эмпирическому правилу. - person P. Camilleri; 28.08.2015
comment
Я предоставил награду... Если нет, как я могу ее предоставить? - person Usi Usi; 31.08.2015
comment
Дорогой Массиас, не могли бы вы объяснить, что такое x и xi в формуле? - person Usi Usi; 11.09.2015
comment
x - это точка, в которой вы хотите предсказать свою функцию, x_i (i варьируется) - это все точки в вашем наборе данных (наблюдения) - person P. Camilleri; 11.09.2015

-1 и 0 очень близки к 1, что встречается очень часто, поэтому предполагается, что они будут иметь более высокое значение. (Вот почему 0 имеет более высокое значение, чем -1, даже если они оба не отображаются, 0 ближе к 1).

Что вам нужно, так это меньшая пропускная способность: посмотрите на линию на графике, чтобы увидеть это. Прямо сейчас числа, которые вообще не отображаются, вплоть до 80 получают большую ценность из-за их близости к 1 и 2.
Для достижения этого просто установите скаляр в качестве метода width_method:

my_pdf = gaussian_kde(osservazioni, 0.1)

Это может быть не совсем тот скаляр, который вам нужен, но попробуйте изменить 0,1 на 0,05 или даже меньше и посмотрите, что соответствует тому, что вы ищете.

Также, если вам нужно значение от 0 до 1, вам нужно убедиться, что my_pdf() никогда не сможет вернуть значение больше 0,005, потому что вы умножаете его на 200.
Вот что Я имею в виду:

for e in new_values:
    print (str(e)+" - "+str(my_pdf(e)*100*2))

Значение, которое вы выводите:

mypdf(e)*100*2 == mypdf(e)*200
#You want the max value to be 1 so
1 >= mypdf(e)*200
#Divide both sides by 200
0.005 >= mypdf(e)

Таким образом, mypdf() должно иметь максимальное значение 0,005. ИЛИ Вы можете просто масштабировать данные.

Чтобы максимальное значение равнялось 1 и оставалось пропорциональным входным данным, независимо от входных данных, необходимо сначала собрать выходные данные, а затем масштабировать их на основе наибольшего значения.
< Strong>Пример:

orig_val=[] #Create intermediate list

for e in new_values:
    orig_val += [my_pdf(e)*100*2] #Fill with the data

for i in range(len(new_values)):
    print (str(new_values[i])+" - "+str(orig_val[i]/max(orig_val))) #Scale based on largest value

Узнайте больше о gaussian_kde здесь: scipy.stats.gaussian_kde< /а>

person ThatGuyRussell    schedule 21.08.2015
comment
Большое спасибо за ваш ответ, он мне очень помогает. Но я не могу понять эту часть. Также, если вам нужно значение от 0 до 1, вам нужно убедиться, что my_pdf() никогда не сможет вернуть значение больше 0,005, потому что вы умножаете его на 200. можете ли вы добавить больше информации об этом ? Что мне нужно, так это своего рода порог... Если оценка больше порога, значение надежно, если значение ниже порога, мой алгоритм должен отбросить его... Спасибо - person Usi Usi; 22.08.2015
comment
Конечно, @UsiUsi Я сейчас проясню это в своем коде, а затем скажу, поможет ли это! Кстати, у вас сработало изменение полосы пропускания? - person ThatGuyRussell; 22.08.2015
comment
Конечно, я сделал быстрый тест, и с вашим предложением kde лучше следует исходному дистрибутиву... таким образом я получаю лучший результат... чтобы быть более ясным, теперь я получаю более высокий балл за значения, которые очень распространены в исходные наблюдения.. и более низкий балл для всех других значений... Это отчасти то, что мне нужно... Чего мне не хватает в данный момент, так это способа расчета балла только между 0 и 1. Мне нужна формула для создайте порог, который может дать алгоритму способ решить, доступно ли новое значение или нет - person Usi Usi; 22.08.2015
comment
@UsiUsi Дайте мне знать, помогло ли мое решение для масштабирования! - person ThatGuyRussell; 22.08.2015
comment
@UsiUsi Также, если это решение работает для вас, примите его, чтобы другие пользователи, ищущие ответ на этот вопрос, могли знать, что это решение работает. - person ThatGuyRussell; 22.08.2015
comment
Не хочу показаться мелочным, но вы также можете принять другой ответ, если он лучше. - person P. Camilleri; 22.08.2015
comment
@ М. Массиас Конечно. Извините, если я сделал так, что выбор лучшего варианта не был выбором. Твоего ответа не было в то время, это отличный ответ. - person ThatGuyRussell; 22.08.2015