Normalisieren Sie die Spalten des Pandas-Datenrahmens


226

Ich habe einen Datenrahmen in Pandas, in dem jede Spalte einen anderen Wertebereich hat. Beispielsweise:

df:

A     B   C
1000  10  0.5
765   5   0.35
800   7   0.09

Irgendeine Idee, wie ich die Spalten dieses Datenrahmens normalisieren kann, wobei jeder Wert zwischen 0 und 1 liegt?

Meine gewünschte Ausgabe ist:

A     B    C
1     1    1
0.765 0.5  0.7
0.8   0.7  0.18(which is 0.09/0.5)

1
Es gibt eine Apply-Funktion, z. B. frame.apply (f, axis = 1), wobei f eine Funktion ist, die etwas mit einer Zeile macht ...
tschm

1
Normalisierung ist möglicherweise nicht die am besten geeignete Formulierung, da die Scikit-Learn-Dokumentation sie als "den Prozess des Skalierens einzelner Stichproben auf Einheitsnorm " definiert (dh zeilenweise, wenn ich sie richtig verstehe).
Skippy le Grand Gourou

Ich verstehe nicht, warum min_max-Skalierung als Normalisierung betrachtet wird! Normal muss eine Bedeutung im Sinne einer Normalverteilung mit Mittelwert Null und Varianz 1 haben.
OverFlow Police

Wenn Sie diese Frage im Jahr 2020 oder später besuchen, schauen Sie sich die Antwort von @Poudel an. Wenn Sie Pandas oder Sklearn verwenden, erhalten Sie eine andere Antwort auf die Normalisierung.
Bhishan Poudel

@Poudel liegt das am ddofargument?
Frost

Antworten:


223

Sie können das Paket sklearn und die zugehörigen Vorverarbeitungsprogramme verwenden, um die Daten zu normalisieren.

import pandas as pd
from sklearn import preprocessing

x = df.values #returns a numpy array
min_max_scaler = preprocessing.MinMaxScaler()
x_scaled = min_max_scaler.fit_transform(x)
df = pd.DataFrame(x_scaled)

Weitere Informationen finden Sie in der Scikit-Learn- Dokumentation zur Vorverarbeitung von Daten: Skalieren von Funktionen auf einen Bereich.


46
Ich denke, dies wird die Spaltennamen loswerden, was einer der Gründe sein könnte, warum op überhaupt Datenrahmen verwendet.
Pietz

47
Dadurch werden die Zeilen und nicht die Spalten normalisiert, es sei denn, Sie transponieren sie zuerst. Um zu tun, was der Q verlangt:pd.DataFrame(min_max_scaler.fit_transform(df.T), columns=df.columns, index=df.index)
Kochfelder

26
@pietz, um Spaltennamen beizubehalten, siehe diesen Beitrag . Ersetzen Sie im Grunde die letzte Zeile durch,df=pandas.DataFrame(x_scaled, columns=df.columns)
ijoseph

5
@hobs Das ist nicht richtig. Sandmans Code normalisiert spaltenweise und spaltenweise. Sie erhalten das falsche Ergebnis, wenn Sie transponieren.
Petezurich

8
@petezurich Es sieht so aus, als hätten Sandman oder Praveen ihren Code korrigiert. Leider ist es nicht möglich, Kommentare zu korrigieren;)
Kochfelder

397

Ein einfacher Weg mit Pandas : (hier möchte ich die mittlere Normalisierung verwenden)

normalized_df=(df-df.mean())/df.std()

Min-Max-Normalisierung verwenden:

normalized_df=(df-df.min())/(df.max()-df.min())

Bearbeiten: Um einige Bedenken auszuräumen, muss gesagt werden, dass Pandas im obigen Code automatisch die colomn-weise Funktion anwendet.


16
Ich mag diesen. Es ist kurz, ausdrucksstark und bewahrt die Header-Informationen. aber ich denke, Sie müssen auch die min im Nenner subtrahieren.
Pietz

6
Ich denke nicht, dass es falsch ist. Funktioniert wunderbar für mich - ich denke nicht, dass mean () und std () einen Datenrahmen zurückgeben müssen, damit dies funktioniert, und Ihre Fehlermeldung bedeutet nicht, dass sie kein Datenrahmen sind, ist ein Problem.
Strandtasche

