Normalizar columnas de un marco de datos

9 minutos de lectura

avatar de usuario
ahajib

Tengo un marco de datos en pandas donde cada columna tiene un rango de valores diferente. Por ejemplo:

d.f.:

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

¿Alguna idea de cómo puedo normalizar las columnas de este marco de datos donde cada valor está entre 0 y 1?

Mi resultado deseado es:

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

  • hay una función de aplicación, por ejemplo, frame.apply(f, axis=1) donde f es una función que hace algo con una fila…

    – tschm

    16/10/2014 a las 22:30

  • La normalización podría no ser la redacción más adecuada, ya que documentación de scikit-learn lo define como “el proceso de escalar muestras individuales para tener una norma unitaria” (es decir, fila por fila, si lo entiendo correctamente).

    – Skippy el Gran Gourou

    5 de marzo de 2019 a las 16:58

  • No lo entiendo, ¿por qué la escala min_max se considera normalización? normal tiene que tener significado en el sentido de distribución normal con media cero y varianza 1.

    – Policía de desbordamiento

    21 de abril de 2019 a las 2:21


  • Si está visitando esta pregunta en 2020 o posterior, mire la respuesta de @Poudel, obtendrá una respuesta diferente de normalización si usa pandas vs sklearn.

    – BhishanPoudel

    29 de enero de 2020 a las 20:10

  • @Poudel es esto debido a la ddof ¿argumento?

    – escarcha

    4 abr 2020 a las 20:26

avatar de usuario
China

una manera fácil usando pandas: (aquí quiero usar la normalización media)

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

para usar la normalización min-max:

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

Editar: para abordar algunas inquietudes, debo decir que Pandas aplica automáticamente la función de columna en el código anterior.

  • ¿Se puede hacer de alguna manera con la función de ventana? Lo que quiero decir con eso es calcular max () y min () en función de, por ejemplo, las últimas 10 observaciones.

    – Krakowi

    15 de noviembre de 2019 a las 10:12

  • si quieres guardar alguna columna, hazlo normalized_df['TARGET'] = df['TARGET']

    –Roman Filippov

    22 de diciembre de 2019 a las 9:53


  • esta es una buena solución, pero necesita muchas comprobaciones menos hermosas para evitar errores de división por cero

    -Teddy Ward

    7 mayo 2020 a las 21:26

  • Hice una nueva pregunta; Si alguien sabe la respuesta, por favor ilumíneme: stackoverflow.com/questions/61726904/…

    – Psicotecnópata

    12 de mayo de 2020 a las 11:02

  • ¿Existe una forma estándar integrada de hacer esto por columna sin recorrer todas las columnas?

    – Gulzar

    12 de enero de 2021 a las 10:42


avatar de usuario
hombre de arena

Puede usar el paquete sklearn y sus utilidades de preprocesamiento asociadas para normalizar los datos.

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)

Para obtener más información, consulte el scikit-learn documentación sobre el preprocesamiento de datos: escalar características a un rango.

  • Creo que esto eliminará los nombres de las columnas, lo que podría ser una de las razones por las que op está usando marcos de datos en primer lugar.

    – pietz

    16 de enero de 2017 a las 21:02

  • Esto normalizará las filas y no las columnas, a menos que lo transponga primero. Para hacer lo que pide la Q: pd.DataFrame(min_max_scaler.fit_transform(df.T), columns=df.columns, index=df.index)

    – placas

    20 de enero de 2017 a las 23:47

  • @pietz para mantener los nombres de las columnas, vea esta publicación. Básicamente reemplaza la última línea con , df=pandas.DataFrame(x_scaled, columns=df.columns)

    – José

    26 de junio de 2017 a las 18:52


  • @hobs Esto no es correcto. El código de Sandman se normaliza por columnas y por columnas. Obtienes un resultado incorrecto si transpones.

    – petezurich

    1 de abril de 2018 a las 14:10

  • @petezurich Parece que Sandman o Praveen corrigieron su código. Desafortunadamente, no es posible corregir los comentarios 😉

    – placas

    03/04/2018 a las 21:25

avatar de usuario
Miguel Aquilina

Basado en esta publicación: https://stats.stackexchange.com/questions/70801/how-to-normalize-data-to-0-1-range

Puedes hacer lo siguiente:

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

No necesitas seguir preocupándote por si tus valores son negativos o positivos. Y los valores deben estar bien distribuidos entre 0 y 1.

  • Tenga cuidado cuando los valores mínimo y máximo sean iguales, su denominador es 0 y obtendrá un valor de NaN.

    – hru_d

    1 de febrero de 2019 a las 6:02

  • @HrushikeshDhumal, entonces no es necesario normalizar, ya que todos los valores serían iguales.

    – Appaji Chintimi

    26 de octubre de 2020 a las 9:13

  • @AppajiChintimi, esta solución se aplica a datos completos, si no ha realizado una verificación de cordura, podría tener problemas.

    – hru_d

    29 oct 2020 a las 23:54

avatar de usuario
BhishanPoudel

Ejemplo detallado de métodos de normalización

  • Normalización de pandas (imparcial)
  • Normalización de Sklearn (sesgada)
  • ¿Afecta el enfoque sesgado versus imparcial al aprendizaje automático?
  • Escalado mixto-máximo

Referencias:
Wikipedia: estimación imparcial de la desviación estándar

