2015-08-19 8 views
12

это мой код: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)) 

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

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

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

+0

Что должен представлять ваш счет? Используя KDE, вы получите высокие оценки для значений, близких к частым в вашем наборе данных. Если вас интересует другой результат, возможно, вы подумали об использовании другой модели. – liborm

ответ

9

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

до мультипликативной константы, формула для предсказания:

enter image description here

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

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

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

Некоторые графики, чтобы проиллюстрировать влияние пропускной способности: enter image description here

код используется:

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 

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

С другой стороны, для x = 768, значение ядра равно 1 для всех x_i, которые равны 7 68, но таких точек не так много (точнее, 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)) 
+0

Хорошее объяснение, спасибо вам также ... что вы предлагаете для достижения того, что мне нужно? –

+0

Спасибо за точные улучшения в вашем ответе ... Можете ли вы также привести мне пример последней части? Как найти максимальное значение для нормализации функции? –

+0

@UsiUsi Не уверен, но кажется, что это всегда будет 'my_pdf (1)'. В противном случае просто используйте 'np.max (my_pdf (x))'. –

1

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

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

my_pdf = gaussian_kde(osservazioni, 0.1) 

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

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

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

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

+0

Спасибо большое за ответ, мне это очень помогает. Но я не могу понять эту часть. Также, если вам нужно значение от 0 до 1, вы должны убедиться, что my_pdf() никогда не сможет вернуть значение более .005, потому что вы умножаете его на 200. " Вы можете добавить дополнительную информацию об этом? Что мне нужно - это своего рода порог ... Является ли оценка больше порога, это значение является надежным, если значение ниже порога, мой алгоритм должен отбросить его ... Спасибо –

+0

Конечно @UsiUsi Я очищу это в моем коде сейчас, а затем скажите мне, помогает ли это! Кстати, изменилось ли использование полосы пропускания для вас? – ThatGuyRussell

+0

Конечно, я сделал быстрый тест, и это с вашим предложением, что kde лучше подходит к исходному дистрибутиву ... таким образом, я получаю лучший результат ... чтобы быть более ясным, теперь я получаю более высокий балл за очень часто используемые значения в первоначальных наблюдениях .. и более низкий балл для всех других значений ... Это отчасти то, что мне нужно ... То, что я пропустил на данный момент, - это способ подсчета очков только между 0 и 1. Мне нужно формулу, чтобы создать порог, который может дать алго способ решить, доступно ли новое значение или нет. –