从numpy数组

时间:2017-10-12 15:31:51

标签: python arrays numpy filter

我有一个基本的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)

1 个答案:

答案 0 :(得分:0)

这里有一些hacky演示,试图从this answer(SO的聚类专家)那里学到一些东西。

我改变了一些事情,不会给予任何保证:

  • 标记法
    • 很重要:我在这里偏离他的基础理论(他的方法应该更优秀)!
    • 我只是根据最近的中心标记(如在kmeans中)
  • argrelextrema的比较器(对于没有唯一值的数据需要!)
  • 使用启发式带宽选择(不设置常量!)

此代码使用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值):

enter image description here

现在让我们在5左右添加4个新点(因为我很懒,并将它们添加到最后,我使用了上面提到的排列)。只需在代码中取消注释这些行。

输出:

enter image description here

所以在第一种情况下,我们获得了两个集群,现在我们得到了三个集群(我发誓: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)。