web-dev-qa-db-fra.com

Pandas - Calcule le z-score pour toutes les colonnes

J'ai une base de données contenant une seule colonne d'identifiants et toutes les autres colonnes sont des valeurs numériques pour lesquelles je souhaite calculer des scores z. En voici une sous-section:

ID      Age    BMI    Risk Factor
PT 6    48     19.3    4
PT 8    43     20.9    NaN
PT 2    39     18.1    3
PT 9    41     19.5    NaN

Certaines de mes colonnes contiennent des valeurs de NaN que je ne souhaite pas inclure dans les calculs du z-score. Je compte donc utiliser une solution proposée pour cette question: comment zscore normaliser pandas colonne avec nans?

df['zscore'] = (df.a - df.a.mean())/df.a.std(ddof=0)

Je suis intéressé par l’application de cette solution à toutes mes colonnes, à l’exception de la colonne ID, afin de générer une nouvelle trame de données que je peux enregistrer en tant que fichier Excel à l’aide

df2.to_Excel("Z-Scores.xlsx")

Donc en gros; Comment puis-je calculer les scores z pour chaque colonne (en ignorant les valeurs NaN) et tout insérer dans une nouvelle trame de données?

SIDENOTE: il y a un concept dans pandas appelé "indexation") qui m'intimide parce que je ne le comprends pas bien. Si l'indexation est une partie cruciale de la résolution de ce problème, veuillez rendre muette votre explication de l'indexation .

31
Slavatron

Construisez une liste à partir des colonnes et supprimez la colonne pour laquelle vous ne voulez pas calculer le score Z pour:

In [66]:
cols = list(df.columns)
cols.remove('ID')
df[cols]

Out[66]:
   Age  BMI  Risk  Factor
0    6   48  19.3       4
1    8   43  20.9     NaN
2    2   39  18.1       3
3    9   41  19.5     NaN
In [68]:
# now iterate over the remaining columns and create a new zscore column
for col in cols:
    col_zscore = col + '_zscore'
    df[col_zscore] = (df[col] - df[col].mean())/df[col].std(ddof=0)
df
Out[68]:
   ID  Age  BMI  Risk  Factor  Age_zscore  BMI_zscore  Risk_zscore  \
0  PT    6   48  19.3       4   -0.093250    1.569614    -0.150946   
1  PT    8   43  20.9     NaN    0.652753    0.074744     1.459148   
2  PT    2   39  18.1       3   -1.585258   -1.121153    -1.358517   
3  PT    9   41  19.5     NaN    1.025755   -0.523205     0.050315   

   Factor_zscore  
0              1  
1            NaN  
2             -1  
3            NaN  
54
EdChum

Utilisation de la fonction zscore de Scipy :

df = pd.DataFrame(np.random.randint(100, 200, size=(5, 3)), columns=['A', 'B', 'C'])
df

|    |   A |   B |   C |
|---:|----:|----:|----:|
|  0 | 163 | 163 | 159 |
|  1 | 120 | 153 | 181 |
|  2 | 130 | 199 | 108 |
|  3 | 108 | 188 | 157 |
|  4 | 109 | 171 | 119 |

from scipy.stats import zscore
df.apply(zscore)

|    |         A |         B |         C |
|---:|----------:|----------:|----------:|
|  0 |  1.83447  | -0.708023 |  0.523362 |
|  1 | -0.297482 | -1.30804  |  1.3342   |
|  2 |  0.198321 |  1.45205  | -1.35632  |
|  3 | -0.892446 |  0.792025 |  0.449649 |
|  4 | -0.842866 | -0.228007 | -0.950897 |

Si toutes les colonnes de votre cadre de données ne sont pas numériques, vous pouvez appliquer la fonction Z-score uniquement aux colonnes numériques à l'aide de la commande select_dtypes une fonction:

# Note that `select_dtypes` returns a data frame. We are selecting only the columns
numeric_cols = df.select_dtypes(include=[np.number]).columns
df[numeric_cols].apply(zscore)

|    |         A |         B |         C |
|---:|----------:|----------:|----------:|
|  0 |  1.83447  | -0.708023 |  0.523362 |
|  1 | -0.297482 | -1.30804  |  1.3342   |
|  2 |  0.198321 |  1.45205  | -1.35632  |
|  3 | -0.892446 |  0.792025 |  0.449649 |
|  4 | -0.842866 | -0.228007 | -0.950897 |
40
Manuel

