[PYTHON] Détection de valeur anormale par apprentissage non supervisé: distance Maharanobis (implémentation)

À propos, dans le prolongement de la théorie précédente, cette fois, je vais réellement implémenter la distance Maharanobis avec python. Cliquez ici pour la théorie précédente Détection de valeur anormale par apprentissage non supervisé: distance Maharanobis (théorie)

introduction

La bibliothèque scikit-learn de Python implémente une fonction qui calcule la distance Maharanobis. Robust covariance estimation and Mahalanobis distances relevance

Cependant, même si j'écris un article qui dit "Je vais exécuter ce code!", Ce ne sera qu'une traduction en anglais. Cette fois, je vais l'implémenter moi-même et voir comment le processus de calcul est au programme.

Enfin, après avoir connecté tous les codes, le but est de pouvoir calculer la distance par vous-même.

environnement

Supposons également que le fichier traité dans cette expérience ait le format suivant. Supposons que Column est le numéro de la machine et Row le score de la machine. (Il semble qu'Ichamon volera dans la direction opposée, mais bien sûr l'inverse n'est pas un problème.)

test.csv

1 2 3 4 5 6 7 8 9 10
a 0 6 7 2 3 3 1 0 0 1
b 1 1 11 6 0 2 1 4 1 2
c 2 12 32 5 0 1 3 4 1 1
d 3 3 7 3 2 2 2 1 2 5
e 4 6 6 3 5 1 1 1 1 3
f 5 7 9 5 0 2 2 1 1 2

Avec ce format, le score semble extrêmement élevé uniquement pour le troisième numéro de machine.

Avec la distance Maharanobis, vous pouvez définir vous-même un certain seuil et juger un enregistrement dont la valeur dépasse le seuil comme une valeur anormale. Notez que vous devez régler vous-même le seuil à chaque fois. </ b> Cette fois, nous allons visualiser les données </ b> anormales en les montrant sous forme de graphique sans fixer de seuil de ce côté.

la mise en oeuvre

import La fonction à importer est la suivante.

  • numpy
  • scipy
  • pandas
  • matplotlib
  • pylab

Ces procédures d'installation sont omises cette fois. Pour l'installation, il est préférable d'utiliser pip ou easy_install.

# -*- coding: utf-8 -*-
import numpy as np
import scipy as sc
from scipy import linalg
from scipy import spatial
import scipy.spatial.distance
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.font_manager
import pylab

Définition variable

Cette fois, il y a 6 lignes pour ROW et 10 lignes pour COLUMN. De plus, comme le test.csv mentionné précédemment est lu, lisez-le également.

ROW = 10
COLUMN = 6
csv = pd.read_csv('test.csv')

Dans le même temps, les variables à gérer dans le futur sont également définies ici en premier.

# row:ligne,column:Colonne,ave:moyenne,vcm:分散共分散ligneColonne
row = []
column = []
ave = [0.0 for i in range(ROW)]
vcm = np.zeros((COLUMN, ROW, ROW))
diff = np.zeros((1, ROW))
mahal = np.zeros(COLUMN)
tmp = np.zeros(ROW)

Supprimer les valeurs manquantes

Dans les données générales, il n'y a pas beaucoup de cas où toutes les données sont remplies comme ceci test.csv. Dans un tel cas, je supprime la valeur manquante comme suit.

#Supprimer les données manquantes
# axis =1 supprime les colonnes avec des valeurs manquantes
trans_data = csv.dropna(axis=1)
print(trans_data)

Si vous imprimez ceci,

  Unnamed: 0  1   2   3  4  5  6  7  8  9  10
0          a  0   6   7  2  3  3  1  0  0   1
1          b  1   1  11  6  0  2  1  4  1   2
2          c  2  12  32  5  0  1  3  4  1   1
3          d  3   3   7  3  2  2  2  1  2   5
4          e  4   6   6  3  5  1  1  1  1   3
5          f  5   7   9  5  0  2  2  1  1   2

Ce sera sorti comme ça.

De plus, les données formatées de cette manière sont converties dans un format de liste et stockées dans la ligne et la colonne déclarées précédemment.

#trans en ligne_Concaténer des éléments de données au format liste
for i in range(ROW):
    row.append(list(trans_data.ix[i]))
print(row)

#Concaténer les colonnes
for i in range(1, COLUMN+1):
    column.append(list(trans_data.ix[:, i]))
print(column)
#résultat du calcul de ligne

[['a', 0, 6, 7, 2, 3, 3, 1, 0, 0, 1], ['b', 1, 1, 11, 6, 0, 2, 1, 4, 1, 2], ['c', 2, 12, 32, 5, 0, 1, 3, 4, 1, 1], ['d', 3, 3, 7, 3, 2, 2, 2, 1, 2, 5], ['e', 4, 6, 6, 3, 5, 1, 1, 1, 1, 3], ['f', 5, 7, 9, 5, 0, 2, 2, 1, 1, 2]]

#résultat du calcul de la colonne
[[0, 1, 2, 3, 4, 5], [6, 1, 12, 3, 6, 7], [7, 11, 32, 7, 6, 9], [2, 6, 5, 3, 3, 5], [3, 0, 0, 2, 5, 0], [3, 2, 1, 2, 1, 2], [1, 1, 3, 2, 1, 2], [0, 4, 4, 1, 1, 1], [0, 1, 1, 2, 1, 1], [1, 2, 1, 5, 3, 2]]

Il s'est avéré qu'il est stocké ligne par ligne sous forme de tableau multidimensionnel.

Calcul du vecteur de valeur moyenne

J'ai expliqué que le vecteur de valeur moyenne peut être exprimé par la formule suivante.

{ 
  μ = \frac{1}{m} \sum_{i=1}^m x_i
}

Si cela est réellement écrit en python, ce sera comme suit.

#Calcul de la valeur moyenne
for i in range(ROW):
    #Une technique appelée tranchage
    ave[i] = np.average(row[i][1:len(row[i])])
print(ave)
  Unnamed: 0  1   2   3  4  5  6  7  8  9  10
0          a  0   6   7  2  3  3  1  0  0   1
1          b  1   1  11  6  0  2  1  4  1   2
2          c  2  12  32  5  0  1  3  4  1   1
3          d  3   3   7  3  2  2  2  1  2   5
4          e  4   6   6  3  5  1  1  1  1   3
5          f  5   7   9  5  0  2  2  1  1   2
[2.2999999999999998, 2.8999999999999999, 6.0999999999999996, 3.0, 3.1000000000000001, 3.3999999999999999]

Des valeurs numériques sont affichées pour la ligne, telles que la moyenne des valeurs de la ligne a et la moyenne des valeurs de la ligne b.

Calcul de la matrice distribuée co-distribuée

Comme je l'ai mentionné dans l'article précédent, la matrice de co-distribution de distribution est également

\sum_{} = \frac{1}{m}\sum_{i=1}^m (x_i - μ)(x_i - μ)^{\mathrm{T}}

Il peut être calculé de cette manière.

#Puisqu'il utilise la méthode de Numpy, array()Converti la liste avec.
column = np.array([column])
ave = np.array(ave)

#Trouvez la matrice distribuée co-distribuée
# np.swapaxes()Vous pouvez convertir l'axe avec.
for i in range(COLUMN):
    diff = (column[0][i] - ave)
    diff = np.array([diff])
    vcm[i] = (diff * np.swapaxes(diff, 0, 1)) / COLUMN

print(vcm)

La partie diff est la différence, et mathématiquement

 {(x_i - μ)}

Il pointe vers cette partie. Calculez cette différence pour chaque colonne et trouvez la matrice pour chaque colonne.

  Unnamed: 0  1   2   3  4  5  6  7  8  9  10
0          a  0   6   7  2  3  3  1  0  0   1
1          b  1   1  11  6  0  2  1  4  1   2
2          c  2  12  32  5  0  1  3  4  1   1
3          d  3   3   7  3  2  2  2  1  2   5
4          e  4   6   6  3  5  1  1  1  1   3
5          f  5   7   9  5  0  2  2  1  1   2
#colonne vcm matrice 1ère colonne
[[[  5.29000000e-01   4.37000000e-01   9.43000000e-01  -0.00000000e+00
    -2.07000000e-01  -3.68000000e-01]
  [  4.37000000e-01   3.61000000e-01   7.79000000e-01  -0.00000000e+00
    -1.71000000e-01  -3.04000000e-01]
  [  9.43000000e-01   7.79000000e-01   1.68100000e+00  -0.00000000e+00
    -3.69000000e-01  -6.56000000e-01]
  [ -0.00000000e+00  -0.00000000e+00  -0.00000000e+00   0.00000000e+00
     0.00000000e+00   0.00000000e+00]
  [ -2.07000000e-01  -1.71000000e-01  -3.69000000e-01   0.00000000e+00
     8.10000000e-02   1.44000000e-01]
  [ -3.68000000e-01  -3.04000000e-01  -6.56000000e-01   0.00000000e+00
     1.44000000e-01   2.56000000e-01]]

#vcm deuxième rangée
 [[  1.36900000e+00  -7.03000000e-01   2.18300000e+00   0.00000000e+00
     1.07300000e+00   1.33200000e+00]
  [ -7.03000000e-01   3.61000000e-01  -1.12100000e+00  -0.00000000e+00
    -5.51000000e-01  -6.84000000e-01]
  [  2.18300000e+00  -1.12100000e+00   3.48100000e+00   0.00000000e+00
     1.71100000e+00   2.12400000e+00]
  [  0.00000000e+00  -0.00000000e+00   0.00000000e+00   0.00000000e+00
     0.00000000e+00   0.00000000e+00]
  [  1.07300000e+00  -5.51000000e-01   1.71100000e+00   0.00000000e+00
     8.41000000e-01   1.04400000e+00]
  [  1.33200000e+00  -6.84000000e-01   2.12400000e+00   0.00000000e+00
     1.04400000e+00   1.29600000e+00]]

…

#vcm 10ème rangée
[[  1.69000000e-01   1.17000000e-01   6.63000000e-01  -2.60000000e-01
     1.30000000e-02   1.82000000e-01]
  [  1.17000000e-01   8.10000000e-02   4.59000000e-01  -1.80000000e-01
     9.00000000e-03   1.26000000e-01]
  [  6.63000000e-01   4.59000000e-01   2.60100000e+00  -1.02000000e+00
     5.10000000e-02   7.14000000e-01]
  [ -2.60000000e-01  -1.80000000e-01  -1.02000000e+00   4.00000000e-01
    -2.00000000e-02  -2.80000000e-01]
  [  1.30000000e-02   9.00000000e-03   5.10000000e-02  -2.00000000e-02
     1.00000000e-03   1.40000000e-02]
  [  1.82000000e-01   1.26000000e-01   7.14000000e-01  -2.80000000e-01
     1.40000000e-02   1.96000000e-01]]]

Trouver la distance Maharanobis

La distance Maharanobis peut être calculée à l'aide de la formule suivante.

  θ < \sqrt{(x_i - μ) ^{\mathrm{T}}\sum{}^{-1} (x_i - μ) }
#Trouver la distance de mahalanobis
for i in range(COLUMN):
    #Générez une matrice inverse générale et multipliez-la par un prix de rotation pour faciliter le calcul.
    vcm[i] = sc.linalg.pinv(vcm[i])
    vcm[i] = vcm[i].transpose()
    vcm[i] = np.identity(ROW)
    #Génération de vecteur de différence
    diff = (column[0][i] - ave)
    for j in range(ROW):
        tmp[j] = np.dot(diff, vcm[i][j])
    mahal[i] = np.dot(tmp, diff)
#Distance de Maharanobis
[  5.39258751   8.5720476   28.53559181   3.67151195   7.89176786
   5.88897275   4.72016949   5.00799361   6.7882251    5.8719673 ]

Vous pouvez maintenant calculer la distance pour chaque colonne d'enregistrements!

En fait, tracer

Tracons la distance de Maharanobis ainsi obtenue sur un graphe.

plot = pylab.arange(0.0, ROW, 1.0)
mahal = np.sqrt(mahal)

print("Distance de Maharanobis")
print(mahal)
plt.bar(range(COLUMN),mahal)
plt.title("")
plt.xlabel("x")
plt.ylabel("y")
plt.savefig("plot1.png ")

plot1.png

  Unnamed: 0  1   2   3  4  5  6  7  8  9  10
0          a  0   6   7  2  3  3  1  0  0   1
1          b  1   1  11  6  0  2  1  4  1   2
2          c  2  12  32  5  0  1  3  4  1   1
3          d  3   3   7  3  2  2  2  1  2   5
4          e  4   6   6  3  5  1  1  1  1   3
5          f  5   7   9  5  0  2  2  1  1   2
#Distance de Maharanobis
[  5.39258751   8.5720476   28.53559181   3.67151195   7.89176786
   5.88897275   4.72016949   5.00799361   6.7882251    5.8719673 ]

Quand je l'ai tracé, j'ai trouvé que les enregistrements de la troisième colonne étaient très éloignés des autres éléments. Vous pouvez maintenant voir que les données sont dans le désordre visuellement.

en conclusion

Qu'as-tu pensé. Cette fois, sur la base de la Théorie, j'ai en fait calculé la distance de Maharanobis en utilisant python. Le programme utilisé cette fois a été publié sur GitHub gist.

Comme il a été implémenté en version intégrale, il peut y avoir une faille dans le code, donc si vous avez besoin de calculs précis, [estimation de covariance robuste et pertinence des distances de Mahalanobis](http://scikit-learn.org/stable/auto_examples/ covariance / plot_mahalanobis_distances.html) Nous vous recommandons vivement d'utiliser la bibliothèque en référence à ce document.

Nous vous serions reconnaissants si vous pouviez nous contacter si vous avez des lacunes ou des erreurs.

Recommended Posts