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


131

Припустимо, у мене є кадр даних панди df:

Я хочу обчислити середнє значення стовпця кадру даних.

Це легко:

df.apply(average) 

то діапазон стовпців мудрий max (col) - min (col). Знову це легко:

df.apply(max) - df.apply(min)

Тепер для кожного елемента я хочу відняти середнє значення його стовпця та розділити на діапазон його стовпця. Я не впевнений, як це зробити

Будь-яка допомога / покажчики високо цінується.

Відповіді:


225
In [92]: df
Out[92]:
           a         b          c         d
A  -0.488816  0.863769   4.325608 -4.721202
B -11.937097  2.993993 -12.916784 -1.086236
C  -5.569493  4.672679  -2.168464 -9.315900
D   8.892368  0.932785   4.535396  0.598124

In [93]: df_norm = (df - df.mean()) / (df.max() - df.min())

In [94]: df_norm
Out[94]:
          a         b         c         d
A  0.085789 -0.394348  0.337016 -0.109935
B -0.463830  0.164926 -0.650963  0.256714
C -0.158129  0.605652 -0.035090 -0.573389
D  0.536170 -0.376229  0.349037  0.426611

In [95]: df_norm.mean()
Out[95]:
a   -2.081668e-17
b    4.857226e-17
c    1.734723e-17
d   -1.040834e-17

In [96]: df_norm.max() - df_norm.min()
Out[96]:
a    1
b    1
c    1
d    1

Чи є спосіб це зробити, якщо ви хочете нормалізувати підмножину? Скажіть цей рядок Aі Bє частиною більшого фактора групування, який ви хочете нормалізувати окремо від Cта D.
Амюнімус

Виберіть підмножину та обчисліть, як раніше. Див. Pandas.pydata.org/pandas-docs/stable/indexing.html про індексацію та вибір даних
Wouter Overmeire

17
Якщо вам потрібно, щоб ваші значення були> 0: df_norm = (df - df.min ()) / (df.max () - df.min ())
Dayvid Oliveira

1
у перших дужках має бути df_norm = (df - df.min ()) / (df.max () - df.min ()), а не df.mean (), щоб отримати значення від 0 до 1
jnPy

2
Якщо у вашому фреймі даних є рядки в деяких стовпцях, дивіться цю відповідь
netskink

73

Якщо ви не заперечуєте над тим sklearn, щоб імпортувати бібліотеку, я б рекомендував метод, про який говорили в цьому блозі.

import pandas as pd
from sklearn import preprocessing

data = {'score': [234,24,14,27,-74,46,73,-18,59,160]}
cols = data.columns
df = pd.DataFrame(data)
df

min_max_scaler = preprocessing.MinMaxScaler()
np_scaled = min_max_scaler.fit_transform(df)
df_normalized = pd.DataFrame(np_scaled, columns = cols)
df_normalized

2
посилання на допис у блозі мертве. у вас є робочий?
ринки

3
Відповідний метод створення нормалізованих одиниць нормалізованих даних називається StandardScaler.
abeboparebop

Я знайшов подібне рішення в іншому місці. Проблема полягала в тому, що в np_scaled частині вона відображала помилку, очікуючи 2D масив, але вхід - 1D масив, і рекомендується використовувати переформатування (-1,1). Будь-яка ідея, як вирішити це як переформатування, також не працює.?
мертвий код

Ви можете отримати попередження залежно від того, з якою версією numpy & sklearn ви працюєте, але в цілому це має спрацювати np_scaled = min_max_scaler.fit_transform(df.score.astype(float).values.reshape(-1, 1))
Jaeyoung Chun

33

Ви можете використовувати applyдля цього, і це трохи акуратніше:

import numpy as np
import pandas as pd

np.random.seed(1)

df = pd.DataFrame(np.random.randn(4,4)* 4 + 3)

          0         1         2         3
0  9.497381  0.552974  0.887313 -1.291874
1  6.461631 -6.206155  9.979247 -0.044828
2  4.276156  2.002518  8.848432 -5.240563
3  1.710331  1.463783  7.535078 -1.399565

df.apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))

          0         1         2         3
0  0.515087  0.133967 -0.651699  0.135175
1  0.125241 -0.689446  0.348301  0.375188
2 -0.155414  0.310554  0.223925 -0.624812
3 -0.484913  0.244924  0.079473  0.114448

Крім того, це добре працює groupby, якщо вибрати відповідні стовпці:

df['grp'] = ['A', 'A', 'B', 'B']

          0         1         2         3 grp
