Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.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 3.x 如何根据阵列的密度对其进行子采样?(删除频繁值,保留罕见值)_Python 3.x_Numpy_Matplotlib_Subsampling - Fatal编程技术网

Python 3.x 如何根据阵列的密度对其进行子采样?(删除频繁值,保留罕见值)

Python 3.x 如何根据阵列的密度对其进行子采样?(删除频繁值,保留罕见值),python-3.x,numpy,matplotlib,subsampling,Python 3.x,Numpy,Matplotlib,Subsampling,我有一个问题,我想绘制一个数据分布,其中一些值经常出现,而另一些值非常罕见。积分总数约为30000分。呈现png或god forbid pdf这样的绘图需要花费很长时间,而且pdf太大,无法显示 因此,我想对数据进行二次采样,仅用于绘图。我想要达到的是,在密度高的地方移除许多重叠的点,但在密度低的地方保留几乎概率为1的点 现在,numpy.random.choice允许我们指定一个概率向量,我已经根据数据直方图进行了一些调整。但我似乎无法做出选择,这样才能真正保留这几点 我附上了数据的图像;分布

我有一个问题,我想绘制一个数据分布,其中一些值经常出现,而另一些值非常罕见。积分总数约为30000分。呈现png或god forbid pdf这样的绘图需要花费很长时间,而且pdf太大,无法显示

因此,我想对数据进行二次采样,仅用于绘图。我想要达到的是,在密度高的地方移除许多重叠的点,但在密度低的地方保留几乎概率为1的点

现在,numpy.random.choice允许我们指定一个概率向量,我已经根据数据直方图进行了一些调整。但我似乎无法做出选择,这样才能真正保留这几点

我附上了数据的图像;分布的右尾端的点要少几个数量级,所以我想保留这些点。数据是3d的,但密度只来自一个维度,所以我可以用它来衡量给定位置上有多少个点


一种可能的方法是建立数据的估计概率分布,然后根据每个点的估计概率密度的倒数进行采样,或者根据估计概率密度越大而变小的其他函数进行采样。有,一个简单的是。下面是一个例子:

import numpy as np
import scipy.stats
import matplotlib.pyplot as plt

np.random.seed(100)
# Make some random Gaussian data
data = np.random.multivariate_normal([1, 1], [[1, 0], [0, 1]], size=1000)
# Compute KDE
kde = scipy.stats.gaussian_kde(data.T)
# Choice probabilities are computed from inverse probability density in KDE
p = 1 / kde.pdf(data.T)
# Normalize choice probabilities
p /= np.sum(p)
# Make sample using choice probabilities
idx = np.random.choice(np.arange(len(data)), size=100, replace=False, p=p)
sample = data[idx]
# Plot
plt.figure()
plt.scatter(data[:, 0], data[:, 1], label='Data', s=10)
plt.scatter(sample[:, 0], sample[:, 1], label='Sample', s=7)
plt.legend()
输出:


一种可能的方法是建立数据的估计概率分布,然后根据每个点的估计概率密度的倒数进行采样,或者根据估计概率密度越大而变小的其他函数进行采样。有,一个简单的是。下面是一个例子:

import numpy as np
import scipy.stats
import matplotlib.pyplot as plt

np.random.seed(100)
# Make some random Gaussian data
data = np.random.multivariate_normal([1, 1], [[1, 0], [0, 1]], size=1000)
# Compute KDE
kde = scipy.stats.gaussian_kde(data.T)
# Choice probabilities are computed from inverse probability density in KDE
p = 1 / kde.pdf(data.T)
# Normalize choice probabilities
p /= np.sum(p)
# Make sample using choice probabilities
idx = np.random.choice(np.arange(len(data)), size=100, replace=False, p=p)
sample = data[idx]
# Plot
plt.figure()
plt.scatter(data[:, 0], data[:, 1], label='Data', s=10)
plt.scatter(sample[:, 0], sample[:, 1], label='Sample', s=7)
plt.legend()
输出:


考虑以下函数。它将沿轴和轴将数据存储在相等的存储箱中

如果垃圾箱中有一个或两个点,接管这些点, 如果箱子中有更多点,则接管最小值和最大值。 附加第一个和最后一个点,以确保使用相同的数据范围。 这允许在低密度区域保留原始数据,但显著减少在高密度区域绘制的数据量。同时,所有特征都以足够密集的分块方式保留下来

import numpy as np; np.random.seed(42)

