[PYTHON] Identifiez les valeurs aberrantes avec le classificateur de forêt aléatoire de scikit-learn

En utilisant RandomForestClassifier de scikit-learn, vous pouvez résoudre le problème de classification dans une forêt aléatoire. En tant que fonctionnalité de Random Forest, il est possible d'identifier les données aberrantes qui ont une valeur différente de la valeur d'attribut qui représente la classe à partir des données appartenant à la même classe. Puisque le scikit-learn officiel n'a pas de fonction pour calculer les valeurs aberrantes, cette fois j'ai créé un script qui génère des valeurs aberrantes. (Au fait, il peut être calculé avec R)

Pour trouver la valeur aberrante, utilisez apply dans la méthode RandomForestClassifier de scicit-learn. Il s'agit d'une méthode qui renvoie l'index de feuille indiquant dans quelle feuille chaque donnée est contenue lorsque les données d'entrée du lot sont fournies à chaque arbre de décision créé par l'algorithme de forêt aléatoire.

Screenshot from 2017-01-22 21-28-40.png

À propos du code

Afin de trouver la valeur de l'écart, il est d'abord nécessaire de trouver le degré de proximité de chaque donnée.

Calcul du degré d'approximation

Le degré de proximité de chaque donnée est calculé à l'aide du tableau renvoyé par la méthode apply comme argument. La méthode apply renvoie un tableau bidimensionnel de [nombre d'échantillons, nombre d'arbres de décision].

A proximité, les données $ x_ {k} $ contenues dans la même feuille que les données $ x_ {n} $ sont comptées, et la somme est calculée en l'exécutant sur tous les arbres de détermination qui les ont créées. Enfin, le résultat est divisé par le nombre d'arbres de décision et normalisé pour obtenir le degré d'approximation des données $ x_ {n} $. Le résultat final est renvoyé sous la forme d'un tableau bidimensionnel de [Nombre d'échantillons, Nombre d'échantillons]. (Au fait, le tableau est une matrice diagonale)

def proximity(data):
  n_samples = np.zeros((len(data),len(data)))
  n_estimators = len(data[0])

  for e,est in enumerate(np.transpose(np.array(data))):
    for n,n_node in enumerate(est):
      for k,k_node in enumerate(est):
        if n_node == k_node:
          n_samples[n][k] += 1

  n_samples = 1.0 * np.array(n_samples) / n_estimators

  return n_samples

Calcul des valeurs aberrantes

Après avoir trouvé le degré d'approximation, trouvez la valeur aberrante. Un tableau d'étiquettes correctes est utilisé comme argument pour calculer les valeurs aberrantes dans la même classe. Le flux de traitement est le suivant.

--Calculer la valeur moyenne du degré de proximité dans la classe

--Calculer les valeurs aberrantes de chaque donnée

--Calculer la valeur médiane et l'écart absolu médian (MAD) des valeurs aberrantes de chaque classe

--Normaliser les valeurs aberrantes de chaque donnée avec les écarts absolus médians et médians

C'est tout ce que vous devez faire, et vous pouvez facilement l'écrire en utilisant numpy. Si l'instruction for est également incluse, la vitesse peut être augmentée.

Utilisez également XGBoost en utilisant l'encapsuleur scikit-learn de XGBoost. Il est également possible de spécifier les valeurs aberrantes.

À propos, dans la normalisation des valeurs aberrantes, la valeur médiane et la valeur MAD sont utilisées à la place de la moyenne et de l'écart type, car il s'agit d'une statistique (robuste) qui n'est pas facilement affectée par les valeurs aberrantes.

def outlier(data, label):
  N = len(label)
  pbar = [0] * N
  data = np.square(data)

  #Trouvez la valeur moyenne du degré de proximité dans la classe
  for n,n_prox2 in enumerate(data):
    for k,k_prox2 in enumerate(n_prox2):
      if label[n] == label[k]:
        pbar[n] += k_prox2
    if pbar[n] == 0.0:
      pbar[n] = 1.0e-32

  #Trouvez la valeur aberrante
  out = N / np.array(pbar)

  #Trouvez les valeurs aberrantes médianes pour chaque classe
  meds = {}
  for n,l in enumerate(label):
    if l not in meds.keys():
      meds[l] = []
    meds[l].append(out[n])
  
  label_uniq = list(set(label))
  med_uniq = {} #La médiane réelle de chaque classe entre dans cette variable
  for l in label_uniq:
    med_uniq[l] = np.median(meds[l])
  
  #Écart absolu central des valeurs aberrantes pour chaque classe(MAD)Cherchant
  mads = {}
  for n,l in enumerate(label):
    if l not in mads.keys():
      mads[l] = []
    mads[l].append(np.abs(out[n] - med_uniq[l]))

  mad_uniq = {} #Le MAD réel de chaque classe entre dans cette variable
  for l in label_uniq:
    mad_uniq[l] = np.median(mads[l])

  #Normaliser les valeurs aberrantes de chaque donnée avec la valeur médiane, MAD
  outlier = [0] * N
  for n,l in enumerate(label):
    if mad_uniq[l] == 0.0:
      outlier[n] = out[n] - med_uniq[l]
    else:
      outlier[n] = (out[n] - med_uniq[l]) / mad_uniq[l]

  return outlier

