Python高斯核密度计算新值的分数

Python高斯核密度计算新值的分数,python,gaussian,kde,kernel-density,Python,Gaussian,Kde,Kernel Density,这是我的代码: 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') f

这是我的代码:

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,4500768]


因此,值-1必须有一个离散的分数,因为它不出现在分布中,而是在观察中非常常见的1值旁边

原因是你的观察结果中的1比768多得多。因此,即使-1不完全是1,它也会得到一个很高的预测值,因为直方图在1处的值比在768处的值大得多

对于乘法常数,预测公式为:

其中K是你的核,D是你的观测值,h是你的带宽。看看,我们发现如果没有为
bw\u方法提供值,那么它是以某种方式估算的,这在这里并不适合您

因此,您可以尝试一些不同的值:带宽越大,考虑的距离新数据越远的点越多,极限情况是一个几乎恒定的预测函数

另一方面,非常小的带宽只考虑非常接近的点,这就是我想要的

一些图表说明了带宽的影响:

使用的代码:

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,所有等于1的x_i的K((x-x_i)/h)值都小于1,但这些值加起来很多(观测值中有921个1,也有357个2)

另一方面,对于x=768,对于768的所有x_i,内核的值是1,但这样的点并不多(精确地说是39)。所以这里很多“小”项的总和要比一小部分大的项的总和大

如果您不希望出现这种行为,可以减小高斯核的大小:这样,由于-1和1之间的距离而支付的惩罚(K(-2))将更高。但我认为这太过符合你的观察结果了

确定新样本是否可接受(与经验分布相比)的公式更像是一个统计问题,您可以查看
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))

-1和0都非常接近经常出现的1,因此预测它们的值会更高。(这就是为什么0的值高于-1,即使它们都没有显示,0也更接近1)

您需要的是更小的带宽:请查看图表中的线条以了解这一点-目前,在距离80远的地方根本不显示的数字由于接近1和2而获得了很大的价值
只需设置一个标量作为带宽\u方法即可实现此目的:

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您只需缩放数据即可。

要使最大值为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

在这里了解有关高斯分布的更多信息:

你的分数应该代表什么?使用KDE,您将获得接近数据集中常见值的高分。如果你对不同的结果感兴趣,也许你应该考虑使用不同的模型。非常感谢你的回答,这对我很有帮助。但是我不能理解“如果你想要一个介于0和1之间的值,你需要确保my_pdf()永远不能返回一个超过.005的值,因为你要将它乘以200。”你能添加更多关于它的信息吗?我需要的是一个门槛。。。如果分数大于阈值,则该值是可靠的,如果该值低于阈值,则我的算法必须放弃该值。。。谢天谢地@usi我现在会在我的代码中清除它,然后告诉我它是否有用!顺便问一下,改变带宽对你有用吗?当然,我做了一个快速测试,根据你的建议,kde更好地遵循原来的发行版。。。这样我得到了更好的结果。。。更清楚的是,我得到了一个更高的分数,这是原始观测中非常常见的值。。所有其他值的分数都较低。。。这部分是我需要的。。。我现在错过的是一种只计算0到1之间的分数的方法。我需要一个公式来创建一个阈值,这个阈值可以给算法一种方法来决定一个新值是可关注的还是可关注的not@UsiUsi让我知道我的缩放解决方案是否有帮助@USI如果此解决方案对您有效,请接受它,以便其他搜索此问题答案的用户可以知道此解决方案有效。很好的解释,也感谢您。。。你有什么建议可以满足我的需要?谢谢你对答案的精确改进。。。你能给我举个最后一部分的例子吗?如何找到最大值来规范化函数?@usi不确定,但似乎总是
my\u pdf(1)
。否则,只需使用
np.max(my_pdf(x))
。很抱歉,我出去了一个短暂的假期。看起来还可以。。。但是如何使分数正常化呢?很难找到一个门槛。。。我需要更复杂的东西。这是我的结果。。[-1]的分数为[0.59625501],[1]的分数为[0.98929683],[0]的分数为[0.84244511],[10]的分数为[0.00987971]的分数为[128]i