[PYTHON] Standardiser la distribution non normale avec un score Z robuste

La normalisation min-max et la normalisation du score Z (standardisation) sont souvent utilisées pour la normalisation / normalisation. Cette fois, j'ai essayé le score Z robuste et je l'ai comparé à la normalisation ci-dessus.

min-max normalization La normalisation min-max est une méthode pour que les données aient une valeur minimale de 0 et une valeur maximale de 1, et se normalise avec la formule suivante.

x' = \frac{x-min(x)}{max(x)-min(x)}

En python, vous pouvez calculer avec minmax_scale ou MinMaxScaler dans sklearn.preprocessing. Cette normalisation suppose que la distribution des données est une ** distribution uniforme **.

Z-score Normalization(Standardization) La normalisation du score Z est une méthode pour rendre la moyenne des données 0 et la distribution 1 et la normaliser avec la formule suivante. Cette valeur est appelée ** Z-score **. * Μ * représente la moyenne et * σ * représente l'écart type.

x' = \frac{x-\mu}{\sigma}

En python, vous pouvez calculer avec scale ou StandardScaler de sklearn.preprocessing. Cette normalisation suppose que la distribution des données est une ** distribution normale **.

Que faire si ce n'est ni uniforme ni normal?

Dans les données réelles, ce n'était souvent ni une distribution uniforme ni normale, donc lorsque j'ai cherché ce qu'il fallait faire, j'ai trouvé le score Z robuste dans l'article suivant.

Score z robuste: médiane et quadrants, standardisation avec distribution non normale et valeurs aberrantes (Memo) Exclusion des valeurs aberrantes à l'aide du score z robuste

Ci-dessous, je l'ai essayé avec Python.

Implémentation d'un score Z robuste

Pour plus d'informations sur le score Z robuste, veuillez lire l'article ci-dessus. Voici une brève description et mise en œuvre.

Le score Z suppose une distribution normale, mais pour l'appliquer à une distribution non normale, remplacez d'abord la moyenne * μ * par la médiane et l'écart-type * σ * par la plage de quadrants (IQR).

x' = \frac{x-median(x)}{IQR}

Cette formule peut être calculée avec robust_scale ou RobustScaler dans sklearn.preprocessing.