échantillon

En utilisant la fonction ci-dessus, j'ai essayé d'identifier la valeur aberrante de l'iris dans les exemples de données de sklearn. L'exemple de code pour générer l'image de ce résultat est illustré ci-dessous.

out.png

code

outlier.py


from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
import numpy as np
import matplotlib.pyplot as plt

def proximity(data):
  n_samples = np.zeros((len(data),len(data)))
  n_estimators = len(data[0])
  for e,est in enumerate(np.transpose(np.array(data))):
    for n,n_node in enumerate(est):
      for k,k_node in enumerate(est):
        if n_node == k_node:
          n_samples[n][k] += 1
  n_samples = 1.0 * np.array(n_samples) / n_estimators
  return n_samples

def outlier(data, label):
  N = len(label)
  pbar = [0] * N
  data = np.square(data)

  #Trouvez la valeur moyenne du degré de proximité dans la classe
  for n,n_prox2 in enumerate(data):
    for k,k_prox2 in enumerate(n_prox2):
      if label[n] == label[k]:
        pbar[n] += k_prox2
    if pbar[n] == 0.0:
      pbar[n] = 1.0e-32

  #Trouvez la valeur aberrante
  out = N / np.array(pbar)

  #Trouvez les valeurs aberrantes médianes pour chaque classe
  meds = {}
  for n,l in enumerate(label):
    if l not in meds.keys():
      meds[l] = []
    meds[l].append(out[n])
  
  label_uniq = list(set(label))
  med_uniq = {} #La médiane réelle de chaque classe entre dans cette variable
  for l in label_uniq:
    med_uniq[l] = np.median(meds[l])
  
  #Écart absolu central des valeurs aberrantes pour chaque classe(MAD)Cherchant
  mads = {}
  for n,l in enumerate(label):
    if l not in mads.keys():
      mads[l] = []
    mads[l].append(np.abs(out[n] - med_uniq[l]))

  mad_uniq = {} #Le MAD réel de chaque classe entre dans cette variable
  for l in label_uniq:
    mad_uniq[l] = np.median(mads[l])

  #Normaliser les valeurs aberrantes de chaque donnée avec la valeur médiane, MAD
  outlier = [0] * N
  for n,l in enumerate(label):
    if mad_uniq[l] == 0.0:
      outlier[n] = out[n] - med_uniq[l]
    else:
      outlier[n] = (out[n] - med_uniq[l]) / mad_uniq[l]

  return outlier


if __name__ == '__main__':
  iris = load_iris()
  X = iris.data
  y = iris.target
  div = 50
  best_oob = len(y)

  for i in range(20):
    rf = RandomForestClassifier(max_depth=5,n_estimators=10,oob_score=True)
    rf.fit(X, y)
    if best_oob > rf.oob_score:
      app = rf.apply(X)
  
  prx = proximity(app)
  out = outlier(prx,y)
  
  fig = plt.figure(figsize=[7,4])
  ax = fig.add_subplot(1,1,1)

  ax.scatter(np.arange(div),out[:div], c="r",marker='o', label='class 0')
  ax.scatter(np.arange(div,div*2),out[div:div*2], c="b",marker='^', label='class 1')
  ax.scatter(np.arange(div*2,div*3),out[div*2:], c="g",marker='s', label='class 2')
  
  ax.set_ylabel('outlier') 
  ax.legend(loc="best")
  fig.savefig("out.png ")
  

référence

Recommended Posts

Identifiez les valeurs aberrantes avec le classificateur de forêt aléatoire de scikit-learn
Regrouper les écoles représentatives à l'été 2016 avec scikit-learn
Remplissez les valeurs manquantes avec Scikit-learn impute
Isomap avec Scikit-learn
DBSCAN avec scikit-learn
Clustering avec scikit-learn (1)
Clustering avec scikit-learn (2)
PCA avec Scikit-learn
kmeans ++ avec scikit-learn
Validation croisée avec scikit-learn
SVM multi-classes avec scikit-learn
Clustering avec scikit-learn + DBSCAN
Apprentissage Scikit-Learn avec la chimioinfomatique
Remplissez les valeurs aberrantes avec NaN en fonction des quadrants dans Pandas
DBSCAN (clustering) avec scikit-learn
(Suite) Essayez d'autres fonctions de distance avec kmeans dans Scikit-learn
Installez scikit.learn avec pip
Calculer tf-idf avec scikit-learn
Exploitez LibreOffice avec Python
Grattage avec chromedriver en python
Réseau de neurones avec Python (scikit-learn)
Gérer les sons en Python
Grattage avec du sélénium en Python
Traitement parallèle avec Parallel de scikit-learn
Grattage avec Tor en Python
Tweet avec image en Python
Combiné avec ordinal en Python
[Python] Régression linéaire avec scicit-learn
Régression linéaire robuste avec scikit-learn