Pandy-Oblicz Z-score dla wszystkich kolumn
Mam ramkę danych zawierającą pojedynczą kolumnę identyfikatorów, a wszystkie pozostałe kolumny są wartościami liczbowymi, dla których chcę obliczyć z-scores. Oto jego podrozdział:
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
Niektóre z moich kolumn zawierają wartości NaN, których nie chcę włączać do obliczeń z-score, więc zamierzam skorzystać z rozwiązania zaproponowanego na to pytanie: Jak znormalizować kolumny pand z nan?
df['zscore'] = (df.a - df.a.mean())/df.a.std(ddof=0)
Jestem zainteresowany zastosowaniem tego rozwiązania do wszystkich moich kolumn z wyjątkiem kolumny ID, aby utworzyć nowy dataframe, który mogę zapisać jako plik Excel za pomocą
df2.to_excel("Z-Scores.xlsx")
Więc zasadniczo; jak mogę obliczyć z-scores dla każdej kolumny (ignorując wartości NaN) i wcisnąć wszystko do nowej ramki danych?
Uwaga boczna: w pandach istnieje pojęcie zwane "indeksowaniem", które mnie onieśmiela, ponieważ nie rozumiem go dobrze. Jeśli indeksowanie jest kluczową częścią rozwiązania tego problemu, proszę o wyjaśnienie sposobu indeksowania.
7 answers
Zbuduj listę z kolumn i Usuń kolumnę, dla której nie chcesz obliczyć wyniku Z:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-15 15:29:03
Using Scipy ' s zscore function:
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 |
Jeśli nie wszystkie kolumny ramki danych są numeryczne, to można zastosować funkcję Z-score tylko do kolumn numerycznych za pomocą funkcji select_dtypes
:
# 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 |
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-14 09:51:33
Jeśli chcesz obliczyć zscore dla wszystkich kolumn, możesz użyć następującego wzoru:
df_zscore = (df - df.mean())/df.std()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-01 14:09:48
Dla wyniku Z, możemy trzymać się dokumentacji zamiast używać funkcji 'apply'
from scipy.stats import zscore
df_zscore = zscore(cols as array, axis=1)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-26 16:52:12
Oto inny sposób na uzyskanie Zscore za pomocą funkcji niestandardowej:
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
Wynik odtworzony za pomocą scipy.statystyki 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-06 15:54:29
Rozwiązanie prawie jednoliniowe:
df2 = (df.ix[:,1:] - df.ix[:,1:].mean()) / df.ix[:,1:].std()
df2['ID'] = df['ID']
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-22 19:45:53
Kiedy mamy do czynienia z szeregami czasowymi, Obliczanie z-scores (lub anomalii-nie to samo, ale można łatwo dostosować ten kod) jest nieco bardziej skomplikowane. Na przykład, masz 10 lat danych temperatury mierzone tygodniowo. Aby obliczyć z-scores dla całego szeregu czasowego, musisz znać średnie i odchylenia standardowe dla każdego dnia roku. Więc zaczynajmy:
Załóżmy, że masz ramkę danych pandy. Przede wszystkim potrzebujesz indeksu DateTime. Jeśli jeszcze go nie masz, ale na szczęście masz kolumnę z datami, po prostu zrób to jako swój indeks. Pandy będą próbować odgadnąć format daty. Celem jest posiadanie DateTimeIndex. Możesz to sprawdzić, próbując:
type(df.index)
Jeśli go nie masz, zróbmy to.
df.index = pd.DatetimeIndex(df[datecolumn])
df = df.drop(datecolumn,axis=1)
Kolejnym krokiem jest obliczenie średniej i odchylenia standardowego dla każdej grupy dni. W tym celu używamy metody groupby.
mean = pd.groupby(df,by=[df.index.dayofyear]).aggregate(np.nanmean)
std = pd.groupby(df,by=[df.index.dayofyear]).aggregate(np.nanstd)
Na koniec przechodzimy przez wszystkie daty, wykonując obliczenia (wartość-średnia) / stddev; jednak, jak wspomniane, dla szeregów czasowych nie jest to takie proste.
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.
Logika wewnątrz pętli for jest następująca: dla danego roku musimy dopasować każdy dzień roku do jego średniej i stdev. Prowadzimy to przez wszystkie lata w Twojej serii czasowej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-12 05:16:26