首页 > 代码库 > sklearn基础知识-准备阶段

sklearn基础知识-准备阶段

6.标签特征二元化

处理分类变量还有另一种方法,不需要通过OneHotEncoder,我们可以用LabelBinarizer。

这是一个阈值与分类变量组合的方法。
In [1]:
from sklearn import datasets as d
iris = d.load_iris()
target = iris.target
How to do it...
导入LabelBinarizer()创建一个对象:
In [2]:
from sklearn.preprocessing import LabelBinarizer
label_binarizer = LabelBinarizer()
现在,将因变量的值转换成一个新的特征向量:

In [3]:
new_target = label_binarizer.fit_transform(target)
让我们看看new_target和label_binarizer对象的结果:

In [4]:
new_target.shape
Out[4]:
(150, 3)
In [5]:
new_target[:5]

In [6]:
new_target[-5:]

In [9]:
label_binarizer.classes_
Out[9]:
array([0, 1, 2])

iris的因变量基数为3,就是说有三种值,

当LabelBinarizer将 N×1N×1 向量转换成 N×CN×C 矩阵时, CC 就是 N×1N×1 向量的基数。

需要注意的是,当label_binarizer处理因变量之后,再转换基数以外的值都是[0,0,0]:

In [15]:
label_binarizer.transform([4])
Out[15]:
array([[0, 0, 0]])
There‘s more...
0和1并不一定都是表示因变量中的阳性和阴性实例。例如,如果我们需要用1000表示阳性值,用-1000表示阴性值,我们可以用label_binarizer处理:


In [22]:
label_binarizer = LabelBinarizer(neg_label=-1000, pos_label=1000)
label_binarizer.fit_transform(target)[:5]

7.处理缺失值
scikit-learn有一些常见的计算方法,它可以对现有数据进行变换填补NA值。
In [2]:
from sklearn import datasets
import numpy as np
iris = datasets.load_iris()
iris_X = iris.data
masking_array = np.random.binomial(1, .25, iris_X.shape).astype(bool)
iris_X[masking_array] = np.nan
In [3]:
masking_array[:5]

In [4]:
iris_X[:5]
In [5]:
from sklearn import preprocessing
impute = preprocessing.Imputer()
iris_X_prime = impute.fit_transform(iris_X)
iris_X_prime[:5]

默认是均值mean,一共是三种:


均值mean(默认方法)
中位数median
众数most_frequent
scikit-learn会用指定的方法计算数据集中的每个缺失值,然后把它们填充好。


例如,用median方法重新计算iris_X,重新初始化impute即可:


In [9]:
impute = preprocessing.Imputer(strategy=‘median‘)
iris_X_prime = impute.fit_transform(iris_X)
iris_X_prime[:5]
In [10]:
iris_X[np.isnan(iris_X)] = -1
iris_X[:5]


In [11]:
impute = preprocessing.Imputer(missing_values=-1)
iris_X_prime = impute.fit_transform(iris_X)
iris_X_prime[:5]
Out[11]:
array([[ 5.1       ,  3.05221239,  1.4       ,  0.2       ],
       [ 4.9       ,  3.05221239,  1.4       ,  0.2       ],
       [ 4.7       ,  3.2       ,  1.3       ,  0.2       ],
       [ 5.86306306,  3.1       ,  1.5       ,  1.21388889],
       [ 5.        ,  3.6       ,  3.82685185,  0.2       ]])
There‘s more...
pandas库也可以处理缺失值,而且更加灵活,但是重用性较弱:


In [12]:
import pandas as pd
iris_X[masking_array] = np.nan
iris_df = pd.DataFrame(iris_X, columns=iris.feature_names)
iris_df.fillna(iris_df.mean())[‘sepal length (cm)‘].head(5)
Out[12]:
0    5.100000
1    4.900000
2    4.700000
3    5.863063
4    5.000000
Name: sepal length (cm), dtype: float64
其灵活性在于,fillna可以填充任意统计参数值:


In [13]:
iris_df.fillna(iris_df.max())[‘sepal length (cm)‘].head(5)
8.用管线命令处理多个步骤
管线命令可以把多个步骤组合成一个对象执行。
这样可以更方便灵活地调节和控制整个模型的配置,而不只是一个一个步骤调节。

In [1]:
from sklearn import datasets
import numpy as np
mat = datasets.make_spd_matrix(10)
masking_array = np.random.binomial(1, .1, mat.shape).astype(bool)
mat[masking_array] = np.nan
mat[:4, :4]
不用管道命令:
In [2]:
from sklearn import preprocessing
impute = preprocessing.Imputer()
scaler = preprocessing.StandardScaler()
mat_imputed = impute.fit_transform(mat)
mat_imputed[:4, :4]

In [5]:
mat_imp_and_scaled = scaler.fit_transform(mat_imputed)
mat_imp_and_scaled[:4, :4]

现在我们用pipeline来演示:
In [6]:
from sklearn import pipeline
pipe = pipeline.Pipeline([(‘impute‘, impute), (‘scaler‘, scaler)])
我们看看pipe的内容。和前面介绍一致,管线命令定义了处理步骤:
In [7]:
pipe
Out[7]:
Pipeline(steps=[(‘impute‘, Imputer(axis=0, copy=True, missing_values=‘NaN‘, strategy=‘mean‘, verbose=0)), 
(‘scaler‘, StandardScaler(copy=True, with_mean=True, with_std=True))])
然后在调用pipe的fit_transform方法,就可以把多个步骤组合成一个对象了:
In [10]:
new_mat = pipe.fit_transform(mat)
new_mat[:4, :4]

In [11]:
np.array_equal(new_mat, mat_imp_and_scaled)
Out[11]:
True
pipeline最重要的函数也不外乎下面三个:

fit
transform
fit_transform
具体来说,如果管线命令有N个对象,前N-1个对象必须实现fit和transform,
第N个对象至少实现fit。否则就会出现错误。
使用管线命令的理由主要有两点:

首先是方便。
其次,就是使用交叉验证。模型可以变得很复杂。如果管线命令中的一个步骤调整了参数,
那么它们必然需要重新测试;测试一个步骤参数的代码管理成本是很低的。但是,
如果测试5个步骤的全部参数会变都很复杂。管线命令可以缓解这些负担。

9.用主成分分析降维
主成分分析(Principal component analysis,PCA)是本书介绍的第一个高级技术。
而PCA将统计学和线性代数组合起来实现降维,堪称简单模型的杀手锏。

PCA是scikit-learn的一个分解模块。
In [1]:
from sklearn import datasets
iris = datasets.load_iris()
iris_X = iris.data

In [2]:
from sklearn import decomposition
然后,初始化一个PCA对象:
In [3]:
pca = decomposition.PCA()
pca
Out[3]:
PCA(copy=True, n_components=None, whiten=False)
PCA的参数很少。这样PCA对象就创建了,
下面用fit_transform处理iris_X数据:
In [6]:
iris_pca = pca.fit_transform(iris_X)
iris_pca[:5]

这样PCA就完成了,我们可以看看降维的效果:


In [8]:
pca.explained_variance_ratio_
Out[8]:
array([ 0.92461621,  0.05301557,  0.01718514,  0.00518309])
PCA用正交向量集表示原始数据集。
PCA将原始数据集映射到新的空间中,里面每个列向量都是彼此正交的。从数据分析的视角看,
PCA将数据集的协方差矩阵变换成若干能够“解释”一定比例变量的列向量。
例如,在iris数据集中,92.5%的变量可以由第一个主成份表示。

数据分析里面维度多会导致维度灾难,因此降维至关重要。通常算法处理高维训练集时会出现拟合过度(overfit)
的情况,于是难以把握测试集的一般性特征。如果数据集的真实结构可以用更少的维度表示,那么通常都值得一试。


为了演示这点,我们用PCA将iris数据集转换成二维数据。iris数据集用全部的维度通常可以很好的分类:


In [9]:
pca = decomposition.PCA(n_components=2)
iris_X_prime = pca.fit_transform(iris_X)
iris_X_prime.shape
Out[9]:
(150, 2)
我们的矩阵现在是 150×2150×2 ,不是 150×4150×4 了。二维变量更容易可视化:

PCA对象还可以一开始设置解释变量的比例。例如,如果我们想介绍98%的变量,PCA对象就可以这样创建:


In [15]:
pca = decomposition.PCA(n_components=.98)
iris_X_prime = pca.fit_transform(iris_X)
pca.explained_variance_ratio_.sum()
Out[15]:
0.99481691454981014
In [16]:
iris_X_prime.shape
Out[16]:
(150, 3)
10 用因子分析降维
因子分析(factor analysis)是另一种降维方法。与PCA不同的是,因子分析有假设而PCA没有假设。
因子分析的基本假设是有一些隐藏特征与数据集的特征相关。
这个主题将浓缩(boil down)样本数据集的显性特征,尝试像理解因变量一样地理解自变量之间的隐藏特征。
让我们再用iris数据集来比较PCA与因子分析,首先加载因子分析类:
In [3]:
from sklearn import datasets
iris = datasets.load_iris()
from sklearn.decomposition import FactorAnalysis

In [6]:
fa = FactorAnalysis(n_components=2)
iris_two_dim = fa.fit_transform(iris.data)
iris_two_dim[:5]

由于因子分析是一种概率性的转换方法,我们可以通过不同的角度来观察,
例如模型观测值的对数似然估计值,通过模型比较对数似然估计值会更好。


