Нормалізуйте стовпці кадру даних панд


226

У мене є фрейм даних у пандах, де кожен стовпець має різний діапазон значень. Наприклад:

df:

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
є функція застосування, наприклад frame.apply (f, ось = 1), де f - функція, яка робить щось із рядком ...
tschm

1
Нормалізація може бути не найбільш підходящим формулюванням, оскільки наукова документація scikit визначає це як "процес масштабування окремих зразків, щоб мати одиничну норму " (тобто рядок за рядком, якщо я правильно його визначив).
Skippy le Grand Gourou

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

Якщо ви відвідуєте це питання у 2020 році або пізніше, подивіться на відповідь @Poudel, ви отримаєте іншу відповідь щодо нормалізації, якщо ви використовуєте панди проти sklearn.
Bhishan Poudel

@Poudel це пов’язано з ddofаргументом?
fffrost

Відповіді:


223

Ви можете використовувати пакет 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 вчитися документації по попередній обробці даних: масштабування особливість в діапазон.


46
Я думаю, що це позбудеться назв стовпців, що може бути однією з причин, коли op в першу чергу використовується фрейми даних.
піт

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 Це неправильно. Код Сендмена нормалізує розмір стовпців та стовпців. Ви отримуєте неправильний результат, якщо переводите.
петезуріч

8
@petezurich Схоже, Сендман або Правен виправили свій код. На жаль, виправити коментарі неможливо;)
варильні панелі

397

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

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

використовувати нормалізацію min-max:

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

Редагування: Щоб вирішити деякі проблеми, потрібно сказати, що Pandas автоматично застосовує функцію, що відповідає вимогам, у коді вище.


16
мені подобається цей. він короткий, він виразний і він зберігає інформацію заголовка. але я думаю, що вам потрібно відняти хв і в знаменнику.
піт

6
Я не думаю, що це неправильно. Для мене це прекрасно працює - я не думаю, що означає () і std () потрібно повертати кадр даних для того, щоб це працювало, а повідомлення про помилку не означає, що вони не є фреймом даних є проблемою.
Strandtasche

24
це не стовпчаста нормалізація. це нормалізує всю матрицю в цілому, що дасть неправильні результати.
Nguai al

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

1
мені це теж подобається
Ісаак Сім

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Один кращий :-)
Абу Shoeb

4
Це не повинно бути вісь = 1, оскільки питання стовпців нормально нормалізується?
Nguai al

Ні, з документації : axis [...] 0 or 'index': apply function to each column. За замовчуванням насправді, axis=0тому цей однокласник можна написати ще коротше :-) Спасибі @tschm.
jorijnsmit

30

Якщо вам подобається використання пакету sklearn, ви можете зберегти імена стовпців та індексів, використовуючи 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
Зауважте, що ОП запитував діапазон [0..1], і це рішення масштабується до [-1..1]. Спробуйте це з масивом [-10, 10].
Олександр Сосновщенко

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

просто І явно
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 нормалізується лише у потрібних стовпцях


Однак якщо ви хочете навпаки , виберіть список стовпців, які НЕ хочете нормалізувати, ви можете просто створити список усіх стовпців і видалити ці непотрібні

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

ділення поточного значення на max не дасть вам правильної нормалізації, якщо хв не буде 0.
Піт

Я погоджуюся, але це те, про що просив ОТ (див. Його приклад)
Даніеле

11

Рішення, яке дають Сендман і Правен, дуже добре. Єдина проблема з цим, якщо у вас є категоричні змінні в інших стовпцях кадру даних, цей метод потребує деяких коригувань.

Моє рішення такого типу питань таке:

 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_estimation_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.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?

Не існує стандартного розрахунку відхилення в масштабі 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. Об'єкти, передані функціям, - це об'єкти серії, що мають індекс або індекс DataFrame (ось = 0), або стовпці (вісь = 1). Тип повернення залежить від того, чи передаються функції агрегати, або аргумент зменшення, якщо DataFrame порожній.

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


2
Було б добре пояснити, чому ваш код вирішує проблему ОП, щоб люди могли адаптувати стратегію, а не просто копіювати ваш код. Прочитайте, будь ласка, як я можу написати гарну відповідь?
Містер T

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.