def filt(x,y, bins):
    d = np.digitize(x, bins)
    xfilt = []
    yfilt = []
    for i in np.unique(d):
        xi = x[d == i]
        yi = y[d == i]
        if len(xi) <= 2:
            xfilt.extend(list(xi))
            yfilt.extend(list(yi))
        else:
            xfilt.extend([xi[np.argmax(yi)], xi[np.argmin(yi)]])
            yfilt.extend([yi.max(), yi.min()])
    # prepend/append first/last point if necessary
    if x[0] != xfilt[0]:
        xfilt = [x[0]] + xfilt
        yfilt = [y[0]] + yfilt
    if x[-1] != xfilt[-1]:
        xfilt.append(x[-1])
        yfilt.append(y[-1])
    sort = np.argsort(xfilt)
    return np.array(xfilt)[sort], np.array(yfilt)[sort]
然后调用xf,yf=filtex,y,bins并绘制原始数据和过滤数据,得出:

下面将显示具有大约30000个数据点的问题的用例。使用所介绍的技术可以将绘制点的数量从30000个减少到500个左右。这个数字当然取决于正在使用的箱子——这里有300个箱子。在这种情况下,该函数需要约10 ms的时间进行计算。这不是很快,但与绘制所有点相比仍然有很大的改进

import matplotlib.pyplot as plt

# Generate some data
x = np.sort(np.random.rayleigh(3, size=30000))
y = np.cumsum(np.random.randn(len(x)))+250
# Decide for a number of bins
bins = np.linspace(x.min(),x.max(),301)
# Filter data
xf, yf = filt(x,y,bins) 

# Plot results
fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, figsize=(7,8), 
                                    gridspec_kw=dict(height_ratios=[1,2,2]))

ax1.hist(x, bins=bins)
ax1.set_yscale("log")
ax1.set_yticks([1,10,100,1000])

ax2.plot(x,y, linewidth=1, label="original data, {} points".format(len(x)))

ax3.plot(xf, yf, linewidth=1, label="binned min/max, {} points".format(len(xf)))

for ax in [ax2, ax3]:
    ax.legend()
plt.show()

考虑以下函数。它将沿轴和轴将数据存储在相等的存储箱中

如果垃圾箱中有一个或两个点,接管这些点, 如果箱子中有更多点,则接管最小值和最大值。 附加第一个和最后一个点,以确保使用相同的数据范围。 这允许在低密度区域保留原始数据,但显著减少在高密度区域绘制的数据量。同时,所有特征都以足够密集的分块方式保留下来

import numpy as np; np.random.seed(42)

def filt(x,y, bins):
    d = np.digitize(x, bins)
    xfilt = []
    yfilt = []
    for i in np.unique(d):
        xi = x[d == i]
        yi = y[d == i]
        if len(xi) <= 2:
            xfilt.extend(list(xi))
            yfilt.extend(list(yi))
        else:
            xfilt.extend([xi[np.argmax(yi)], xi[np.argmin(yi)]])
            yfilt.extend([yi.max(), yi.min()])
    # prepend/append first/last point if necessary
    if x[0] != xfilt[0]:
        xfilt = [x[0]] + xfilt
        yfilt = [y[0]] + yfilt
    if x[-1] != xfilt[-1]:
        xfilt.append(x[-1])
        yfilt.append(y[-1])
    sort = np.argsort(xfilt)
    return np.array(xfilt)[sort], np.array(yfilt)[sort]
然后调用xf,yf=filtex,y,bins并绘制原始数据和过滤数据,得出:

下面将显示具有大约30000个数据点的问题的用例。使用所介绍的技术可以将绘制点的数量从30000个减少到500个左右。这个数字当然取决于正在使用的箱子——这里有300个箱子。在这种情况下,该函数需要约10 ms的时间进行计算。这不是很快,但与绘制所有点相比仍然有很大的改进

import matplotlib.pyplot as plt

# Generate some data
x = np.sort(np.random.rayleigh(3, size=30000))
y = np.cumsum(np.random.randn(len(x)))+250
# Decide for a number of bins
bins = np.linspace(x.min(),x.max(),301)
# Filter data
xf, yf = filt(x,y,bins) 

# Plot results
fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, figsize=(7,8), 
                                    gridspec_kw=dict(height_ratios=[1,2,2]))

ax1.hist(x, bins=bins)
ax1.set_yscale("log")
ax1.set_yticks([1,10,100,1000])

ax2.plot(x,y, linewidth=1, label="original data, {} points".format(len(x)))

ax3.plot(xf, yf, linewidth=1, label="binned min/max, {} points".format(len(xf)))

for ax in [ax2, ax3]:
    ax.legend()
plt.show()

我想与@ImportanceOfBeingErnest bbands gmail私下聊天我想与@ImportanceOfBeingErnest bbands gmail私下聊天