Datos de ejemplo

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

Normalización usando pandas (Da estimaciones imparciales)

Al normalizar, simplemente restamos la media y dividimos por la desviación estándar.

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

Normalización usando sklearn (Da estimaciones sesgadas, diferentes de pandas)

Si haces lo mismo con sklearn ¡Obtendrás una salida DIFERENTE!

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

¿Las estimaciones sesgadas de sklearn hacen que el aprendizaje automático sea menos poderoso?

NO.

La documentación oficial de sklearn.preprocesamiento.escala establece que es POCO PROBABLE que el uso de un estimador sesgado afecte el rendimiento de los algoritmos de aprendizaje automático y que podemos usarlos de manera segura.

De la documentación oficial:

Usamos un estimador sesgado para la desviación estándar, equivalente a numpy.std(x, ddof=0). Tenga en cuenta que la elección de ddof es poco probable que afecte el rendimiento del modelo.

¿Qué pasa con el escalado MinMax?

No hay cálculo de Desviación estándar en el escalado MinMax. Entonces, el resultado es el mismo tanto en pandas como en 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

avatar de usuario
tschm

Su problema es en realidad una transformación simple que actúa sobre las columnas:

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

frame.apply(f, axis=0)

O aún más conciso:

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

  • los lambda uno es el mejor 🙂

    – Abu Shoeb

    8 dic 2018 a las 23:49

  • ¿No se supone que esto es eje = 1 ya que la pregunta es la normalización de columnas?

    – Nguai al

    26 de abril de 2019 a las 23:27

  • no, de la documentos: axis [...] 0 or 'index': apply function to each column. El valor predeterminado es en realidad axis=0 así que esta frase se puede escribir aún más corta 🙂 Gracias @tschm.

    – jorijnsmit

    11 de abril de 2020 a las 15:01

  • Esto solo es correcto si el mínimo es 0, que no es algo que realmente deba asumir

    – QFSW

    21 de noviembre de 2020 a las 17:19

  • Mi ejemplo estaba destinado a ilustrar cómo aplicar funciones en columnas de marcos de datos. Obviamente, como siempre, debe prestar atención a los casos extremos, por ejemplo, aquí el máximo podría ser cero y generar un problema. No estoy seguro de entender @QFSW.

    – tschm

    22 de noviembre de 2020 a las 18:28

avatar de usuario
j triste

Si le gusta usar el paquete sklearn, puede mantener los nombres de columna e índice usando pandas loc al igual que:

from sklearn.preprocessing import MinMaxScaler

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

  • los lambda uno es el mejor 🙂

    – Abu Shoeb

    8 dic 2018 a las 23:49

  • ¿No se supone que esto es eje = 1 ya que la pregunta es la normalización de columnas?

    – Nguai al

    26 de abril de 2019 a las 23:27

  • no, de la documentos: axis [...] 0 or 'index': apply function to each column. El valor predeterminado es en realidad axis=0 así que esta frase se puede escribir aún más corta 🙂 Gracias @tschm.

    – jorijnsmit

    11 de abril de 2020 a las 15:01

  • Esto solo es correcto si el mínimo es 0, que no es algo que realmente deba asumir

    – QFSW

    21 de noviembre de 2020 a las 17:19

  • Mi ejemplo estaba destinado a ilustrar cómo aplicar funciones en columnas de marcos de datos. Obviamente, como siempre, debe prestar atención a los casos extremos, por ejemplo, aquí el máximo podría ser cero y generar un problema. No estoy seguro de entender @QFSW.

    – tschm

    22 de noviembre de 2020 a las 18:28

avatar de usuario
gulzar

cuidado con esta respuestaya que SOLO funciona para datos que varían [0, n]. Esto no funciona para ningún rango de datos.


Lo simple es hermoso:

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

  • Tenga en cuenta que OP pidió [0..1] rango y esta solución escala a [-1..1] rango. Prueba esto con la matriz [-10, 10].

    – Alexander Sosnovshchenko

    28 de abril de 2018 a las 9:20

  • @AlexanderSosnovshchenko no realmente. Basil Musa asume que la matriz del OP siempre es no negativa, por eso ha dado esta solución. Si alguna columna tiene una entrada negativa, este código NO se normaliza a la [-1,1] rango. Pruébalo con la matriz [-5, 10]. La forma correcta de normalizar a [0,1] con valores negativos fue dado por la respuesta de Cina df["A"] = (df["A"]-df["A"].min()) / (df["A"].max()-df["A"].min())

    – Pepe Mandioca

    9 de noviembre de 2018 a las 13:24


  • Quizás incluso más simple: df /= df.max() – suponiendo que el objetivo es normalizar todas y cada una de las columnas, individualmente.

    – n1k31t4

    31 de mayo de 2020 a las 22:26

  • Esta respuesta es incorrecta. La suposición no negativa no se puede hacer aquí, ya que no es el OP ni los futuros lectores lo afirmaron. Además, incluso estrictamente positivo no funciona aquí: [1, 10] se normalizará a [0.1, 1] en vez de [0,1].

    – Gulzar

    12 de mayo de 2021 a las 11:53


  • Gracias @Gulzar, soy el autor de esta respuesta y, sinceramente, me sorprendió que se votara 29 veces.

    – Albahaca Musa

    18 mayo 2021 a las 15:12

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad