Normalisieren Sie Daten in Pandas

131

Angenommen, ich habe einen Pandas-Datenrahmen df:

Ich möchte den spaltenweisen Mittelwert eines Datenrahmens berechnen.

Das ist einfach:

df.apply(average) 

dann der spaltenweise Bereich max (col) - min (col). Das ist wieder einfach:

df.apply(max) - df.apply(min)

Nun möchte ich für jedes Element den Mittelwert seiner Spalte subtrahieren und durch den Bereich seiner Spalte dividieren. Ich bin mir nicht sicher, wie ich das machen soll

Jede Hilfe / Hinweise werden sehr geschätzt.

Jason
quelle

Antworten:

225
In [92]: df
Out[92]:
           a         b          c         d
A  -0.488816  0.863769   4.325608 -4.721202
B -11.937097  2.993993 -12.916784 -1.086236
C  -5.569493  4.672679  -2.168464 -9.315900
D   8.892368  0.932785   4.535396  0.598124

In [93]: df_norm = (df - df.mean()) / (df.max() - df.min())

In [94]: df_norm
Out[94]:
          a         b         c         d
A  0.085789 -0.394348  0.337016 -0.109935
B -0.463830  0.164926 -0.650963  0.256714
C -0.158129  0.605652 -0.035090 -0.573389
D  0.536170 -0.376229  0.349037  0.426611

In [95]: df_norm.mean()
Out[95]:
a   -2.081668e-17
b    4.857226e-17
c    1.734723e-17
d   -1.040834e-17

In [96]: df_norm.max() - df_norm.min()
Out[96]:
a    1
b    1
c    1
d    1
Wouter Overmeire
quelle
Gibt es eine Möglichkeit, dies zu tun, wenn Sie eine Teilmenge normalisieren möchten? Sagen Sie diese Zeile Aund Bsind Teil eines größeren Gruppierungsfaktors, den Sie getrennt von Cund normalisieren möchten D.
Amyunimus
Wählen Sie die Teilmenge aus und berechnen Sie wie zuvor. Siehe pandas.pydata.org/pandas-docs/stable/indexing.html zum Indizieren und Auswählen von Daten
Wouter Overmeire
17
Wenn Ihre Werte> 0 sein müssen: df_norm = (df - df.min ()) / (df.max () - df.min ())
Dayvid Oliveira
1
sollte df_norm = (df - df.min ()) / (df.max () - df.min ()) sein und nicht df.mean () in den ersten Klammern, um die Werte zwischen 0 und 1 zu erhalten
jnPy
2
Wenn Ihr Datenrahmen Zeichenfolgen in einigen Spalten hat, sehen Sie diese Antwort
netskink
73

Wenn es Ihnen nichts ausmacht, die sklearnBibliothek zu importieren , würde ich die in diesem Blog beschriebene Methode empfehlen .

import pandas as pd
from sklearn import preprocessing

data = {'score': [234,24,14,27,-74,46,73,-18,59,160]}
cols = data.columns
df = pd.DataFrame(data)
df

min_max_scaler = preprocessing.MinMaxScaler()
np_scaled = min_max_scaler.fit_transform(df)
df_normalized = pd.DataFrame(np_scaled, columns = cols)
df_normalized
David S.
quelle
2
Der Link zum Blog-Beitrag ist tot. Hast du eine funktionierende?
Marts
3
Die entsprechende Methode zum Erstellen von normalisierten normalisierten Daten heißt StandardScaler.
Abeboparebop
Ich habe eine ähnliche Lösung an einem anderen Ort gefunden. Das Problem war, dass im Teil np_scaled ein Fehler beim Erwarten eines 2D-Arrays angezeigt wurde, die Eingabe jedoch ein 1D-Array ist, und es wurde empfohlen, die Umformung (-1,1) zu verwenden. Irgendeine Idee, wie man dies als Umformung löst, funktioniert auch nicht.
Deadcode
Je nachdem, mit welcher Version von numpy & sklearn Sie arbeiten, werden möglicherweise Warnungen angezeigt. Im Allgemeinen sollte dies jedoch funktionieren np_scaled = min_max_scaler.fit_transform(df.score.astype(float).values.reshape(-1, 1))
Jaeyoung Chun,
33

Sie können applydies verwenden, und es ist ein bisschen ordentlicher:

import numpy as np
import pandas as pd

np.random.seed(1)

df = pd.DataFrame(np.random.randn(4,4)* 4 + 3)

          0         1         2         3
0  9.497381  0.552974  0.887313 -1.291874
1  6.461631 -6.206155  9.979247 -0.044828
2  4.276156  2.002518  8.848432 -5.240563
3  1.710331  1.463783  7.535078 -1.399565

df.apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))

          0         1         2         3
0  0.515087  0.133967 -0.651699  0.135175
1  0.125241 -0.689446  0.348301  0.375188
2 -0.155414  0.310554  0.223925 -0.624812
3 -0.484913  0.244924  0.079473  0.114448

Es funktioniert auch gut mit groupby, wenn Sie die relevanten Spalten auswählen:

df['grp'] = ['A', 'A', 'B', 'B']

          0         1         2         3 grp
0  9.497381  0.552974  0.887313 -1.291874   A
1  6.461631 -6.206155  9.979247 -0.044828   A
2  4.276156  2.002518  8.848432 -5.240563   B
3  1.710331  1.463783  7.535078 -1.399565   B


