我有一个基本的numpy值数组(称为timeseries,如下所示)。刚好超过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)
答案 0 :(得分:0)
这里有一些hacky演示,试图从this answer(SO的聚类专家)那里学到一些东西。
我改变了一些事情,不会给予任何保证:
此代码使用kernel-density-estimation 获取自动选择k的1d群集。现在听起来,你不要总是使用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< x)。