Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 有没有办法找到直方图局部极大值的范围?_Python_Scipy_Histogram - Fatal编程技术网

Python 有没有办法找到直方图局部极大值的范围?

Python 有没有办法找到直方图局部极大值的范围?,python,scipy,histogram,Python,Scipy,Histogram,我想知道是否有办法找到直方图的局部极大值范围。例如,假设我有以下直方图(忽略橙色曲线): 直方图实际上是从字典中获得的。我希望找到这个直方图(在水平轴上)的局部最大值的范围,比如说,在这种情况下是1.3-1.6和2.1-2.4。我不知道哪些工具会有帮助,或者我可能想使用哪些技术。我知道有一种工具可以找到一维数组的局部极大值: from scipy.signal import argrelextrema x = np.random.random(12) argrelextrema(x, np.gr

我想知道是否有办法找到直方图的局部极大值范围。例如,假设我有以下直方图(忽略橙色曲线): 直方图实际上是从字典中获得的。我希望找到这个直方图(在水平轴上)的局部最大值的范围,比如说,在这种情况下是1.3-1.6和2.1-2.4。我不知道哪些工具会有帮助,或者我可能想使用哪些技术。我知道有一种工具可以找到一维数组的局部极大值:

from scipy.signal import argrelextrema
x = np.random.random(12)
argrelextrema(x, np.greater)
但我不认为它会在这里工作,因为我正在寻找一个范围,而且直方图上有一些“摆动”。有人能给我一些建议/例子来说明我如何获得我想要的范围吗?非常感谢你的帮助


PS:我试图不仅仅搜索y值高于某个极限的x的范围:)

我不知道我是否正确理解你想要做什么,但是你可以将直方图视为双峰分布的概率密度函数(PDF),然后找到两个模式周围的模式和最高密度间隔(HDI)

因此,我创建了一些示例数据

import numpy as np
import pandas as pd
import scipy.stats as sps
from scipy.signal import find_peaks, argrelextrema
import matplotlib.pyplot as plt

d1 = sps.norm(loc=1.3, scale=.2)
d2 = sps.norm(loc=2.2, scale=.3)

r1 = d1.rvs(size=5000, random_state=1)
r2 = d2.rvs(size=5000, random_state=1)

r = np.concatenate((r1, r2))

h = plt.hist(r, bins=100, density=True);

我们只有
h
,这是
hist
函数的结果,该函数将包含密度(100)和料仓范围(101)

所以我们首先需要选择每个箱子的平均值

density = h[0]
values = h[1][:-1] + np.diff(h[1])[0] / 2

plt.hist(r, bins=100, density=True, alpha=.25)
plt.plot(values, density);

现在我们可以规范化PDF(求和为1)并使用移动平均平滑数据,我们将仅使用移动平均来获得峰值(最大值)和最小值

norm_density = density / density.sum()
norm_density_ma = pd.Series(norm_density).rolling(7, center=True).mean().values

plt.plot(values, norm_density_ma)
plt.plot(values, norm_density);
minima = argrelextrema(norm_density_ma, np.less)[0]
minima
array([40])

现在我们可以得到极大值的索引

peaks = find_peaks(norm_density_ma)[0]
peaks
array([24, 57])
和最小值

norm_density = density / density.sum()
norm_density_ma = pd.Series(norm_density).rolling(7, center=True).mean().values

plt.plot(values, norm_density_ma)
plt.plot(values, norm_density);
minima = argrelextrema(norm_density_ma, np.less)[0]
minima
array([40])
检查它们是否正确

plt.plot(values, norm_density_ma)
plt.plot(values, norm_density)
for peak in peaks:
    plt.axvline(values[peak], color='r')
plt.axvline(values[minima], color='k', ls='--');

最后,我们必须从归一化的
h
直方图数据中找出两种模式(峰值)周围的HDI。我们可以使用一个简单的函数来获取网格的HDI(有关详细信息和详细信息,请参阅)

假设我们希望HDI包含0.3的质量

# HDI around the 1st mode
hdi1 = HDI_of_grid(norm_density, credMass=.3)

plt.plot(values, norm_density_ma)
plt.plot(values, norm_density)
plt.fill_between(
    values[hdi1['indexes']], 
    0, norm_density[hdi1['indexes']],
    alpha=.25
)
for peak in peaks:
    plt.axvline(values[peak], color='r')

对于第二种模式,我们将从
minima
获取HDI以避免第一种模式

# HDI around the 2nd mode
hdi2 = HDI_of_grid(norm_density[minima[0]:], credMass=.3)

plt.plot(values, norm_density_ma)
plt.plot(values, norm_density)
plt.fill_between(
    values[hdi1['indexes']], 
    0, norm_density[hdi1['indexes']],
    alpha=.25
)
plt.fill_between(
    values[hdi2['indexes']+minima], 
    0, norm_density[hdi2['indexes']+minima],
    alpha=.25
)
for peak in peaks:
    plt.axvline(values[peak], color='r')

我们有两个HDI的值

# 1st mode
values[peaks[0]]
1.320249129265321
# 0.3 HDI
values[hdi1['indexes']].take([0, -1])
array([1.12857599, 1.45715851])

# 2nd mode
values[peaks[1]]
2.2238510564735363
# 0.3 HDI
values[hdi2['indexes']+minima].take([0, -1])
array([1.95003229, 2.47028795])

我不知道scipy,但一般来说,局部极大值就是函数值改变的地方。你可以用一些平均函数来消除“噪音”。@user3431635谢谢你的评论!但这里我想保留原始直方图的数据。您有离散值还是连续值?@Aven Desta直方图的值是离散的:)您如何定义“范围”-以什么标准?