De plus, il le rend compatible avec les distributions normales standard. L'IQR correspondant à la distribution normale standard est appelé la plage de quadrants normalisés (NIQR), qui est l'IQR divisé par F (0,75) --F (0,25) = 1,3489. (F (x) est l'inverse de la fonction de distribution cumulative)

NIQR = \frac{IQR}{1.3489}

Le score Z robuste est le dénominateur de la formule ci-dessus remplacée de IQR par NIQR.

robust Z score = \frac{x-median(x)}{NIQR}

Si elle est mise en œuvre sur la base de ce qui précède, la fonction sera la suivante.


def robust_z(x):
    from sklearn.preprocessing import robust_scale
    from scipy.stats import norm

    coefficient = norm.ppf(0.75)-norm.ppf(0.25)
    robust_z_score = robust_scale(x)*coefficient

    return robust_z_score

Comparaison de trois normalisations

Je voudrais comparer les trois normalisations qui sont sorties jusqu'à présent. Préparez d'abord les données. Je veux des données qui ne sont ni uniformes ni normales, j'ai donc préparé des données qui combinent une distribution uniforme et normale.

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.stats import chisquare, shapiro, norm
from sklearn.preprocessing import minmax_scale, scale, robust_scale

np.random.seed(2020)

#Données combinant une distribution uniforme et une distribution normale.
data = np.concatenate((np.random.uniform(low=5.0, high=10.0, size=100),
                       np.random.normal(loc=5.0, scale=1.0, size=100)))

#Dessinez un histogramme.
fig, axes = plt.subplots()
axes.hist(data)
axes.set_title("Histogram of data")
fig.show()

row.png

Test pour confirmer que ces données ne sont pas uniformément distribuées et ne sont pas normalement distribuées. L'uniformité a été confirmée par le test du chi carré et la normalité a été confirmée par le (test de Shapiro-Wilck).

#Calculez la distribution de fréquence.
hist_data, _ = np.histogram(data, bins="auto")

#Test d'uniformité (test du chi carré)
_, chisquare_p = chisquare(hist_data)
print("Valeur P du test d'uniformité (test du chi carré): {}".format(chisquare_p))

#Test de normalité (test de Shapiro-Wilk)
_, shapiro_p = shapiro(data)
print("Valeur P du test de normalité (test de Shapiro-Wilck): {}".format(shapiro_p))

Les résultats sont les suivants. Les deux ont une valeur P inférieure à 0,05, on peut donc dire qu'ils ne sont ni uniformes ni normaux.

Valeur P du test d'uniformité (test du chi carré): 3.8086163670115985e-09
Valeur P du test de normalité (test de Shapiro-Wilck): 8.850588528730441e-06

Utilisez ces données pour calculer la normalisation min-max, le Z-score et le Z-score robuste et les comparer.

#Normaliser par chaque méthode et placez-le dans le bloc de données.
score_df = pd.DataFrame(data=np.array([minmax_scale(data), scale(data), robust_z(data)]).T,
                        columns=["min-max", "Z-score", "robust Z-score"])


#Créer un graphique
fig, axs = plt.subplots(ncols=3, constrained_layout=True)

#réglage de la largeur de l'axe x
xrange = {"min-max":(0,1),
          "Z-score":(-2.5,2.5),
          "robust Z-score":(-2.5,2.5)}

#Dessin de chaque histogramme
for i, score_name in enumerate(score_df.columns):
    
    axs[i].hist(score_df[score_name])
    axs[i].set_title(score_name)
    axs[i].set_xlim(xrange[score_name])

fig.show()

Le résultat est présenté ci-dessous. Il n'y a pas beaucoup de différence. Cela peut faire une différence en fonction de la distribution des données.

score.png

Comparer avec des données qui ont des valeurs aberrantes

En premier lieu, «robuste» dans le score Z robuste signifie qu'il est robuste contre les ** valeurs aberrantes **. Le score Z robuste est également utilisé pour la détection des valeurs aberrantes. Par conséquent, je voudrais mettre une valeur aberrante dans les données et comparer. Pour faciliter la comparaison, essayez de saisir un grand nombre de valeurs aberrantes extrêmes.

#Combinez les valeurs aberrantes (distribution uniforme) dans les données.
outier = np.concatenate((data,
                         np.random.uniform(low=19.0, high=20.0, size=15)))

#Normaliser par chaque méthode et placez-le dans le bloc de données.
outlier_df = pd.DataFrame(data=np.array([minmax_scale(outier), scale(outier), robust_z(outier)]).T,
                          columns=["min-max", "Z-score", "robust Z-score"])

#Combinez des trames de données sans valeurs aberrantes et avec des valeurs aberrantes.
concat_df = pd.concat([score_df, outlier_df],
               axis=1,
               keys=['without outlier', 'with outlier'])


#Créer un graphique
fig, axs = plt.subplots(nrows=2, ncols=3, constrained_layout=True)

#réglage de la largeur de l'axe x
xrange = {"min-max":(0, 1),
          "Z-score":(-6.5, 6.5),
          "robust Z-score":(-6.5, 6.5)}

#Dessiner un histogramme
for i, (data_name, score_name) in enumerate(concat_df.columns):
    row, col = divmod(i, 3)
    axs[row, col].hist(concat_df[(data_name, score_name)])
    axs[row, col].set_xlim(xrange[score_name])
    
    title = "\n".join([data_name, score_name])    
    axs[row, col].set_title(title)       
    
plt.show()

Le résultat est présenté ci-dessous. Le haut est lorsqu'il n'y a pas de valeur aberrante et le bas est lorsqu'il y a une valeur aberrante. La normalisation min-max est très sensible aux valeurs aberrantes. Le score Z est également affecté par les valeurs aberrantes et est très différent de l'absence de valeurs aberrantes. Le score Z robuste est le moins affecté par les valeurs aberrantes et est relativement similaire à l'absence de valeurs aberrantes.

outlier.png

finalement

Le score Z robuste donne le même résultat que le score Z lorsque les données sont normalement distribuées, je pense donc à utiliser un score Z robuste en cas de doute. En particulier, j'ai estimé qu'un score Z robuste est efficace lorsque je souhaite également utiliser des valeurs aberrantes.

Recommended Posts

Standardiser la distribution non normale avec un score Z robuste
3. Distribution normale avec un réseau neuronal!
Standardisez par groupe avec les pandas
Régression linéaire robuste avec scikit-learn