Нормализовать столбцы панд данных


227

У меня есть датафрейм в пандах, где каждый столбец имеет различный диапазон значений. Например:

ДФ:

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

Любая идея, как я могу нормализовать столбцы этого кадра данных, где каждое значение находится между 0 и 1?

Мой желаемый результат:

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
есть функция apply, например frame.apply (f, axis = 1), где f - это функция, которая что-то делает со строкой ...
tschm

1
Нормализация может быть не самой подходящей формулировкой, поскольку документация scikit-learn определяет ее как «процесс масштабирования отдельных выборок для получения единичной нормы » (т. Е. Строка за строкой, если я правильно понял).
Скиппи ле Гран Гуру

Я не понимаю, почему масштабирование min_max считается нормализацией! нормальный должен иметь значение в смысле нормального распределения со средним нулем и дисперсией 1.
Полиция

Если вы посещаете этот вопрос в 2020 году или позже, посмотрите на ответ @Poudel, вы получите другой ответ на вопрос о нормализации, если вы используете pandas vs sklearn.
Бхишан Пудель

@ Пудель, это из-за ddofспора?
fffrost

Ответы:


224

Вы можете использовать пакет sklearn и связанные с ним утилиты предварительной обработки для нормализации данных.

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)

Для получения дополнительной информации см. Документацию scikit-learn по предварительной обработке данных: масштабирование функций до диапазона.


46
я думаю, что это избавит от имен столбцов, что может быть одной из причин, по которой операционная система в первую очередь использует кадры данных.
Питс

47
Это нормализует строки, а не столбцы, если вы сначала не транспонируете их. Для того, чтобы сделать то , что просит Q для:pd.DataFrame(min_max_scaler.fit_transform(df.T), columns=df.columns, index=df.index)
варочных панелей

26
@pietz, чтобы сохранить названия столбцов, смотрите этот пост . В основном заменить последнюю строку,df=pandas.DataFrame(x_scaled, columns=df.columns)
ijoseph

5
@hobs Это не правильно. Код Сэндмена нормализует по столбцам и по столбцам. Вы получите неправильный результат, если перенесете.
petezurich

8
@petezurich Похоже, Sandman или Правин исправили свой код. К сожалению, это не возможно исправить комментарии;)
hobs

399

один простой способ с помощью панд : (здесь я хочу использовать среднюю нормализацию)

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

использовать нормализацию min-max:

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

Изменить: Чтобы решить некоторые проблемы, необходимо сказать, что Pandas автоматически применяет функцию колонки в коде выше.


16
мне нравится этот. оно короткое, оно выразительное и сохраняет информацию заголовка. но я думаю, что вы должны также вычесть мин в знаменателе.
Питс

6
Я не думаю, что это неправильно. Работает прекрасно для меня - я не думаю, что mean () и std () должны возвращать фрейм данных, чтобы это работало, и ваше сообщение об ошибке не означает, что они не являются фреймами данных.
Strandtasche

24
это не столбцовая нормализация. это нормализует всю матрицу в целом, что даст неправильные результаты.
Нгуай Аль

6
Тоже сработало у меня красиво. @Nguaial, возможно, вы пытаетесь сделать это на матовой матрице, и в этом случае результат будет таким, как вы сказали. Но для кадров данных Pandas меры min, max, ... применяются по столбцам по умолчанию.
вспомогательный


51

На основании этого поста: /stats/70801/how-to-normalize-data-to-0-1-range

Вы можете сделать следующее:

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

Вам не нужно беспокоиться о том, являются ли ваши значения отрицательными или положительными. И значения должны быть красиво распределены между 0 и 1.


8
Будьте осторожны, когда значения min и max совпадают, ваш знаменатель равен 0, и вы получите значение NaN.
Хрушикеш Думал

36

Ваша проблема на самом деле является простым преобразованием, действующим на столбцы:

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

frame.apply(f, axis=0)

Или даже более кратко:

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

2
Один lambdaиз них самый лучший :-)
Абу Шоеб

4
разве это не должно быть ось = 1, поскольку вопрос заключается в нормализации по столбцам?
Нгуай Аль

Нет, из документации : axis [...] 0 or 'index': apply function to each column. На самом деле по умолчанию axis=0это одна строка может быть написана еще короче :-) Спасибо @tschm.
jorijnsmit

30

Если вам нравится использовать пакет sklearn, вы можете сохранить имена столбцов и индексов, используя pandas loc:

from sklearn.preprocessing import MinMaxScaler

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

27

Простое это красиво:

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

Отличное и на мой взгляд лучшее решение!
Мацей А. Беднарз

6
Обратите внимание, что OP запросил диапазон [0..1], и это решение масштабируется до диапазона [-1..1]. Попробуйте это с массивом [-10, 10].
Александр Сосновщенко