24
Dies ist keine spaltenweise Normalisierung. Dies normalisiert die gesamte Matrix als Ganzes, was zu falschen Ergebnissen führt.
Nguai al

5
Hat auch bei mir wunderbar funktioniert. @Nguaial Sie könnten dies auf einer Numpy-Matrix versuchen. In diesem Fall wäre das Ergebnis das, was Sie gesagt haben. Bei Pandas-Datenrahmen gelten die Kennzahlen min, max, ... standardmäßig spaltenweise.
Hilfs

1
Ich mag dieses auch
Isaac Sim

51

Basierend auf diesem Beitrag: /stats/70801/how-to-normalize-data-to-0-1-range

Sie können Folgendes tun:

def normalize(df):
    result = df.copy()
    for feature_name in df.columns:
        max_value = df[feature_name].max()
        min_value = df[feature_name].min()
        result[feature_name] = (df[feature_name] - min_value) / (max_value - min_value)
    return result

Sie müssen sich keine Sorgen machen, ob Ihre Werte negativ oder positiv sind. Und die Werte sollten gut zwischen 0 und 1 verteilt sein.


8
Seien Sie vorsichtig, wenn die Min- und Max-Werte gleich sind, Ihr Nenner 0 ist und Sie einen NaN-Wert erhalten.
Hrushikesh Dhumal

36

Ihr Problem ist eigentlich eine einfache Transformation, die auf die Spalten wirkt:

def f(s):
    return s/s.max()

frame.apply(f, axis=0)

Oder noch knapper:

   frame.apply(lambda x: x/x.max(), axis=0)

2
Der lambdaeine ist der beste :-)
Abu Shoeb

4
Soll dies nicht Achse = 1 sein, da die Frage die spaltenweise Normalisierung ist?
Nguai al

Nein, aus den Dokumenten : axis [...] 0 or 'index': apply function to each column. Die Standardeinstellung ist eigentlich, axis=0damit dieser Einzeiler noch kürzer geschrieben werden kann :-) Danke @tschm.
jorijnsmit

30

Wenn Sie das sklearn-Paket verwenden möchten, können Sie die Spalten- und Indexnamen mithilfe von Pandas locwie folgt beibehalten :

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler() 
scaled_values = scaler.fit_transform(df) 
df.loc[:,:] = scaled_values

27

Einfach ist schön:

df["A"] = df["A"] / df["A"].max()
df["B"] = df["B"] / df["B"].max()
df["C"] = df["C"] / df["C"].max()

Toll und meiner Meinung nach die beste Lösung!
Maciej A. Bednarz

6
Beachten Sie, dass OP nach dem Bereich [0..1] gefragt hat und diese Lösung auf den Bereich [-1..1] skaliert. Versuchen Sie dies mit dem Array [-10, 10].
Alexander Sosnovshchenko

3
@ AlexanderSosnovshchenko nicht wirklich. Basil Musa geht davon aus, dass die Matrix des OP immer nicht negativ ist, deshalb hat er diese Lösung gegeben. Wenn eine Spalte einen negativen Eintrag hat, normalisiert sich dieser Code NICHT auf den Bereich [-1,1]. Versuchen Sie es mit dem Array [-5, 10]. Der richtige Weg zur Normalisierung auf [0,1] mit negativen Werten wurde durch df["A"] = (df["A"]-df["A"].min()) / (df["A"].max()-df["A"].min())
Cinas

einfach UND explizit
joshi123

Vielleicht noch einfacher: df /= df.max()- Unter der Annahme, dass das Ziel darin besteht, jede einzelne Spalte einzeln zu normalisieren.
n1k31t4

24

Sie können eine Liste von Spalten erstellen, die Sie normalisieren möchten

column_names_to_normalize = ['A', 'E', 'G', 'sadasdsd', 'lol']
x = df[column_names_to_normalize].values
x_scaled = min_max_scaler.fit_transform(x)
df_temp = pd.DataFrame(x_scaled, columns=column_names_to_normalize, index = df.index)
df[column_names_to_normalize] = df_temp

Ihr Pandas-Datenrahmen wird jetzt nur in den gewünschten Spalten normalisiert


