sklearn.datasets 模块用于获取较为经典的数据集。
load_*()
和 fetch_*()
返回的数据类型为 sklearn.utils.Bunch,是一种字典格式。其中几个主要的键值对如下:
Bunch 类型可以通过 iris[‘data’] 或 iris.data 获取对应的值。
from sklearn.datasets import load_iris
iris = load_iris()
print(iris['data'])
print(iris.data)
一个数据集通常会被划分为训练集和测试集,划分比例通常为 8:2 或 7:3,可以通过 sklearn.model_selection.train_test_split(arrays, *options)
进行划分。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
iris = load_iris()
x_train, x_test, y_train, y_test = train_test_split(iris.data, list(iris.target), test_size=0.2)
print(type(x_train)) #
print(type(x_test)) #
print(type(y_train)) #
print(type(y_test)) #
print(x_train.shape) # (120, 4)
print(x_test.shape) # (30, 4)
数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限。
特征工程旨在将原始特征转换为更能表示预测模型潜在问题的特征,从而提高对未知数据预测的准确性。
特征工程包括特征提取、特征预处理、特征降维等。
特征提取旨在将任意类型的数据(如文本或图像)转换为可用于机器学习的数值型数据,这一转换过程也叫做特征值化。
可以通过 sklearn.feature_extraction.DictVectorizer(sparse=True, …) 对字典数据进行特征值化:
from sklearn.feature_extraction import DictVectorizer
# 创建一个字典列表作为示例数据
data = [{'city': '北京', 'temperature': 100},
{'city': '上海', 'temperature': 60},
{'city': '深圳', 'temperature': 30}]
# 创建一个 DictVectorizer 实例
vec = DictVectorizer(sparse=True) # sparse=True 表示输出稀疏矩阵
# 对示例数据进行向量化
X = vec.fit_transform(data)
# 将 sparse 矩阵转换回之前的格式
y = vec.inverse_transform(X)
# 输出转换后的特征矩阵
print(X)
print(y)
print(vec.get_feature_names())
---------
(0, 1) 1.0
(0, 3) 100.0
(1, 0) 1.0
(1, 3) 60.0
(2, 2) 1.0
(2, 3) 30.0
[{'city=北京': 1.0, 'temperature': 100.0}, {'city=上海': 1.0, 'temperature': 60.0}, {'city=深圳': 1.0, 'temperature': 30.0}]
['city=上海', 'city=北京', 'city=深圳', 'temperature']
"""
vec.fit_transform(data) 会先分析字典的所有类别,['city=上海', 'city=北京', 'city=深圳', 'temperature'] 分别表示为 [0, 1, 2, 3];
因此在上述结果中的小括号内,第一个值表示第几个样本,第二个值表示类别,这两个值就构成了 sparse 矩阵的行列坐标,并使用独热编码对其进行特征值化。
"""
vec = DictVectorizer(sparse=False) # sparse=False 表示输出稀疏矩阵的二维数组
X = vec.fit_transform(data)
print(X)
---------
[[ 0. 1. 0. 100.]
[ 1. 0. 0. 60.]
[ 0. 0. 1. 30.]]
可以通过 sklearn.feature_extraction.text.CountVectorizer(stop_words=None) 对文本数据进行特征值化:
from sklearn.feature_extraction.text import CountVectorizer
# 创建一个字符串列表作为示例数据
data = ['life is short, i like like like python',
'life is too long, i dislike python']
# 创建一个 CountVectorizer 实例
vec = CountVectorizer() # 输出词频稀疏矩阵
# 对示例数据进行向量化
X = vec.fit_transform(data)
# 将 sparse 矩阵转换回之前的格式
y = vec.inverse_transform(X)
# 输出转换后的特征矩阵
print(X)
print(y)
print(vec.get_feature_names()) # 获取单词特征列表,标点符号与单个字母不计入列表
print(type(X))
print(X.toarray())
---------
(0, 2) 1
(0, 1) 1
(0, 6) 1
(0, 3) 3
(0, 5) 1
(1, 2) 1
(1, 1) 1
(1, 5) 1
(1, 7) 1
(1, 4) 1
(1, 0) 1
[array(['life', 'is', 'short', 'like', 'python'], dtype='), array(['life', 'is', 'python', 'too', 'long', 'dislike'], dtype=')]
['dislike', 'is', 'life', 'like', 'long', 'python', 'short', 'too']
<class 'scipy.sparse.csr.csr_matrix'>
[[0 1 1 3 0 1 1 0]
[1 1 1 0 1 1 0 1]]
"""
vec.fit_transform(data) 会先分析文本的所有单词,['dislike', 'is', 'life', 'like', 'long', 'python', 'short', 'too'] 分别表示为 [0, 1, 2, 3, 4, 5, 6, 7];
因此在上述结果中的小括号内,第一个值表示第几个样本,第二个值表示不同单词,这两个值就构成了 sparse 矩阵的行列坐标,并使用独热编码对其进行特征值化。
"""
vec = CountVectorizer(stop_words=['is', 'too']) # 停用参数,其中的单词将不计入单词特征列表
X = vec.fit_transform(data)
print(X.toarray())
print(vec.get_feature_names())
---------
[[0 1 1 0 1 1]
[1 1 0 1 1 0]]
['dislike', 'life', 'like', 'long', 'python', 'short']
data = ['我 爱 北京 天安门',
'天安门 上 太阳 升']
vec = CountVectorizer() # 输出词频稀疏矩阵
X = vec.fit_transform(data)
print(X)
print(vec.get_feature_names())
print(X.toarray())
---------
(0, 0) 1
(0, 1) 1
(1, 1) 1
(1, 2) 1
['北京', '天安门', '太阳']
[[1 1 0]
[0 1 1]]
TF-IDF 的主要思想是如果某个词语或短语在一篇文章中出现的频率很高,而在其他文章中很少出现,则认为该词语或短语具有很好的类别区分能力,适合用于分类。因此,TF-IDF 的主要作用是用于评估一个词语对于一个文件集或语料库中一份文件的重要程度。
词频(term frequency,tf)指的是某一个词语在该文件中出现的频率。
逆向文档频率(inverse document frequency,idf)是对某一个词语普遍重要性的度量。某一词语的 idf 可由总文件数除以包含该词语的文件数,再对其取以十为底的对数得到。
t f i d f = t f ∗ i d f tfidf = tf * idf tfidf=tf∗idf
假设语料库中有 1000 篇文章,其中有 100 篇文章包含”经济“一词,现在有一篇新的文章,该文章总共有 100 个词语,其中”经济“一词出现了 10次,tfidf 的计算如下:
也就是说,”经济“这个词对于该文章的重要程度为 0.1。
可以通过 sklearn.feature_extraction.text.TfidfVectorizer(stop_words=None) 对文本数据进行特征值化:
特征预处理旨在通过一些转换函数,将特征数据转换成更加适合算法模型的特征数据。
数值型数据的无量纲化是指将不同维度的数值型数据统一到同一标准的过程,使得不同维度的特征具有相同的量纲。这个过程可以消除不同维度特征之间的量纲和单位差异,有助于提高模型训练的收敛速度,避免某些特征对模型产生过大影响。
常见的数值型数据的无量纲化方法有:
归一化
最小-最大缩放(Min-Max Scaling),将数据线性地缩放到一个固定范围内,通常是 [0, 1] 或 [-1, 1];公式如下:
x ′ = x − m i n ( x ) m a x ( x ) − m i n ( x ) x' = \frac{x - min(x)}{max(x) - min(x)} x′=max(x)−min(x)x−min(x)
如果需要将数据映射到指定范围(映射到 [0, 1] 时不需要),还需要进行如下计算:
x ′ ′ = x ′ ∗ ( u p p e r − l o w e r ) + l o w e r x'' = x' * (upper - lower) + lower x′′=x′∗(upper−lower)+lower
其中, u p p e r upper upper 表示区间的上限, l o w e r lower lower 表示区间的下限;例如我想将数据映射到 [-1, 1] 范围,那么 1 就是区间上限,-1 就是区间下限。
标准化
Z-Score 标准化(Z-Score Normalization),通过减去均值并除以标准差,将数据转换为均值为 0 标准差为 1 的标准正态分布数据;公式如下:
x ′ = x − μ σ x' = \frac{x - \mu}{\sigma} x′=σx−μ
无量纲化可以使不同特征之间的数值范围相近,有利于加快模型训练时的收敛速度,提高模型的精确度和稳定性。
Min-Max Scaling 和 Z-Score Normalization 都属于归一化操作,如果不对数据进行归一化处理,会导致什么问题:
最小-最大缩放的优缺点:
综上来看,最小最大缩放这种归一化方法的鲁棒性相对较差,适用于范围已知且数据分布相对均匀的数据集。如果数据的分布非常不均匀或者范围未知,使用最小-最大缩放进行归一化可能会导致数据失真,不利于模型的训练和预测。在这种情况下,使用其他归一化方法,如标准化(Z-score normalization)更为合适。
Z-Score Normalization 的优缺点:
Z-score normalization 方法相较于最小-最大缩放方法而言,在处理异常值时更具鲁棒性,归一化后的数据相对更稳定。Z-score normalization 基于样本统计量(均值和标准差)进行计算,而不是依赖于固定范围,因此能更好地适应数据集的变化。Z-score normalization 适用于符合正态分布假设的数据集。
可以通过 sklearn.preprocessing.MinMaxScaler(feature_range=(0, 1)) 对数据进行最小-最大缩放:
from sklearn.preprocessing import MinMaxScaler
data = [[90, 5, 145],
[85, 30, 189],
[53, 8, 159],
[98, 15, 110]]
scale = MinMaxScaler(feature_range=(0, 1)) # 实例化 MinMaxScaler 类对象,映射范围为 [0, 1]
X = scale.fit_transform(np.array(data)) # 进行最小-最大缩放计算
print(X)
print(type(X))
---------
[[0.82222222 0. 0.44303797]
[0.71111111 1. 1. ]
[0. 0.12 0.62025316]
[1. 0.4 0. ]]
<class 'numpy.ndarray'>
可以通过 sklearn.preprocessing.StandardScaler() 对数据进行 Z-score normalization:
from sklearn.preprocessing import StandardScaler
data = [[90, 5, 145],
[85, 30, 189],
[53, 8, 159],
[98, 15, 110]]
scale = StandardScaler() # 实例化 StandardScaler 类对象,均值为 0,标准差为 1
X = scale.fit_transform(data) # 进行 Z-score normalization 计算
print(X)
print(type(X))
---------
[[ 0.49721207 -0.98378271 -0.20251156]
[ 0.20473438 1.60511916 1.3471421 ]
[-1.66712283 -0.67311449 0.29056006]
[ 0.96517638 0.05177804 -1.43519061]]
<class 'numpy.ndarray'>
特征降维是指在某些限定条件下,降低随机变量(特征)个数,以得到一组不相关主变量的过程。
特征降维的方式主要有:
数据集中往往包含冗余特征或相关性较强的特征,特征选择旨在从原有特征中找出主要特征。
特征选择的方法主要有:
方差选择法可以通过 sklearn.feature_selection.VarianceThreshold(threshold=0.0) 实现:
from sklearn.feature_selection import VarianceThreshold
data = [[50, 1, 3],
[40, 1, 2],
[30, 1, 1]]
var = VarianceThreshold() # 实例化 VarianceThreshold 类对象,threshold 默认为 0.0
X = var.fit_transform(data) # 进行方差计算,并根据阈值选择特征
print(X)
print(type(X))
---------
[[50 3]
[40 2]
[30 1]]
<class 'numpy.ndarray'>
常用的相关系数计算方法有:
皮尔逊相关系数( pearson correlation coefficient),衡量了两个变量(特征)之间的线性相关程度,取值范围为 [-1, 1],-1 表示完全负相关,1 表示完全正相关,0 表示无相关性。
皮尔逊相关系数只能衡量线性关系,对于非线性关系无法准确刻画。此外,它对异常值敏感,当数据中存在异常值时,相关系数的计算结果可能会受到影响。
假设有两个变量 X X X 和 Y Y Y,它们的观测值分别为 x 1 , x 2 , . . . , x n x_1, x_2, ..., x_n x1,x2,...,xn 和 y 1 , y 2 , . . . , y n y_1, y_2, ..., y_n y1,y2,...,yn,则它们的皮尔逊相关系数计算过程如下:
斯皮尔曼相关系数(spearman correlation coefficient),衡量两个变量之间的单调关系强度的非参数统计指标,取值范围为 [-1, 1],-1 表示完全负相关,1 表示完全正相关,0 表示无相关性。
与皮尔逊相关系数不同,斯皮尔曼相关系数不需要假设数据服从正态分布,并且对非线性关系也能够比较好地描述。此外,当数据中存在异常值时,斯皮尔曼相关系数的计算结果会更加稳健。但是,当数据中存在重复值时,斯皮尔曼相关系数的计算结果可能会失真,因此需要对数据进行去重处理。
斯皮尔曼相关系数的计算方法如下:
皮尔逊相关系数法可以通过 scipy.stats.pearsonr(x, y) 实现:
from scipy.stats import pearsonr
data = [[1, 2, 3, 4, 5],
[10, 23, 32, 48, 54]]
r, _ = pearsonr(data[0], data[1]) # 计算皮尔逊相关系数
print(r)
print(type(r))
---------
0.9929103222184174
<class 'numpy.float64'>
主成分分析可以把具有相关性的高维变量转换为线性无关的低维变量,称为主成分。主成分能够尽可能保留原始数据的信息。
可以通过 sklearn.decomposition.PCA(n_components=None) 实现主成分分析:
from sklearn.decomposition import PCA
data = [[1, 2, 3, 4, 5],
[10, 23, 32, 48, 54],
[4, 56, 78, 23, 17]]
pca = PCA(n_components=2)
X = pca.fit_transform(data)
print(X)
print(type(X))
---------
[[ 49.07977129 -16.9822929 ]
[ -3.07160134 37.60922964]
[-46.00816996 -20.62693674]]
<class 'numpy.ndarray'>