Normaliser les colonnes du bloc de données pandas


227

J'ai une trame de données dans les pandas où chaque colonne a une plage de valeurs différente. Par exemple:

df:

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

Une idée comment je peux normaliser les colonnes de cette trame de données où chaque valeur est comprise entre 0 et 1?

Ma sortie souhaitée est:

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
il y a une fonction apply, par exemple frame.apply (f, axis = 1) où f est une fonction qui fait quelque chose avec une ligne ...
tschm

1
La normalisation n'est peut-être pas la formulation la plus appropriée, car la documentation de scikit-learn la définit comme "le processus de mise à l'échelle d'échantillons individuels pour avoir une norme d'unité " (c'est-à-dire ligne par ligne, si je comprends bien).
Skippy le Grand Gourou

Je ne comprends pas, pourquoi la mise à l'échelle min_max est considérée comme une normalisation! normal doit avoir un sens dans le sens d'une distribution normale avec un zéro moyen et une variance 1.
OverFlow Police

Si vous visitez cette question en 2020 ou plus tard, regardez la réponse de @Poudel, vous obtenez une réponse différente de normalisation si vous utilisez pandas vs sklearn.
Bhishan Poudel

@Poudel est-ce dû à l' ddofargument?
fffrost

Réponses:


224

Vous pouvez utiliser le package sklearn et ses utilitaires de prétraitement associés pour normaliser les données.

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)

Pour plus d'informations, consultez la documentation de scikit-learn sur le prétraitement des données: mise à l'échelle des fonctionnalités sur une plage.


46
Je pense que cela supprimera les noms des colonnes, ce qui pourrait être l'une des raisons pour lesquelles op utilise des cadres de données en premier lieu.
pietz

47
Cela normalisera les lignes et non les colonnes, sauf si vous les transposez d'abord. Pour faire ce que le Q demande:pd.DataFrame(min_max_scaler.fit_transform(df.T), columns=df.columns, index=df.index)
plaques de cuisson

26
@pietz pour conserver les noms des colonnes, consultez cet article . Remplacer essentiellement la dernière ligne par,df=pandas.DataFrame(x_scaled, columns=df.columns)
ijoseph

5
@hobs Ce n'est pas correct. Le code de Sandman normalise colonne par colonne et par colonne. Vous obtenez le mauvais résultat si vous transposez.
petezurich

8
@petezurich Il semble que Sandman ou Praveen aient corrigé leur code. Malheureusement, il n'est pas possible de corriger les commentaires;)
plaques de cuisson

399

un moyen simple en utilisant Pandas : (ici, je veux utiliser la normalisation moyenne)

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

pour utiliser la normalisation min-max:

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

Modifier: Pour répondre à certaines préoccupations, il faut dire que Pandas applique automatiquement la fonction par colonne dans le code ci-dessus.


16
J'aime celui la. c'est court, c'est expressif et ça préserve les informations d'en-tête. mais je pense que vous devez également soustraire le min dans le dénominateur.
pietz

6
Je ne pense pas que ce soit mal. Fonctionne très bien pour moi - je ne pense pas que mean () et std () aient besoin de renvoyer une trame de données pour que cela fonctionne et votre message d'erreur n'implique pas qu'ils ne sont pas une trame de données est un problème.
Strandtasche

24
ce n'est pas une normalisation par colonne. cela normalise la matrice entière dans son ensemble, ce qui donnera de mauvais résultats.
Nguai al

6
A également fonctionné magnifiquement pour moi. @Nguaial vous pourriez essayer ceci sur une matrice numpy auquel cas le résultat serait ce que vous avez dit. Mais pour les cadres de données Pandas, les mesures min, max, ... s'appliquent par défaut aux colonnes.
Auxiliary

1
j'aime aussi celui-ci
Isaac Sim

51

Basé sur ce post: /stats/70801/how-to-normalize-data-to-0-1-range

Vous pouvez effectuer les opérations suivantes:

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

Vous n'avez pas besoin de vous inquiéter de savoir si vos valeurs sont négatives ou positives. Et les valeurs doivent être bien réparties entre 0 et 1.


8
Soyez prudent lorsque les valeurs min et max sont identiques, votre dénominateur est 0 et vous obtiendrez une valeur NaN.
Hrushikesh Dhumal

36

Votre problème est en fait une simple transformation agissant sur les colonnes:

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

frame.apply(f, axis=0)

Ou encore plus laconique:

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

2
L' lambdaun est le meilleur :-)
Abu Shoeb

4
n'est-ce pas censé être axe = 1 puisque la question est la normalisation par colonne?
Nguai al

Non, des docs : axis [...] 0 or 'index': apply function to each column. La valeur par défaut est en fait axis=0donc ce one-liner peut être écrit encore plus court :-) Merci @tschm.
jorijnsmit

30

Si vous aimez utiliser le package sklearn, vous pouvez conserver les noms de colonne et d'index en utilisant des pandas loccomme ceci:

from sklearn.preprocessing import MinMaxScaler

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

27

Le simple est beau:

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

Super et à mon avis la meilleure solution!
Maciej A. Bednarz

6
Notez que OP a demandé une plage de [0..1] et cette solution évolue vers la plage de [-1..1]. Essayez ceci avec le tableau [-10, 10].
Alexander Sosnovshchenko

