将StandardScaler应用于数据集的部分

47

我想使用 sklearnStandardScaler。是否可以将其应用于某些特征列而不应用于其他列?

例如,假设我的 data 是:

data = pd.DataFrame({'Name' : [3, 4,6], 'Age' : [18, 92,98], 'Weight' : [68, 59,49]})

   Age  Name  Weight
0   18     3      68
1   92     4      59
2   98     6      49


col_names = ['Name', 'Age', 'Weight']
features = data[col_names]

我适配并转换数据

scaler = StandardScaler().fit(features.values)
features = scaler.transform(features.values)
scaled_features = pd.DataFrame(features, columns = col_names)

       Name       Age    Weight
0 -1.069045 -1.411004  1.202703
1 -0.267261  0.623041  0.042954
2  1.336306  0.787964 -1.245657

但是,这些名字实际上不是整数,而是字符串,我不想将它们标准化。如何仅对AgeWeight列应用fittransform方法?


1
我想提供一个更好的解决方案:已经接受的答案没有保留列名,因此不太好。应该使用这个一行代码:data[['Age', 'Weight']] = StandardScaler().fit_transform(data[['Age', 'Weight']])。 - Philipp Schwarz
6个回答

61

在 v0.20 中引入了ColumnTransformer,它可以将转换器应用于数组或 pandas DataFrame 的指定列。

import pandas as pd
data = pd.DataFrame({'Name' : [3, 4,6], 'Age' : [18, 92,98], 'Weight' : [68, 59,49]})

col_names = ['Name', 'Age', 'Weight']
features = data[col_names]

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler

ct = ColumnTransformer([
        ('somename', StandardScaler(), ['Age', 'Weight'])
    ], remainder='passthrough')

ct.fit_transform(features)

注意:它也有一个类似于Pipeline的速记版本make_column_transformer,它不需要命名转换器。

输出

-1.41100443,  1.20270298,  3.       
 0.62304092,  0.04295368,  4.       
 0.78796352, -1.24565666,  6.       

2
这是现在最好的答案(不需要您复制数据框) - kellyfj
6
好的回答!如果我使用pandas数据框进行操作,如何保留列名?有没有一种方法可以在最后不必重命名所有列? - DataBach
这正是我在寻找的,最佳答案且更快,虽然使用apply也是一个替代方案。 - user3065757
2
被接受的答案并没有保留列名,因此质量较差。相反,使用这个一行代码:data[['Age', 'Weight']] = StandardScaler().fit_transform(data[['Age', 'Weight']]) - Philipp Schwarz
要么保留列名 或者 保留列顺序,否则使用起来非常麻烦。目前,“passthrough”列被附加到末尾 并且 它们的名称被删除,因此很难处理生成的对象。 - pcko1
为了保留列名和顺序,请参考此问题的答案 - Aelius

46

更新:

目前最好的处理方法是使用ColumnTransformer,具体解释可以参考这里


首先创建你的数据框的一个副本:

scaled_features = data.copy()

不要在转换中包括“Name”列:

col_names = ['Age', 'Weight']
features = scaled_features[col_names]
scaler = StandardScaler().fit(features.values)
features = scaler.transform(features.values)

现在,不要创建新的数据框,而是将结果赋值给这两列:

scaled_features[col_names] = features
print(scaled_features)


        Age  Name    Weight
0 -1.411004     3  1.202703
1  0.623041     4  0.042954
2  0.787964     6 -1.245657

它能够工作,但我无法使用“inverse_transform”函数来使用这种方法获取初始值。'test = scaled_features.iloc[1,:]''test_inverse = scaler.inverse_transform(test)'我得到了错误:ValueError: operands could not be broadcast together with shapes (3,) (2,) (3,)。 - mitsi
1
scaler.inverse_transform(scaled_features[col_names].values) 对我有用。 - ayhan
我正在尝试使用第一行测试inverse_transform函数。 是的,它对我也起作用,但我失去了列名。如果我重新转换整个数据框,我可以插入它。但是,如果我只想inverse_transform第一行怎么办? - mitsi
如果我表达不够清晰,请原谅。当我提到“name”列时,我指的是包含名称的列(数据框的第二列,即我不想缩放的列),而不是列名。 - mitsi
是的 - mitsi

8
来晚了,但这是我喜欢的解决方案:
#load data
data = pd.DataFrame({'Name' : [3, 4,6], 'Age' : [18, 92,98], 'Weight' : [68, 59,49]})

#list for cols to scale
cols_to_scale = ['Age','Weight']

#create and fit scaler
scaler = StandardScaler()
scaler.fit(data[cols_to_scale])

#scale selected data
data[cols_to_scale] = scaler.transform(data[cols_to_scale])

3
我发现最简单的方法是:
from sklearn.preprocessing import StandardScaler
# I'm selecting only numericals to scale
numerical = temp.select_dtypes(include='float64').columns
# This will transform the selected columns and merge to the original data frame
temp.loc[:,numerical] = StandardScaler().fit_transform(temp.loc[:,numerical])

输出

         Age  Name    Weight
0 -1.411004     3  1.202703
1  0.623041     4  0.042954
2  0.787964     6 -1.245657

2
另一个选择是在缩放之前删除名称列,然后将其合并回来:
data = pd.DataFrame({'Name' : [3, 4,6], 'Age' : [18, 92,98], 'Weight' : [68, 59,49]})
from sklearn.preprocessing import StandardScaler

# Save the variable you don't want to scale
name_var = data['Name']

# Fit scaler to your data
scaler.fit(data.drop('Name', axis = 1))

# Calculate scaled values and store them in a separate object
scaled_values = scaler.transform(data.drop('Name', axis = 1))

data = pd.DataFrame(scaled_values, index = data.index, columns = data.drop('ID', axis = 1).columns)
data['Name'] = name_var

print(data)

2
一个更符合 Python 风格的做法是 -
from sklearn.preprocessing import StandardScaler
data[['Age','Weight']] = data[['Age','Weight']].apply(
                           lambda x: StandardScaler().fit_transform(x))
data 

输出 -

         Age  Name    Weight
0 -1.411004     3  1.202703
1  0.623041     4  0.042954
2  0.787964     6 -1.245657

我如何只对列“年龄”和“体重”应用fit和transform函数。我不知道OP想要做这些事情。 - hashcode55

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接