Si vous souhaitez calculer le score z pour toutes les colonnes, vous pouvez simplement utiliser les éléments suivants:

df_zscore = (df - df.mean())/df.std()
9
Joe Bathelt

Voici une autre façon d’obtenir Zscore en utilisant une fonction personnalisée:

In [6]: import pandas as pd; import numpy as np

In [7]: np.random.seed(0) # Fixes the random seed

In [8]: df = pd.DataFrame(np.random.randn(5,3), columns=["randomA", "randomB","randomC"])

In [9]: df # watch output of dataframe
Out[9]:
    randomA   randomB   randomC
0  1.764052  0.400157  0.978738
1  2.240893  1.867558 -0.977278
2  0.950088 -0.151357 -0.103219
3  0.410599  0.144044  1.454274
4  0.761038  0.121675  0.443863

## Create custom function to compute Zscore 
In [10]: def z_score(df):
   ....:         df.columns = [x + "_zscore" for x in df.columns.tolist()]
   ....:         return ((df - df.mean())/df.std(ddof=0))
   ....:

## make sure you filter or select columns of interest before passing dataframe to function
In [11]: z_score(df) # compute Zscore
Out[11]:
   randomA_zscore  randomB_zscore  randomC_zscore
0        0.798350       -0.106335        0.731041
1        1.505002        1.939828       -1.577295
2       -0.407899       -0.875374       -0.545799
3       -1.207392       -0.463464        1.292230
4       -0.688061       -0.494655        0.099824

Résultat reproduit avec scipy.stats zscore

In [12]: from scipy.stats import zscore

In [13]: df.apply(zscore) # (Credit: Manuel)
Out[13]:
    randomA   randomB   randomC
0  0.798350 -0.106335  0.731041
1  1.505002  1.939828 -1.577295
2 -0.407899 -0.875374 -0.545799
3 -1.207392 -0.463464  1.292230
4 -0.688061 -0.494655  0.099824
4
Surya

La solution presque one-liner:

df2 = (df.ix[:,1:] - df.ix[:,1:].mean()) / df.ix[:,1:].std()
df2['ID'] = df['ID']
3
Josh Chartier

pour le score Z, nous pouvons nous en tenir à la documentation au lieu d'utiliser la fonction 'appliquer'

df_zscore = scipy.stats.zscore(cols as array, axis=1)
2
ibozkurt79

Lorsque nous avons affaire à des séries chronologiques, le calcul des scores z (ou des anomalies - ce n'est pas la même chose, mais vous pouvez facilement adapter ce code) - est un peu plus compliqué. Par exemple, vous avez 10 ans de données de température mesurées chaque semaine. Pour calculer les scores z pour toute la série chronologique, vous devez connaître les moyennes et les écarts types pour chaque jour de l'année. Alors, commençons:

Supposons que vous ayez un pandas DataFrame. Tout d'abord, vous avez besoin d'un index DateTime. Si vous ne l'avez pas encore, mais heureusement, vous avez une colonne avec des dates, faites-le simplement comme votre index. Pandas va essayer de deviner le format de la date. Le but ici est d’avoir DateTimeIndex. Vous pouvez le vérifier en essayant:

type(df.index)

Si vous n'en avez pas, faisons-le.

df.index = pd.DatetimeIndex(df[datecolumn])
df = df.drop(datecolumn,axis=1)

La prochaine étape consiste à calculer la moyenne et l'écart type pour chaque groupe de jours. Pour cela, nous utilisons la méthode groupby.

mean = pd.groupby(df,by=[df.index.dayofyear]).aggregate(np.nanmean)
std = pd.groupby(df,by=[df.index.dayofyear]).aggregate(np.nanstd)

Enfin, nous parcourons toutes les dates en effectuant le calcul (valeur - moyenne)/stddev; cependant, comme mentionné, pour les séries chronologiques, ce n'est pas si simple.

df2 = df.copy() #keep a copy for future comparisons 
for y in np.unique(df.index.year):
    for d in np.unique(df.index.dayofyear):
        df2[(df.index.year==y) & (df.index.dayofyear==d)] = (df[(df.index.year==y) & (df.index.dayofyear==d)]- mean.ix[d])/std.ix[d]
        df2.index.name = 'date' #this is just to look nicer

df2 #this is your z-score dataset.

La logique à l’intérieur des boucles for est la suivante: pour une année donnée, nous devons faire correspondre chaque jour d’une année à sa moyenne et à sa moyenne. Nous l’utilisons pour toutes les années de votre série chronologique.

1
Deninhos