从 numpy 数组中删除错误但合理的值
Posted
技术标签:
【中文标题】从 numpy 数组中删除错误但合理的值【英文标题】:Remove bad but plausible values from numpy array 【发布时间】:2018-03-24 14:56:25 【问题描述】:我有一个基本的 numpy 值数组(称为时间序列,如下所示)。略高于 0 的值通常表示错误的值(理想情况下,它们本来是 Nan'd 但唉......),所以我想将它们从数组中删除。我的问题是,对于时间序列的其他实例,这些 0 左右的值可能是合理的。仅供参考,这些值是海面温度测量值,如果测量值是在极地附近或极地地区进行的,则接近 0 的值是合理的。
我的问题是:有没有一种聪明的方法可以删除这些数据点?我曾考虑过使用 np.diff 尝试在数据中定位“步骤变化”,但我似乎没有得到任何结果。我还考虑过使用统计信息,例如围绕时间序列平均值的窗口,但是因为这些值是双峰的,所以这是行不通的;例如,在下面的情况下,平均值将在 9 左右——这并不代表真正的平均值(即,删除了坏数据)——因此围绕这个值的窗口会删除所有好的值。
array([[ 17.7804203 ],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 17.7335453 ],
[ 17.72670937],
[ 17.72670937],
[ 17.75502968],
[ 17.81459999],
[ 17.89565468],
[ 17.98159218],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 17.9210453 ]], dtype=float32)
【问题讨论】:
没有先验模型信息,您无能为力。而且这个模型信息没有正式说明。所以这个例子或多或少有 2 个峰值(我的措辞不好/不正式;想象一个数轴,在某个 x 轴值上有很多点;还有一些在其他 x 轴值)。总是这样吗?零附近的一是恒定的。总是这样吗?如是;也许使用一些一维聚类来获得这两个(平均值)值;然后检查两者的方差(使用来自聚类的类信息)并丢弃具有较低方差的类的所有值。 您基本上需要一维clustering 算法来对您的双峰(多峰)数据进行分类。我是DBSCAN 的特别粉丝,因为不需要事先知道存在多少组,并且能够在集群中识别主要成员和异常值。 感谢您的建议。我的一个想法是找到小于 0.1 的重复值(因为错误值在给定数组中似乎相同)。然后根据具体情况删除这些值。但这仍然不是一个完美的解决方案 与错误的接近零值在同一个数组中的似是而非的接近零值,还是在我们不必担心的其他数组中? 【参考方案1】:这里有一些 hacky 演示,试图向 this answer(SO 的集群专家)学习一些东西。
我改变了一些东西,不做任何保证:
标记方法 重要:我在这里偏离了他的基本理论(他的方法应该更好)! 我只是根据最近的中心进行标记(如 kmeans) argrelextrema 的比较器(对于没有唯一值的数据需要!) 使用启发式带宽选择(不设置常数!)这段代码使用kernel-density-estimation获得一个自动选择k的一维聚类。现在听起来,你不想总是使用k=2
,但这里更通用。
所以将它用于您的数据:
import numpy as np
from scipy.signal import argrelextrema
from scipy.spatial.distance import cdist
from sklearn.neighbors.kde import KernelDensity
import matplotlib.pyplot as plt
import matplotlib.cm as cm
x = np.array([[ 17.7804203 ],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 17.7335453 ],
[ 17.72670937],
[ 17.72670937],
[ 17.75502968],
[ 17.81459999],
[ 17.89565468],
[ 17.98159218],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 0.08901367],
[ 17.9210453 ],])
# [5.4],
# [5.41],
# [5.3],
# [5.35]])
np.random.shuffle(x) # just for demo
kde = KernelDensity(kernel='gaussian').fit(x) # bandwith heuristic
s = np.linspace(np.amin(x), np.amax(x))
e = kde.score_samples(s.reshape(-1,1))
ma = argrelextrema(e, np.greater_equal )[0]
s_ma = np.array([s[ma[i]] for i in range(len(ma))]) # cluster centers
n_clusters = len(s_ma) # n_clusters
# class labeling
Y = cdist(x, s_ma[np.newaxis].T)
labels = np.empty(len(x), dtype=int)
for x_ind in range(len(x)):
labels[x_ind] = np.argmin(Y[x_ind, :])
# plot classification
xs = np.arange(len(x))
colors = cm.rainbow(np.linspace(0, 1, n_clusters))
for label in range(n_clusters):
inds = np.where(labels == label)[0]
plt.scatter(xs[inds], x[inds], color=colors[label], s=40)
plt.show()
输出这个分类(记住:我置换了 x 值):
现在让我们在 5 左右添加 4 个新点(因为我很懒,所以将它们添加到最后,我使用了提到的排列)。只需取消注释代码中的这些行即可。
输出:
所以在第一种情况下,我们获得了两个集群,现在我们获得了三个(我发誓:n_clusters=3
尽管我的 matplotlib 代码以某种方式改变了颜色......)!
随意玩弄这个。您可能会在评论中使用我的方法,使用标签来提取类,计算方差并丢弃最低的类。但这当然取决于您的任务。
例如最后添加的这段代码:
# Calculate variance for each class
variances = np.array([np.var(x[np.where(labels == i)[0]]) for i in
range(n_clusters)])
print(np.hstack([variances[np.newaxis].T, s_ma[np.newaxis].T]))
会输出:
[[ 1.92592994e-34 8.90136700e-02] # variance | cluster_mean
[ 1.92500000e-03 5.20117896e+00]
[ 8.05793565e-03 1.79815922e+01]]
在您的情况下可能被解释为:扔掉 0 类(最小方差或一些阈值检查:使用 var
【讨论】:
感谢@sascha 的建议。我会玩弄你的想法,看看它对我有什么影响。以上是关于从 numpy 数组中删除错误但合理的值的主要内容,如果未能解决你的问题,请参考以下文章