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.

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

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

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

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.


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]
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.