2017-10-12 4 views
0

J'ai un tableau de base numpy de base (appelé timeseries, et donné ci-dessous). Les valeurs juste au-dessus de 0 représentent généralement de mauvaises valeurs (idéalement, elles auraient été Nan'd mais hélas ...), et donc je veux les retirer du tableau. Mon problème est que pour d'autres instances de timeseries, ces valeurs autour de 0 pourraient être plausibles. Pour info, les valeurs sont des mesures de température de surface de la mer et si les mesures ont été prises à proximité ou dans des régions polaires, une valeur proche de 0 est plausible.Supprime les valeurs incorrectes mais plausibles du tableau numpy

Ma question est la suivante: y a-t-il une façon intelligente de supprimer ces points de données? J'ai pensé à utiliser np.diff pour essayer de localiser les «changements d'étapes» dans les données, mais je ne semble pas aller nulle part. J'ai aussi pensé à utiliser des statistiques, comme une fenêtre sur la valeur moyenne des timeseries, mais comme les valeurs sont bimodales, cela ne fonctionnera pas; par exemple, dans le cas ci-dessous, la valeur moyenne serait d'environ 9 - ce qui n'est pas représentatif de la vraie moyenne (c'est-à-dire avec les mauvaises données supprimées)) - une fenêtre autour de cette valeur supprimerait toutes les bonnes valeurs.

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

Sans informations de modèle a priori, il n'y a pas grand chose à faire. Et ce modèle-info n'est pas déclaré formellement. Donc cet exemple a plus ou moins 2 pics (ma formulation est mauvaise/informelle, imaginez une ligne numérique et il y a beaucoup de points à une valeur d'axe x, et d'autres à une autre valeur d'axe x). Est-ce toujours le cas? Celui autour de zéro est constant. Est-ce toujours le cas? Si oui; peut-être utiliser un cluster 1d pour obtenir ces 2 valeurs (moyennes); Vérifiez ensuite la variance des deux (en utilisant les informations de classe issues de la classification) et jetez toutes les valeurs de la classe avec la variance inférieure. – sascha

+0

vous avez essentiellement besoin d'un algorithme 1D [clustering] (http://scikit-learn.org/stable/modules/clustering.html) pour classer vos données bimodales (multimodales). Je suis un fan particulier de [DBSCAN] (http://scikit-learn.org/stable/modules/clustering.html#dbscan) pour ne pas avoir besoin de savoir combien de groupes existent à l'avance, et être capable de s'identifier dans un cluster les membres primaires et les valeurs aberrantes. – Aaron

+0

Merci pour les suggestions. Une idée que j'ai eu est de trouver des valeurs de répétition inférieures à 0,1 (car la mauvaise valeur semble être la même dans un tableau donné). Il suffit ensuite de supprimer ces valeurs au cas par cas. Mais ce n'est toujours pas une solution parfaite – InitialConditions

Répondre

0

Voici une démo aki, en essayant d'apprendre quelque chose de this answer (l'expert en cluster de SO).

j'ai changé certaines choses et ne donnera aucune garantie:

  • étiquetage méthode
    • importante: je suis dévier de sa théorie sous-jacente ici (son approche devrait être supérieure)!
    • je suis juste étiquetage selon le centre le plus proche (comme dans kmeans)
  • comparateur argrelextrema (nécessaire pour vos données qui n'a pas des valeurs uniques!)
  • en utilisant la bande passante-sélection heuristique (par pas la mise en constante!)

Ce code utilise kernel-density-estimationpour obtenir un 1d-cluster qui choisit automatiquement k. Maintenant, ça sonne, vous ne voulez pas toujours utiliser k=2, mais ceci est plus général.

donc l'utiliser pour vos données:

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() 

sortie cette classification (rappelez-vous: i permuté les valeurs x):

enter image description here

Maintenant, nous allons ajouter 4 nouveaux points autour de 5 (comme je suis paresseux et les a ajouté à la fin, j'ai utilisé la permutation mentionnée). Décommentez simplement ces lignes dans le code.

Sortie:

enter image description here

Ainsi, dans le premier cas, nous avons obtenu deux groupes, maintenant, nous avons trois (je jure: n_clusters=3 bien que mon code matplotlib change les couleurs en quelque sorte ...)!

N'hésitez pas à jouer avec cela. Vous pouvez utiliser mon approche dans le commentaire, en utilisant les étiquettes pour extraire les classes, calculer la variance et jeter la classe avec la plus basse. Mais cela dépend de votre tâche bien sûr.

Par exemple le code ajouté à la fin:

# 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])) 

génèrerait:

[[ 1.92592994e-34 8.90136700e-02] # variance | cluster_mean 
[ 1.92500000e-03 5.20117896e+00] 
[ 8.05793565e-03 1.79815922e+01]] 

qui dans votre cas pourrait être interprété comme: classe 0 jeter loin (variance minimale ou une thresholding- vérifier: supprimer tous avec var < x).

+0

Merci @sascha pour la suggestion. Je vais jouer avec votre idée et voir où ça me mène. – InitialConditions