Allerdings , wenn Sie das wollen gegenüber , wählen Sie eine Liste der Spalten , dass Sie NICHT TUN normalisieren möchten, können Sie einfach eine Liste aller Spalten erstellen , und dass nicht Gewünschten entfernen

column_names_to_not_normalize = ['B', 'J', 'K']
column_names_to_normalize = [x for x in list(df) if x not in column_names_to_not_normalize ]

11

Die Lösung von Sandman und Praveen ist sehr gut. Das einzige Problem dabei ist, dass diese Methode einige Anpassungen erfordert, wenn Sie kategoriale Variablen in anderen Spalten Ihres Datenrahmens haben.

Meine Lösung für diese Art von Problem lautet wie folgt:

 from sklearn import preprocesing
 x = pd.concat([df.Numerical1, df.Numerical2,df.Numerical3])
 min_max_scaler = preprocessing.MinMaxScaler()
 x_scaled = min_max_scaler.fit_transform(x)
 x_new = pd.DataFrame(x_scaled)
 df = pd.concat([df.Categoricals,x_new])

2
Diese Antwort ist nützlich, da die meisten Beispiele im Internet einen Skalierer auf alle Spalten anwenden, während dies tatsächlich die Situation betrifft, in der ein Skalierer, beispielsweise der MinMaxScaler, nicht auf alle Spalten angewendet werden sollte.
Demongolem

10

Ich denke, dass ein besserer Weg, dies bei Pandas zu tun, gerecht ist

df = df/df.max().astype(np.float64)

Bearbeiten Wenn in Ihrem Datenrahmen negative Zahlen vorhanden sind, sollten Sie stattdessen verwenden

df = df/df.loc[df.abs().idxmax()].astype(np.float64)

1
Wenn

Wenn Sie den aktuellen Wert durch das
Maximum teilen

Ich stimme zu, aber darum hat der OT gebeten (siehe sein Beispiel)
Daniele

10

Beispiel für verschiedene Standardisierungen in Python.

Eine Referenz finden Sie in diesem Wikipedia-Artikel: https://en.wikipedia.org/wiki/Unbiased_estimation_of_standard_deviation

Beispieldaten

import pandas as pd
df = pd.DataFrame({
               'A':[1,2,3],
               'B':[100,300,500],
               'C':list('abc')
             })
print(df)
   A    B  C
0  1  100  a
1  2  300  b
2  3  500  c

Normalisierung mit Pandas (Gibt unvoreingenommene Schätzungen)

Bei der Normalisierung subtrahieren wir einfach den Mittelwert und dividieren durch die Standardabweichung.

df.iloc[:,0:-1] = df.iloc[:,0:-1].apply(lambda x: (x-x.mean())/ x.std(), axis=0)
print(df)
     A    B  C
0 -1.0 -1.0  a
1  0.0  0.0  b
2  1.0  1.0  c

Normalisierung mit sklearn (Gibt voreingenommene Schätzungen, die sich von Pandas unterscheiden)

Wenn Sie dasselbe tun, erhalten sklearnSie eine VERSCHIEDENE Ausgabe!

import pandas as pd

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()


df = pd.DataFrame({
               'A':[1,2,3],
               'B':[100,300,500],
               'C':list('abc')
             })
df.iloc[:,0:-1] = scaler.fit_transform(df.iloc[:,0:-1].to_numpy())
print(df)
          A         B  C
0 -1.224745 -1.224745  a
1  0.000000  0.000000  b
2  1.224745  1.224745  c

Macht voreingenommene Schätzungen von sklearn maschinelles Lernen weniger leistungsfähig?

NEIN.

Die offizielle Dokumentation von sklearn.preprocessing.scale besagt, dass die Verwendung eines voreingenommenen Schätzers die Leistung von Algorithmen für maschinelles Lernen UNMÖGLICHERWEISE beeinträchtigt und wir sie sicher verwenden können.

From official documentation:
We use a biased estimator for the standard deviation,
equivalent to numpy.std(x, ddof=0). 
Note that the choice of ddof is unlikely to affect model performance.

Was ist mit MinMax-Skalierung?

Bei der MinMax-Skalierung gibt es keine Standardabweichungsberechnung. Das Ergebnis ist also sowohl bei Pandas als auch bei Scikit-Learn gleich.

