Подтвердить что ты не робот

Pandas масштабирование столбцов dataframe с помощью sklearn

У меня есть фреймворк pandas со столбцами смешанного типа, и я хотел бы применить sklearn min_max_scaler к некоторым столбцам. В идеале я хотел бы сделать эти преобразования на месте, но пока не понял способ сделать это. Я написал следующий код, который работает:

import pandas as pd
import numpy as np
from sklearn import preprocessing

scaler = preprocessing.MinMaxScaler()

dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],'B':[103.02,107.26,110.35,114.23,114.68], 'C':['big','small','big','small','small']})
min_max_scaler = preprocessing.MinMaxScaler()

def scaleColumns(df, cols_to_scale):
    for col in cols_to_scale:
        df[col] = pd.DataFrame(min_max_scaler.fit_transform(pd.DataFrame(dfTest[col])),columns=[col])
    return df

dfTest

    A   B   C
0    14.00   103.02  big
1    90.20   107.26  small
2    90.95   110.35  big
3    96.27   114.23  small
4    91.21   114.68  small

scaled_df = scaleColumns(dfTest,['A','B'])
scaled_df

A   B   C
0    0.000000    0.000000    big
1    0.926219    0.363636    small
2    0.935335    0.628645    big
3    1.000000    0.961407    small
4    0.938495    1.000000    small

Мне интересно, если это предпочтительный/самый эффективный способ сделать это преобразование. Есть ли способ использовать df.apply, что было бы лучше?

Я также удивлен, что не могу получить следующий код для работы:

bad_output = min_max_scaler.fit_transform(dfTest['A'])

Если я передаю полный кадр данных в скаляр, он работает:

dfTest2 = dfTest.drop('C', axis = 1) good_output = min_max_scaler.fit_transform(dfTest2) good_output

Я смущен, почему сбой серии с масштабированием не получается. В моем полном рабочем коде выше я надеялся просто передать серию в scaler, а затем установить столбец dataframe = в масштабированную серию. Я видел, что этот вопрос задал несколько других мест, но не нашел хорошего ответа. Любая помощь в понимании того, что здесь происходит, будет очень признательна!

4b9b3361

Ответ 1

Я не уверен, что предыдущие версии pandas предотвратили это, но теперь следующий сниппет отлично работает для меня и производит именно то, что вы хотите, без использования apply

>>> import pandas as pd
>>> from sklearn.preprocessing import MinMaxScaler


>>> scaler = MinMaxScaler()

>>> dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],
                           'B':[103.02,107.26,110.35,114.23,114.68],
                           'C':['big','small','big','small','small']})

>>> dfTest[['A', 'B']] = scaler.fit_transform(dfTest[['A', 'B']])

>>> dfTest
          A         B      C
0  0.000000  0.000000    big
1  0.926219  0.363636  small
2  0.935335  0.628645    big
3  1.000000  0.961407  small
4  0.938495  1.000000  small

Ответ 2

Как это?

dfTest = pd.DataFrame({
           'A':[14.00,90.20,90.95,96.27,91.21],
           'B':[103.02,107.26,110.35,114.23,114.68], 
           'C':['big','small','big','small','small']
         })
dfTest[['A','B']] = dfTest[['A','B']].apply(
                           lambda x: MinMaxScaler().fit_transform(x))
dfTest

    A           B           C
0   0.000000    0.000000    big
1   0.926219    0.363636    small
2   0.935335    0.628645    big
3   1.000000    0.961407    small
4   0.938495    1.000000    small

Ответ 3

Как уже упоминалось в комментарии .apply(lambda el: scale.fit_transform(el)) метод .apply(lambda el: scale.fit_transform(el)) выдаст следующее предупреждение:

DeprecationWarning: Передача 1d-массивов, поскольку данные устарели в 0,17 и вызовет ValueError в 0,19. Измените ваши данные, используя X.reshape(-1, 1), если ваши данные имеют одну функцию, или X.reshape(1, -1), если он содержит один образец.

Преобразование ваших столбцов в пустые массивы должно сделать эту работу (я предпочитаю StandardScaler):

from sklearn.preprocessing import StandardScaler
scale = StandardScaler()

dfTest[['A','B','C']] = scale.fit_transform(dfTest[['A','B','C']].as_matrix())

Редактировать ноябрь 2018 г. (протестировано для панд 0.23.4)

Как упоминает Роб Мюррей в комментариях, в текущей (v0.23.4) версии pandas .as_matrix() возвращает FutureWarning. Поэтому его следует заменить на .values:

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

scaler.fit_transform(dfTest[['A','B']].values)

Редактировать май 2019 г. (протестировано для панд 0.24.2)

Как упоминает в комментариях 0.24.0 "Начиная с 0.24.0, рекомендуется использовать .to_numpy() вместо .values ".

Обновленный пример:

import pandas as pd
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
dfTest = pd.DataFrame({
               'A':[14.00,90.20,90.95,96.27,91.21],
               'B':[103.02,107.26,110.35,114.23,114.68],
               'C':['big','small','big','small','small']
             })
dfTest[['A', 'B']] = scaler.fit_transform(dfTest[['A','B']].to_numpy())
dfTest
      A         B      C
0 -1.995290 -1.571117    big
1  0.436356 -0.603995  small
2  0.460289  0.100818    big
3  0.630058  0.985826  small
4  0.468586  1.088469  small

Ответ 4

Вы можете сделать это, используя только pandas:

In [235]:
dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],'B':[103.02,107.26,110.35,114.23,114.68], 'C':['big','small','big','small','small']})
df = dfTest[['A', 'B']]
df_norm = (df - df.min()) / (df.max() - df.min())
print df_norm
print pd.concat((df_norm, dfTest.C),1)

          A         B
0  0.000000  0.000000
1  0.926219  0.363636
2  0.935335  0.628645
3  1.000000  0.961407
4  0.938495  1.000000
          A         B      C
0  0.000000  0.000000    big
1  0.926219  0.363636  small
2  0.935335  0.628645    big
3  1.000000  0.961407  small
4  0.938495  1.000000  small

Ответ 5

df = pd.DataFrame(scale.fit_transform(df.values), columns=df.columns, index=df.index)

Это должно работать без предупреждений об амортизации.

Ответ 6

Обратите внимание, что sklearn использует смещенную оценку для стандартного отклонения. Рассмотрим следующий пример нормализации:

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 вы получите РАЗНЫЕ выходные данные!

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, использование смещенной оценки НЕПРАВИЛЬНО влияет на производительность алгоритмов машинного обучения, и мы можем безопасно их использовать.