因子分析也有不足之处。由于你不是通过拟合模型直接预测结果,拟合模型只是一个中间步骤。
这本身并非坏事,但是训练实际模型时误差就会产生。
因子分析与前面介绍的PCA类似。但两者有一个不同之处。PCA是通过对数据进行线性变换获取一个能够解释
数据变量的主成分向量空间,这个空间中的每个主成分向量都是正交的。你可以把PCA看成是 NN 维数据集降维成
 MM 维,其中 M<NM<N 。


而因子分析的基本假设是,有 MM 个重要特征和它们的线性组合(加噪声),能够构成原始的 NN 维数据集。
也就是说,你不需要指定结果变量(就是最终生成 NN 维),而是要指定数据模型的因子数量( MM 个因子)
13.用字典学习分解法分类
用于分类的分解方法——字典学习(Dictionary Learning),将数据集转换成一个稀疏的形式。
DictionaryLearning方法的思想是把特征看作构成数据集的基础。首先我们导入iris数据集:


In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
In [2]:
from sklearn.datasets import load_iris
iris = load_iris()
iris_data = http://www.mamicode.com/iris.data
iris_target = iris.target

首先,导入DictionaryLearning:
In [3]:
from sklearn.decomposition import DictionaryLearning
然后用三个成分表示iris数据集中花的类型:

In [4]:
dl = DictionaryLearning(3)
再用fit_transform转换其他数据,这样我们就可以对比训练前后的数据了:
In [5]:
transformed = dl.fit_transform(iris_data[::2])
transformed[:5]
意,每个成分的值分别平行 xx , yy 和 zz 三个轴,其他坐标都是0;这就是稀疏性。


In [6]:
from mpl_toolkits.mplot3d import Axes3D
colors = np.array(list(‘rgb‘))
f = plt.figure()
ax = f.add_subplot(111, projection=‘3d‘)
ax.set_title("Training Set")
ax.scatter(transformed[:, 0], transformed[:, 1], transformed[:, 2], color=colors[iris.target[::2]]);

下面,让我们用fit而不用fit_transform来训练数据集:

In [7]:
transformed = dl.transform(iris_data[1::2])
In [8]:
colors = np.array(list(‘rgb‘))
f = plt.figure()
ax = f.add_subplot(111, projection=‘3d‘)
ax.set_title("Training Set")
ax.scatter(transformed[:, 0], transformed[:, 1], transformed[:, 2], color=colors[iris.target[1::2]]);
17.用随机梯度下降处理回归
随机梯度下降法(Stochastic Gradient Descent,SGD),我们将用它解决回归问题,后面我们还用它处理分类问题。
SGD成为许多机器学习算法的核心的另一个原因是它很容易描述过程。我们对数据作一些变换,
然后用模型的损失函数(loss function)拟合数据。

In [5]:
from sklearn import datasets
X, y = datasets.make_regression(int(1e6))
print("{:,}".format(int(1e6)))
1,000,000
还在我们用的是NumPy数组,所以我们可以获得nbytes。
Python本身没有获取NumPy数组大小的方法。输


In [9]:
print("{:,}".format(X.nbytes))
800,000,000

In [10]:
X.nbytes / 1e6
Out[10]:
800.0
In [11]:
X.nbytes / (X.shape[0] * X.shape[1])
Out[11]:
8.0
现在,我们有了数据,就用SGDRegressor来拟合:
In [13]:
import numpy as np
from sklearn import linear_model
sgd = linear_model.SGDRegressor()
train = np.random.choice([True, False], size=len(y), p=[.75, .25])
sgd.fit(X[train], y[train])
Out[13]:
SGDRegressor(alpha=0.0001, average=False, epsilon=0.1, eta0=0.01,
       fit_intercept=True, l1_ratio=0.15, learning_rate=‘invscaling‘,
       loss=‘squared_loss‘, n_iter=5, penalty=‘l2‘, power_t=0.25,
       random_state=None, shuffle=True, verbose=0, warm_start=False)
损失函数是squared_loss,与线性回归里的残差平方和是一样的。
还需要注意shuffle会对数据产生随机搅动(shuffle),这在解决伪相关问题时很有用。
scikit-learn用fit_intercept方法可以自动加一列1。如果想从拟合结果中看到很多输出,
就把verbose设为1。用scikit-learn的API预测,我们可以统计残差的分布情况:


In [16]:
linear_preds = sgd.predict(X[~train])
In [17]:
%matplotlib inline
from matplotlib import pyplot as plt
f, ax = plt.subplots(figsize=(7, 5))
f.tight_layout()
ax.hist(linear_preds - y[~train],label=‘Residuals Linear‘, color=‘b‘, alpha=.5);
ax.set_title("Residuals")
ax.legend(loc=‘best‘);


标准的梯度下降法的思想是在每次迭代计算一个新的相关系数矩阵,然后用学习速率(learning rate)和
目标函数(objective function)的梯度调整它,直到相关系数矩阵收敛为止。如果用伪代码写就是这样:

sklearn基础知识-准备阶段