用sklearn缩放的pandas数据框列


137

我有一个带有混合类型列的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

我很困惑为什么将系列传递给定标器会失败。在上面的完整工作代码中,我希望只将一个系列传递给缩放器,然后将dataframe column =设置为缩放的序列。我已经看到这个问题在其他几个地方问过,但找不到一个好的答案。任何帮助了解这里发生的事情将不胜感激!


1
如果这样做,是否可行bad_output = min_max_scaler.fit_transform(dfTest['A'].values)?访问该values属性将返回一个numpy数组,由于某些原因,有时scikit学习api将正确调用使pandas返回一个numpy数组的正确方法,而有时则不会。
EdChum 2014年

熊猫的数据框是相当复杂的对象,其约定与scikit-learn的约定不匹配。如果将所有内容都转换为NumPy数组,则scikit-learn的使用将变得更加容易。
Fred Foo)2014年

@edChum- bad_output = in_max_scaler.fit_transform(dfTest['A'].values)也不起作用。@larsmans-是的,我想过要走这条路线,这似乎很麻烦。我不知道Pandas可以将完整的数据帧传递给sklearn函数,而不是一系列,这是否是一个bug。我对数据框的理解是,这是系列的决定。在“用于数据分析的Python”一书中读到,它指出,熊猫建立在numpy之上,以使其易于在以NumPy为中心的应用中使用。
flyingmeatball 2014年

Answers:


214

我不确定以前的版本是否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

80
整齐!更通用的版本df[df.columns] = scaler.fit_transform(df[df.columns])
citynorman '17

6
@RajeshThevar外部括号是熊猫的典型选择器括号,告诉熊猫从数据框中选择列。内括号表示列表。您正在将列表传递给pandas选择器。如果仅使用单括号(一个列名后接另一个,并用逗号分隔),pandas会将其解释为好像您正试图从具有多级列(MultiIndex)的数据框中选择一列,并且会抛出键错误。

1
如果您想确切地了解pandas如何实现此索引逻辑以及为什么值元组与列表的解释方式不同,可以添加到@ken的答案中,您可以查看DataFrames如何实现该__getitem__方法。具体来说,您可以打开ipython并执行pd.DataFrame.__getitem__??;您当然导入了熊猫作为pd之后;)
LetsPlayYahtzee '18

4
切记:对于使用培训/测试数据拆分的用户,您只希望适合您的培训数据,而不适合测试数据。
David J.

1
要缩放除timestamps列之外的所有内容,请与columns =df.columns.drop('timestamps') df[df.columns] = scaler.fit_transform(df[df.columns]
intotecho '19

19

像这样?

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
运行此脚本时,会收到很多DeprecationWarnings。应该如何更新?
pir

请参阅下面的@LetsPlayYahtzee的答案
AJP

2
一个更简单的版本:dfTest [[ 'A', 'B'] = dfTest [[ 'A', 'B']]申请
亚历山大V.

12

正如pir的评论中提到的那样-该.apply(lambda el: scale.fit_transform(el))方法将产生以下警告:

DeprecationWarning:在0.17中弃用1d数组作为数据,它将在0.19中引发ValueError。如果数据具有单个功能,则使用X.reshape(-1,1)来重塑数据,如果包含单个样本,则使用X.reshape(1,-1)来重塑数据。

将您的列转换为numpy数组应该可以完成这项工作(我更喜欢StandardScaler):

from sklearn.preprocessing import StandardScaler
scale = StandardScaler()

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

- 编辑 2018年11月(已针对熊猫0.23.4测试)-

作为罗布·默里提到的意见,大熊猫的电流(v0.23.4)版本.as_matrix()的回报FutureWarning。因此,应将其替换为.values

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

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

- 编辑 2019年5月(已针对熊猫0.24.2测试)-

正如joelostblom在评论中提到的那样:“因此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

1
使用.values代替.as_matrix()作为as_matrix()现在给一个FutureWarning
Rob Murray


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

这应该在没有折旧警告的情况下起作用。


7

您只能使用以下方法进行操作 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

6
我知道我可以在大熊猫中做到这一点,但我可能最终还是想使用另一种不容易写自己的sklearn方法。我比找出一个更简单的解决方案更感兴趣的是弄清楚为什么申请系列作品不如我预期的那样有效。我的下一步将是运行RandomForestRegressor,并且我想确保自己了解Pandas和sklearn如何一起工作。
flyingmeatball,2014年

5
该答案很危险,因为df.max() - df.min()可以为0,从而导致异常。而且,df.min()计算两次是低效率的。请注意,这df.ptp()等效于df.max() - df.min()
Acumenus

3

我知道这是一个很老的评论,但仍然:

不要使用单括号(dfTest['A']),而应使用双括号(dfTest[['A']])

即:min_max_scaler.fit_transform(dfTest[['A']])

我相信这会取得理想的结果。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.