使用sklearn对pandas数据框列进行缩放
我有一个包含混合类型列的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'])
如果我把整个数据框传给scaler,它是可以工作的:
dfTest2 = dfTest.drop('C', axis = 1)
good_output = min_max_scaler.fit_transform(dfTest2)
good_output
我不明白为什么把一个系列传给scaler会失败。在我上面的完整代码中,我本希望只把一个系列传给scaler,然后将数据框的列设置为缩放后的系列。
9 个回答
你可以仅仅使用 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
正如pir在评论中提到的,.apply(lambda el: scale.fit_transform(el))
这个方法会产生以下警告:
弃用警告:在0.17版本中,传递一维数组作为数据已经不推荐使用,并且在0.19版本中会引发值错误。请根据你的数据进行重塑,如果你的数据只有一个特征,使用
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月(测试版本为pandas 0.23.4)--
正如Rob Murray在评论中提到的,在当前的(v0.23.4)版本中,.as_matrix()
会返回FutureWarning
。因此,应该用.values
来替代:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit_transform(dfTest[['A','B']].values)
-- 编辑 2019年5月(测试版本为pandas 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
像这样吗?
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
df = pd.DataFrame(scale.fit_transform(df.values), columns=df.columns, index=df.index)
这样做应该不会出现过时警告。
我不太确定之前的 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