跳至主要内容

数据科学中的预处理(第 2 部分):中心化、缩放与逻辑回归

在逻辑回归场景下,了解中心化与缩放是否有助于模型。
· 9分钟 阅读

使用 AI 探索

在本系列的第一篇文章中,我探讨了预处理在机器学习(ML)分类任务中的作用,并深入剖析了 k 近邻算法(k-NN)和葡萄酒质量数据集。您会看到,对数值数据进行中心化和缩放能提升 k-NN 在若干模型评估指标(如准确率)上的表现。您也会看到,预处理并非孤立进行,其价值只能在面向预测的 ML 流水线语境中加以评估。不过,上文仅在单一模型 k-NN 的语境下讨论了预处理的重要性。那时我们的模型表现显著提升,但是否总是如此?并不一定!本文将考察在另一个基础模型——逻辑回归——中,对数值数据进行缩放与中心化的作用。您可以回看上一篇和/或文末的术语表来温习要点。我们仍将使用葡萄酒质量数据集。文中所有示例均使用 Python。如果您尚不熟悉 Python,可在此查看我们的数据科学课程。我将使用 pandas 满足数据框需求,并使用 scikit-learn 完成机器学习相关工作。

我将先简要介绍回归,它既可用于预测数值变量,也可用于预测类别。随后介绍线性回归与逻辑回归,并使用后者来预测红酒品质。接着我们将检验在回归设置下,中心化与缩放是否能帮助模型。

Python 回归简明介绍

Python 中的线性回归

如上所述,回归通常用于根据一个数值变量来预测另一个数值变量。例如,下面我们对波士顿房价数据(scikit-learn 内置数据集)进行线性回归:此处自变量(x 轴)为房间数量,因变量(y 轴)为价格。

这样的回归如何运作?简而言之,机制如下:我们希望将模型 \(y = ax + b\) 拟合到数据 \((x_i,y_i)\),也就是在给定数据的情况下,找到最优的 \(a\) 和 \(b\)。在最常见的普通最小二乘(OLS)表述中,假设误差发生在因变量上。因此,通过最小化 \[SSE = \sum_i (y_i - (ax_i + b))^2\] 来求得最优的 \(a\) 和 \(b\),而这一优化通常借助名为梯度下降的算法实现。下面我们对波士顿房价数据做一个简单线性回归:

# Import necessary packages
import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('ggplot')
from sklearn import datasets
from sklearn import linear_model
import numpy as np

# Load data
boston = datasets.load_boston()
yb = boston.target.reshape(-1, 1)
Xb = boston['data'][:,5].reshape(-1, 1)

# Plot data
plt.scatter(Xb,yb)
plt.ylabel('value of house /1000 ($)')
plt.xlabel('number of rooms')

# Create linear regression object
regr = linear_model.LinearRegression()
# Train the model using the training sets
regr.fit( Xb, yb)

# Plot outputs
plt.scatter(Xb, yb,  color='black')
plt.plot(Xb, regr.predict(Xb), color='blue',
         linewidth=3)
plt.show()

Number of Rooms Graph

该回归刻画了数据整体的递增趋势,但并不深入。我们只使用了一个预测变量,其实可以使用更多;那样模型中将有 \(n\) 个系数 \(a_1,\ldots,a_n\),每个预测变量对应一个系数。值得注意的是,系数 \(a_i\) 的大小表明相应变量与目标变量的相关强度。

Python 中的逻辑回归

回归也可用于分类问题。其首个自然示例便是逻辑回归。在二分类(两个标签)中,我们可将标签视作 0 与 1。仍以 \(x\) 表示预测变量,逻辑回归模型由逻辑函数给出:\[F(x) = \frac{1}{1+e^{-(ax+b)}}.\] 这是一条 S 形曲线,下面给出一个示例。对任意 \(x\),若 \(F(x) <0.5\),则逻辑模型预测 y = 0;反之若 \(F(X) > 0.5\),模型预测 \(y = 1\)。同样地,若我们有多个预测变量,则有 \(n\) 个系数 \(a_1,\ldots,a_n\),每个预测变量对应一个系数。在这种情况下,系数 \(a_i\) 的大小表明相应变量对预测结果的影响强度。

# Synthesize data
X1 = np.random.normal(size=150)
y1 = (X1 > 0).astype(np.float)
X1[X1 > 0] *= 4
X1 += .3 * np.random.normal(size=150)
X1= X1.reshape(-1, 1)

# Run the classifier
clf = linear_model.LogisticRegression()
clf.fit(X1, y1)

# Plot the result
plt.scatter(X1.ravel(), y1, color='black', zorder=20 , alpha = 0.5)
plt.plot(X1_ordered, clf.predict_proba(X1_ordered)[:,1], color='blue' , linewidth = 3)
plt.ylabel('target variable')
plt.xlabel('predictor variable')
plt.show()

Predictor Variable Graph

逻辑回归与数据缩放:葡萄酒数据集

既然我们已了解逻辑回归的机制,那就把它应用到可口的葡萄酒数据集上吧。我先导入数据,并绘制目标变量(好酒/差酒)作为回顾:

# Import necessary modules
from sklearn import linear_model
from sklearn.cross_validation import train_test_split

# Load data
df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv ' , sep = ';')
X = df.drop('quality' , 1).values #drop target variable
y1 = df['quality'].values
y = y1 <= 5 # is the rating <= 5?

# plot histograms of original target variable
# and aggregated target variable
plt.figure(figsize=(20,5));
plt.subplot(1, 2, 1 );
plt.hist(y1);
plt.xlabel('original target value')
plt.ylabel('count')
plt.subplot(1, 2, 2);
plt.hist(y)
plt.xlabel('aggregated target value')
plt.show()

Target Value Graphs

现在让我们运行逻辑回归,看看表现如何!

# Split the data into test and training sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

#initial logistic regression model
lr = linear_model.LogisticRegression()

# fit the model
lr = lr.fit(X_train, y_train)
print('Logistic Regression score for training set: %f' % lr.score(X_train, y_train))
from sklearn.metrics import classification_report
y_true, y_pred = y_test, lr.predict(X_test)
print(classification_report(y_true, y_pred))
Logistic Regression score for training set: 0.752932
             precision    recall  f1-score   support

      False       0.78      0.74      0.76       179
       True       0.69      0.74      0.71       141

avg / total       0.74      0.74      0.74       320

开箱即用的逻辑回归就优于 K-NN(无论是否缩放)。现在让我们对数据进行缩放并再次进行逻辑回归:

from sklearn.preprocessing import scale
Xs = scale(X)
Xs_train, Xs_test, y_train, y_test = train_test_split(Xs, y, test_size=0.2, random_state=42)
lr_2 = lr.fit(Xs_train, y_train)
print('Scaled Logistic Regression score for test set: %f' % lr_2.score(Xs_test, y_test))
y_true, y_pred = y_test, lr_2.predict(Xs_test)
print(classification_report(y_true, y_pred))
Scaled Logistic Regression score for test set: 0.740625
             precision    recall  f1-score   support

      False       0.79      0.74      0.76       179
       True       0.69      0.74      0.72       141

avg / total       0.74      0.74      0.74       320

这很有意思!对逻辑回归而言,数据缩放并未带来性能提升。为什么会这样,尤其是此前我们看到 k 近邻在缩放后性能显著提升?原因在于:如果存在取值范围很大但对目标变量影响不大的预测变量,回归算法会将相应系数 \(a_i\) 调小,从而减弱其对预测的影响。k 近邻并没有这样的内置机制,因此我们非常需要对数据进行缩放。

在下一篇文章中,我将通过合成数据集、加入噪声,并考察随着噪声强度变化,中心化与缩放如何改变两种模型的表现,以此来解析 k-NN 与逻辑回归在中心化与缩放上的巨大差异。

在下面的交互窗口中,您可以自己动手尝试。若需要,您可以通过设置 sc = True 来对数据进行缩放。然后运行整个脚本,以得到逻辑回归模型的准确率及分类报告。

# Set sc = True to scale your features 
sc = False 

# Load data 
df = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv ' , sep = ';') 
X = df.drop('quality' , 1).values # drop target variable 

# Here we scale, if desired 
if sc == True: 
  X = scale(X) 
  
# Target value 
y1 = df['quality'].values # original target variable 
y = y1 <= 5  # new target variable: is the rating <= 5? 

# Split the data into a test set and a training set X_train, X_test, y_train, y_test = 
train_test_split(X, y, test_size=0.2, random_state=42) 

# Train logistic regression model and print performance on the test set 
lr = linear_model.LogisticRegression() 
lr = lr.fit(X_train, y_train) 
print('Logistic Regression score for training set: %f' % lr.score(X_train, y_train)) 
y_true, y_pred = y_test, lr.predict(X_test) 
print(classification_report(y_true, y_pred)) 

术语表

监督学习:从预测变量中推断目标变量的任务。例如,从“年龄”“性别”“是否吸烟”等预测变量推断目标变量“是否患有心脏病”。

分类任务:若目标变量由类别构成(如“点击”或“未点击”、“恶性”或“良性”肿瘤),则该监督学习任务为分类任务。

回归任务:若目标变量为连续变化的变量(如房价)或有序的类别变量(如“葡萄酒质量评分”),则该监督学习任务为回归任务。

k 近邻:一种用于分类任务的算法,将数据点赋予其 k 个最近邻居的多数表决所得的标签。

预处理:数据科学家为使数据更适合后续用途而进行的各种操作。例如,在对推特数据进行情感分析前,您可能需要去除任何 html 标签、空白字符、展开缩写,并将推文切分为其所含词语的列表。

中心化与缩放:二者均为对数值数据的预处理形式,即由数字构成的数据(相对例如类别或字符串);中心化是指用变量的均值去减每个数据点,使新变量的均值为 0;缩放是指将每个数据点乘以某个常数以改变数据范围。请参见正文了解其重要性与示例。

本文由 Jupyter 笔记本生成。您可在此处下载该笔记本。

主题