3
@AlexanderSosnovshchenko pas vraiment. Basil Musa suppose que la matrice du PO est toujours non négative, c'est pourquoi il a donné cette solution. Si une colonne a une entrée négative, ce code ne se normalise PAS dans la plage [-1,1]. Essayez-le avec le tableau [-5, 10]. La bonne façon de normaliser à [0,1] avec des valeurs négatives a été donnée par la réponse de Cinadf["A"] = (df["A"]-df["A"].min()) / (df["A"].max()-df["A"].min())
facuq

simple ET explicite
joshi123

Peut-être encore plus simple: df /= df.max()- en supposant que l'objectif est de normaliser chaque colonne, individuellement.
n1k31t4

24

Vous pouvez créer une liste de colonnes que vous souhaitez normaliser

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

Votre cadre de données Pandas est désormais normalisé uniquement dans les colonnes que vous souhaitez


Cependant , si vous voulez le contraire , sélectionnez une liste de colonnes que vous ne voulez PAS normaliser, vous pouvez simplement créer une liste de toutes les colonnes et supprimer celles non souhaitées

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

Je pense qu'une meilleure façon de le faire chez les pandas est juste

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

Modifier Si, dans votre bloc de données, des nombres négatifs sont présents, vous devez utiliser à la place

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

1
Si toutes les valeurs d'une colonne sont nulles, cela ne fonctionnera pas
ahajib

diviser la valeur actuelle par le max ne vous donnera pas une normalisation correcte à moins que le min ne soit 0.
pietz

Je suis d'accord, mais c'est ce que l'OT demandait (voir son exemple)
Daniele

11

La solution donnée par Sandman et Praveen est très bien. Le seul problème avec cela, si vous avez des variables catégorielles dans d'autres colonnes de votre bloc de données, cette méthode nécessitera quelques ajustements.

Ma solution à ce type de problème est la suivante:

 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
Cette réponse est utile car la plupart des exemples sur Internet appliquent un scaler à toutes les colonnes, alors que cela résout le cas où un scaler, par exemple le MinMaxScaler, ne devrait pas s'appliquer à toutes les colonnes.
demongolem

10

Exemple de différentes standardisations en python.

Pour référence, consultez cet article wikipedia: https://en.wikipedia.org/wiki/Unbias_estimation_of_standard_deviation

Exemples de données

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

Normalisation à l'aide de pandas (donne des estimations impartiales)

Lors de la normalisation, nous soustrayons simplement la moyenne et divisons par l'écart-type.

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

Normalisation à l'aide de sklearn (donne des estimations biaisées, différentes des pandas)

Si vous faites la même chose avec sklearnvous obtiendrez une sortie DIFFÉRENTE!

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

Est-ce que les estimations biaisées de sklearn rendent l'apprentissage machine moins puissant?

NON.

La documentation officielle de sklearn.preprocessing.scale indique que l'utilisation d'un estimateur biaisé N'EST PAS PROBABLE pour affecter les performances des algorithmes d'apprentissage automatique et que nous pouvons les utiliser en toute sécurité.

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.

Qu'en est-il de la mise à l'échelle MinMax?

Il n'y a pas de calcul d'écart type dans la mise à l'échelle MinMax. Le résultat est donc le même pour les pandas et pour scikit-learn.

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

Vous voudrez peut-être que certaines colonnes soient normalisées et les autres inchangées, comme certaines tâches de régression dont les étiquettes de données ou les colonnes catégorielles sont inchangées.Je vous suggère donc cette méthode pythonique (c'est une combinaison de réponses @shg et @Cina):

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

Ce ne sont que des mathématiques simples. La réponse devrait être aussi simple que ci-dessous.

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)

A partir du document de pandas, la structure DataFrame peut appliquer une opération (fonction) à elle-même.

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

Applique la fonction le long de l'axe d'entrée de DataFrame. Les objets passés aux fonctions sont des objets Series ayant un index soit l'index du DataFrame (axe = 0) ou les colonnes (axe = 1). Le type de retour dépend de l'agrégation de fonctions passée ou de l'argument de réduction si le DataFrame est vide.

Vous pouvez appliquer une fonction personnalisée pour faire fonctionner le DataFrame.


2
Il serait bon d'expliquer pourquoi votre code résout le problème des OP, afin que les gens puissent adapter la stratégie plutôt que de simplement copier votre code. Veuillez lire Comment écrire une bonne réponse?
M. T

2

La fonction suivante calcule le score Z:

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

Voici comment procéder par colonne en utilisant la compréhension de liste:

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

1

Vous pouvez simplement utiliser la fonction pandas.DataFrame.transform 1 de cette manière:

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

Cette solution ne fonctionnera pas si toutes les valeurs sont négatives. Considérez [-1, -2, -3]. Nous divisons par -1, et maintenant nous avons [1,2,3].
Dave Liu


0

Vous pouvez le faire en une seule ligne

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

il prend la moyenne de chacune des colonnes, puis la soustrait (moyenne) de chaque ligne (moyenne de la colonne particulière soustrait de sa ligne uniquement) et divise par la moyenne uniquement. Enfin, nous obtenons l'ensemble de données normalisé.


0

Pandas effectue la normalisation par colonne par défaut. Essayez le code ci-dessous.

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

Les valeurs de sortie seront comprises entre 0 et 1.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.