import pandas as pd
df = pd.DataFrame({
               'A':[1,2,3],
               'B':[100,300,500],
             })
(df - df.min()) / (df.max() - df.min())
     A    B
0  0.0  0.0
1  0.5  0.5
2  1.0  1.0


# Using sklearn
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler() 
arr_scaled = scaler.fit_transform(df) 

print(arr_scaled)
[[0.  0. ]
 [0.5 0.5]
 [1.  1. ]]

df_scaled = pd.DataFrame(arr_scaled, columns=df.columns,index=df.index)
print(df_scaled)
     A    B
0  0.0  0.0
1  0.5  0.5
2  1.0  1.0

6

Möglicherweise möchten Sie, dass einige Spalten normalisiert werden und die anderen unverändert bleiben, wie bei einigen Regressionsaufgaben, bei denen Datenbeschriftungen oder kategoriale Spalten unverändert bleiben. Ich empfehle Ihnen daher diese pythonische Methode (eine Kombination aus @ shg- und @ Cina-Antworten):

features_to_normalize = ['A', 'B', 'C']
# could be ['A','B'] 

df[features_to_normalize] = df[features_to_normalize].apply(lambda x:(x-x.min()) / (x.max()-x.min()))

5

Es ist nur einfache Mathematik. Die Antwort sollte so einfach wie unten sein.

normed_df = (df - df.min()) / (df.max() - df.min())

2
def normalize(x):
    try:
        x = x/np.linalg.norm(x,ord=1)
        return x
    except :
        raise
data = pd.DataFrame.apply(data,normalize)

Aus dem Dokument von Pandas kann die DataFrame-Struktur eine Operation (Funktion) auf sich selbst anwenden.

DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)

Wendet die Funktion entlang der Eingabeachse von DataFrame an. An Funktionen übergebene Objekte sind Serienobjekte mit einem Index, der entweder den Index des DataFrames (Achse = 0) oder die Spalten (Achse = 1) enthält. Der Rückgabetyp hängt davon ab, ob übergebene Funktionsaggregate oder das Reduktionsargument, wenn der DataFrame leer ist.

Sie können eine benutzerdefinierte Funktion anwenden, um den DataFrame zu bedienen.


2
Es wäre gut zu erklären, warum Ihr Code das OP-Problem löst, damit die Benutzer die Strategie anpassen können, anstatt nur Ihren Code zu kopieren. Bitte lesen Sie Wie schreibe ich eine gute Antwort?
Herr T

2

Die folgende Funktion berechnet den Z-Score:

def standardization(dataset):
  """ Standardization of numeric fields, where all values will have mean of zero 
  and standard deviation of one. (z-score)

  Args:
    dataset: A `Pandas.Dataframe` 
  """
  dtypes = list(zip(dataset.dtypes.index, map(str, dataset.dtypes)))
  # Normalize numeric columns.
  for column, dtype in dtypes:
      if dtype == 'float32':
          dataset[column] -= dataset[column].mean()
          dataset[column] /= dataset[column].std()
  return dataset

2

So machen Sie es spaltenweise mit Listenverständnis:

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

1

Sie können die Funktion pandas.DataFrame.transform 1 einfach folgendermaßen verwenden :

df.transform(lambda x: x/x.max())

Diese Lösung funktioniert nicht, wenn alle Werte negativ sind. Betrachten Sie [-1, -2, -3]. Wir teilen durch -1 und jetzt haben wir [1,2,3].
Dave Liu


0

Sie können dies in einer Zeile tun

DF_test = DF_test.sub(DF_test.mean(axis=0), axis=1)/DF_test.mean(axis=0)

Es nimmt den Mittelwert für jede Spalte und subtrahiert ihn dann (Mittelwert) von jeder Zeile (der Mittelwert einer bestimmten Spalte subtrahiert nur von ihrer Zeile) und dividiert nur durch den Mittelwert. Schließlich erhalten wir den normalisierten Datensatz.


0

Pandas führt standardmäßig eine spaltenweise Normalisierung durch. Versuchen Sie den folgenden Code.

X= pd.read_csv('.\\data.csv')
X = (X-X.min())/(X.max()-X.min())

Die Ausgabewerte liegen im Bereich von 0 und 1.

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.