df.groupby(['grp'])[[0,1,2,3]].apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))

     0    1    2    3
0  0.5  0.5 -0.5 -0.5
1 -0.5 -0.5  0.5  0.5
2  0.5  0.5  0.5 -0.5
3 -0.5 -0.5 -0.5  0.5
naught101
quelle
2

Leicht modifiziert von: Python Pandas Dataframe: Daten zwischen 0,01 und 0,99 normalisieren? aber aus einigen Kommentaren ging hervor, dass dies relevant war (sorry, wenn dies als Repost angesehen wird ...)

Ich wollte eine angepasste Normalisierung, da das reguläre Perzentil des Bezugspunkts oder des Z-Scores nicht ausreicht. Manchmal wusste ich, was die realisierbaren Max- und Min-Werte der Bevölkerung waren, und wollte sie daher anders als meine Stichprobe oder einen anderen Mittelpunkt oder was auch immer definieren! Dies kann häufig nützlich sein, um Daten für neuronale Netze neu zu skalieren und zu normalisieren, wobei Sie möglicherweise alle Eingaben zwischen 0 und 1 wünschen, einige Ihrer Daten jedoch möglicherweise individueller skaliert werden müssen ... da Perzentile und Standardwerte Ihre Stichprobenabdeckungen voraussetzen die Bevölkerung, aber manchmal wissen wir, dass dies nicht wahr ist. Es war auch sehr nützlich für mich bei der Visualisierung von Daten in Heatmaps. Also habe ich eine benutzerdefinierte Funktion erstellt (zusätzliche Schritte im Code hier verwendet, um ihn so lesbar wie möglich zu machen):

def NormData(s,low='min',center='mid',hi='max',insideout=False,shrinkfactor=0.):    
    if low=='min':
        low=min(s)
    elif low=='abs':
        low=max(abs(min(s)),abs(max(s)))*-1.#sign(min(s))
    if hi=='max':
        hi=max(s)
    elif hi=='abs':
        hi=max(abs(min(s)),abs(max(s)))*1.#sign(max(s))

    if center=='mid':
        center=(max(s)+min(s))/2
    elif center=='avg':
        center=mean(s)
    elif center=='median':
        center=median(s)

    s2=[x-center for x in s]
    hi=hi-center
    low=low-center
    center=0.

    r=[]

    for x in s2:
        if x<low:
            r.append(0.)
        elif x>hi:
            r.append(1.)
        else:
            if x>=center:
                r.append((x-center)/(hi-center)*0.5+0.5)
            else:
                r.append((x-low)/(center-low)*0.5+0.)

    if insideout==True:
        ir=[(1.-abs(z-0.5)*2.) for z in r]
        r=ir

    rr =[x-(x-0.5)*shrinkfactor for x in r]    
    return rr

Dadurch wird eine Pandas-Serie oder auch nur eine Liste aufgenommen und auf die angegebenen Tief-, Mittel- und Hochpunkte normalisiert. es gibt auch einen schrumpfungsfaktor! Damit Sie die Daten von den Endpunkten 0 und 1 weg verkleinern können (ich musste dies tun, wenn ich Farbkarten in Matplotlib kombinierte: Einzelne Farbkarten mit mehr als einer Farbkarte mit Matplotlib ). Sie können also wahrscheinlich sehen, wie der Code funktioniert, aber im Grunde sagen Sie es haben Werte [-5,1,10] in einer Stichprobe, möchten aber basierend auf einem Bereich von -7 bis 7 (also alles über 7, unsere "10" wird effektiv als 7 behandelt) mit einem Mittelpunkt von 2 normalisieren. Verkleinern Sie es jedoch auf eine 256-RGB-Farbkarte:

#In[1]
NormData([-5,2,10],low=-7,center=1,hi=7,shrinkfactor=2./256)
#Out[1]
[0.1279296875, 0.5826822916666667, 0.99609375]

Es kann auch Ihre Daten auf den Kopf stellen ... das mag seltsam erscheinen, aber ich fand es nützlich für Heatmapping. Angenommen, Sie möchten eine dunklere Farbe für Werte, die näher an 0 als hoch / niedrig liegen. Sie können eine Heatmap basierend auf normalisierten Daten erstellen, wobei insideout = True:

#In[2]
NormData([-5,2,10],low=-7,center=1,hi=7,insideout=True,shrinkfactor=2./256)
#Out[2]
[0.251953125, 0.8307291666666666, 0.00390625]

Jetzt ist "2", die dem Zentrum am nächsten liegt und als "1" definiert ist, der höchste Wert.

Wie auch immer, ich dachte, meine Anwendung wäre relevant, wenn Sie Daten auf andere Weise neu skalieren möchten, die nützliche Anwendungen für Sie haben könnten.

Vlox
quelle
Sie können alle if / else-Anweisungen durch ein Wörterbuch mit Funktionen ersetzen . Sieht dann etwas sauberer aus.
Roald
Das ist ziemlich ordentlich, das werde ich mir beim nächsten Mal merken, danke!
Vlox
0

So machen Sie es spaltenweise:

[df[col].update((df[col] - df[col].min()) / (df[col].max() - df[col].min())) for col in df.columns]
Tschad
quelle