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


131

Предположим, у меня есть фрейм данных pandas 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.
Amyunimus

Выберите подмножество и вычислите, как раньше. См. Pandas.pydata.org/pandas-docs/stable/indexing.html о том, как индексировать и выбирать данные
Воутер Овермейр,

17
Если вам нужно, чтобы ваши значения были> 0: df_norm = (df - df.min ()) / (df.max () - df.min ())
Дайвид Оливейра 02 дек.15,

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 01

Я нашел подобное решение в другом месте. Проблема заключалась в том, что в части np_scaled отображалась ошибка, ожидающая 2D-массива, но входные данные - 1D-массив, и мы рекомендовали использовать reshape (-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 Dataframe: нормализовать данные между 0,01 и 0,99? но из некоторых комментариев подумал, что это актуально (извините, если это считается репостом ...)

Я хотел, чтобы индивидуальная нормализация в этом обычном процентиле данных или z-балла была недостаточной. Иногда я знал, каковы возможные максимумы и минимумы популяции, и поэтому хотел определить их, отличные от моей выборки, или другую среднюю точку, или что-то еще! Это часто может быть полезно для изменения масштаба и нормализации данных для нейронных сетей, где вы можете захотеть, чтобы все входные данные находились в диапазоне от 0 до 1, но некоторые из ваших данных, возможно, потребуется масштабировать более индивидуально ... потому что процентили и стандартные отклонения предполагают, что ваши образцы покрывают населения, но иногда мы знаем, что это неправда. Это также было очень полезно для меня при визуализации данных на тепловых картах. Итак, я создал собственную функцию (использовал дополнительные шаги в коде здесь, чтобы сделать его максимально читаемым):

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: Single 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.