3
@ Александр Сосновщенко не совсем. Василий Муса полагает, что матрица ОП всегда неотрицательна, поэтому он дал это решение. Если какой-то столбец имеет отрицательную запись, этот код НЕ нормализуется до диапазона [-1,1]. Попробуйте это с массивом [-5, 10]. Правильный способ нормализации до [0,1] с отрицательными значениями был дан ответом Cinadf["A"] = (df["A"]-df["A"].min()) / (df["A"].max()-df["A"].min())
facuq

просто И явно
joshi123

Возможно, даже проще: df /= df.max()- при условии, что цель состоит в нормализации каждого столбца в отдельности.
n1k31t4

24

Вы можете создать список столбцов, которые вы хотите нормализовать

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

Ваш Pandas Dataframe теперь нормализуется только в тех столбцах, которые вы хотите


Однако , если вы хотите наоборот , выберите список столбцов, которые вы не хотите нормализовать, вы можете просто создать список всех столбцов и удалить эти ненужные

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

Я думаю, что лучший способ сделать это в пандах это просто

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

Изменить Если в вашем фрейме данных присутствуют отрицательные числа, вы должны использовать вместо

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

1
Если все значения столбца равны нулю, это не сработает
ahajib

деление текущего значения на максимальное не даст вам правильной нормализации, если минимальное значение не равно 0.
Pietz

Я согласен, но это то, о чем просил OT (см. Его пример)
Даниэль

11

Решение, данное Sandman и Praveen, очень хорошо. Единственная проблема в том, что если у вас есть категориальные переменные в других столбцах вашего фрейма данных, этот метод потребует некоторых настроек.

Мое решение этой проблемы заключается в следующем:

 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
Этот ответ полезен, потому что большинство примеров в Интернете применяют один скейлер ко всем столбцам, тогда как на самом деле это относится к ситуации, когда один скейлер, скажем MinMaxScaler, не должен применяться ко всем столбцам.
демонголем

10

Пример различных стандартизаций в Python.

Для справки посмотрите эту статью в Википедии: https://en.wikipedia.org/wiki/Unbiased_estima_of_standard_deviation

Пример данных

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

Нормализация с использованием панд (дает объективные оценки)

При нормализации мы просто вычитаем среднее и делим на стандартное отклонение.

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

Нормализация с использованием sklearn (дает необъективные оценки, отличные от панд)

Если вы сделаете то же самое с sklearnвами, вы получите РАЗНЫЕ выходные данные!

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

Делают ли предвзятые оценки sklearn машинное обучение менее мощным?

NO.

Официальная документация sklearn.preprocessing.scale гласит, что использование смещенной оценки НЕДОПУСТИМО, чтобы повлиять на производительность алгоритмов машинного обучения, и мы можем безопасно их использовать.

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.

Как насчет MinMax Scaling?

В масштабировании MinMax нет расчета стандартного отклонения. Таким образом, результат одинаков как для панд, так и для учёных.

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

Возможно, вы захотите, чтобы некоторые столбцы были нормализованы, а другие не изменились, как некоторые из задач регрессии, при которых метки данных или категориальные столбцы не изменились. Поэтому я предлагаю вам этот питонический способ (это комбинация ответов @shg и @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

Это всего лишь простая математика. Ответ должен быть простым, как показано ниже.

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)

Из документа панд структура DataFrame может применить операцию (функцию) к себе.

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

Применяет функцию вдоль входной оси DataFrame. Объекты, передаваемые в функции, являются объектами Series, имеющими индекс либо индекса DataFrame (axis = 0), либо столбцов (axis = 1). Тип возвращаемого значения зависит от того, передана ли агрегатная функция, или от аргумента Reduce, если DataFrame пуст.

Вы можете применить пользовательскую функцию для работы с DataFrame.


2
Было бы хорошо объяснить, почему ваш код решает проблему OP, чтобы люди могли адаптировать стратегию, а не просто копировать ваш код. Пожалуйста, прочитайте Как мне написать хороший ответ?
Мистер Т

2

Следующая функция вычисляет 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

Вот как вы делаете это по столбцам, используя понимание списка:

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

1

Вы можете просто использовать функцию pandas.DataFrame.transform 1 следующим образом:

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

Это решение не будет работать, если все значения отрицательны. Рассмотрим [-1, -2, -3]. Мы делим на -1, и теперь у нас есть [1,2,3].
Дэйв Лю


0

Вы можете сделать это в одну строку

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

он принимает среднее значение для каждого столбца, а затем вычитает его (среднее значение) из каждой строки (среднее значение для конкретного столбца вычитает только из его строки) и делит только среднее значение. Наконец, мы получаем нормализованный набор данных.


0

Pandas выполняет колоночную нормализацию по умолчанию. Попробуйте код ниже.

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

Выходные значения будут в диапазоне от 0 до 1.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.