0  9.497381  0.552974  0.887313 -1.291874   A
1  6.461631 -6.206155  9.979247 -0.044828   A
2  4.276156  2.002518  8.848432 -5.240563   B
3  1.710331  1.463783  7.535078 -1.399565   B


df.groupby(['grp'])[[0,1,2,3]].apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))

     0    1    2    3
0  0.5  0.5 -0.5 -0.5
1 -0.5 -0.5  0.5  0.5
2  0.5  0.5  0.5 -0.5
3 -0.5 -0.5 -0.5  0.5

2

Трохи модифікований від: Пам’ять даних Python Pandas: нормалізувати дані між 0,01 і 0,99? але з деяких коментарів він вважав це доречним (вибачте, якщо вважають репостом, хоча ...)

Я хотів налаштувати нормалізацію в тому, що регулярний перцентиль дати або z-балу не був адекватним. Іноді я знав, що таке можливі максимум і хв для населення, і тому хотів визначити це, крім мого зразка, чи іншого середини, чи будь-чого іншого! Це часто може бути корисним для масштабування та нормалізації даних для нейронних мереж, де ви хочете, щоб усі входи були від 0 до 1, але деякі ваші дані, можливо, потрібно буде масштабувати більш налаштованим способом ... тому, що процентилі та stdevs передбачають обкладинку вашої вибірки населення, але іноді ми знаємо, що це неправда. Це також було дуже корисно для мене під час візуалізації даних у теплових картах. Тому я побудував власну функцію (тут використовуються додаткові кроки в коді, щоб зробити її максимально зрозумілою):

def NormData(s,low='min',center='mid',hi='max',insideout=False,shrinkfactor=0.):    
    if low=='min':
        low=min(s)
    elif low=='abs':
        low=max(abs(min(s)),abs(max(s)))*-1.#sign(min(s))
    if hi=='max':
        hi=max(s)
    elif hi=='abs':
        hi=max(abs(min(s)),abs(max(s)))*1.#sign(max(s))

    if center=='mid':
        center=(max(s)+min(s))/2
    elif center=='avg':
        center=mean(s)
    elif center=='median':
        center=median(s)

    s2=[x-center for x in s]
    hi=hi-center
    low=low-center
    center=0.

    r=[]

    for x in s2:
        if x<low:
            r.append(0.)
        elif x>hi:
            r.append(1.)
        else:
            if x>=center:
                r.append((x-center)/(hi-center)*0.5+0.5)
            else:
                r.append((x-low)/(center-low)*0.5+0.)

    if insideout==True:
        ir=[(1.-abs(z-0.5)*2.) for z in r]
        r=ir

    rr =[x-(x-0.5)*shrinkfactor for x in r]    
    return rr

Це займе серію панд, або навіть просто список і нормалізує його до вказаних низьких, центральних та високих точок. також є фактор скорочення! щоб дозволити масштабування даних подалі від кінцевих точок 0 і 1 (мені довелося це робити, комбінуючи кольорові карти в matplotlib: Один pcolormesh з більш ніж однією кольоровою картою за допомогою Matplotlib ) Тож ви, ймовірно, можете побачити, як працює код, але в основному ви кажете, що ви мають значення [-5,1,10] у вибірці, але хочуть нормалізуватися виходячи з діапазону від -7 до 7 (тому все, що перевищує 7, наше "10" трактується як 7 ефективно) із серединою 2, але зменшіть його до розміру кольорової карти 256 RGB:

#In[1]
NormData([-5,2,10],low=-7,center=1,hi=7,shrinkfactor=2./256)
#Out[1]
[0.1279296875, 0.5826822916666667, 0.99609375]

Він також може перетворити ваші дані зсередини ... Це може здатися дивним, але я вважаю це корисним для теплової карти. Скажіть, що вам потрібно темніший колір для значень, ближчих до 0, а не привіт / низький. Ви можете нагрівати карту на основі нормалізованих даних, де insideout = True:

#In[2]
NormData([-5,2,10],low=-7,center=1,hi=7,insideout=True,shrinkfactor=2./256)
#Out[2]
[0.251953125, 0.8307291666666666, 0.00390625]

Тож зараз "2", який знаходиться найближче до центру, визначений як "1", є найвищим значенням.

У будь-якому разі, я вважав, що моя заява є доречною, якщо ви хочете змінити масштаб даних іншими способами, які можуть мати для вас корисні програми.


Ви можете замінити всі оператори if / else на словник із функціями . Виглядає трохи чистіше.
Роальд

це досить акуратно, я буду мати це на увазі наступного разу, дякую!
Vlox

0

Це так, як ви це робите в стовпцях:

[df[col].update((df[col] - df[col].min()) / (df[col].max() - df[col].min())) for col in df.columns]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.