一.数据集划分 API函数:
sklearn.model_selection.train_test_split(*arrays,**options)
参数:
可以传入多个数据集,返回train与test数据集
1 2 3 4 5 6 7 8 9 10 11 12 from sklearn.model_selection import train_test_split x = [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] y = [10 ,20 ,30 ,40 ,50 ,60 ,70 ,80 ,90 ,100 ] x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2 , random_state=42 , shuffle=True ) print (x_train, x_test, y_train, y_test)
结果:
1 [6, 1, 8, 3, 10, 5, 4, 7] [9, 2] [60, 10, 80, 30, 100, 50, 40, 70] [90, 20]
可以看到,两个数据集以完全相同的方式进行划分,在函数中都是用相同的下标进行抽取,使用的是相同的划分规则 。
而在日常工作中,我们一般都会像上面一样传入两个数据集,一个就是特征 数据集,一个就是标签 数据集。我们以鸢尾花为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 from sklearn.datasets import load_irisfrom sklearn.model_selection import train_test_split iris = load_iris() data = iris.data target = iris.target X_train, X_test, y_train, y_test = train_test_split(data, target, test_size=0.3 , random_state=42 ) print (X_train.shape, X_test.shape, y_train.shape, y_test.shape)
结果:
1 (105, 4) (45, 4) (105,) (45,)
这里取出来的每一整条特征数据都完美对应自己的标签,这也为后续的模型训练奠定了基础。
二.特征工程 2.1 概念 就是对特征进行相关的处理
一般使用pandas
来进行数据清洗和数据处理、使用sklearn
来进行特征工程
特征工程是将任意数据(如文本或图像)转换为可用于机器学习的数字特征,比如:字典特征提取(特征离散化)、文本特征提取、图像特征提取。
2.2 API 实例化转换器对象(transfer),转换器类有很多:
| DictVectorize | 字典特征提取 | | CountVectorizer | 文本特征提取 | | TfidfVectorizer | TF-IDF文本特征词的重要程度特征提取 | | StandardScaler | 标准化 | | MinMaxScaler | 归一化 | | VarianceThreshold| 底方差过滤降维 | | PCA | 主成分分析 |
转换器对象调用 fit_transform(
) 进行特定转换, fit
用于计算数据,transform
进行最终转换。fit_transform()
可以使用fit()
和transform()
代替:
1 data_new = transfer.fit_transform(data)
可写成:
1 2 3 transfer.fit(data) data_new = transfer.transform(data)
2.3 DictVectorizer 字典列表特征提取 讲之前先了解一个概念,稀疏矩阵 :
稀疏矩阵 是指一个矩阵中大部分元素为零,只有少数元素是非零的矩阵。由于稀疏矩阵中零元素非常多,存储和处理稀疏矩阵时,通常会采用特殊的存储格式三元组表 ,以节省内存空间并提高计算效率。
比如:
(0,0) 10
(0,1) 20
(2,0) 90
(2,20) 8
(8,0) 70
表示除了列出的索引位置有值, 其余全是0
同样也有非稀疏矩阵(稠密矩阵),与稀疏矩阵相反。
API:
sklearn.feature_extraction.DictVectorizer(sparse=True)
参数:
sparse:默认以稀疏矩阵表示,为True时返回稀疏矩阵,为False时返回稠密矩阵。
这个API会返回一个字典列表特征提取器对象,再通过前面的fit_transform
方法,就可以将字典列表转换为稀疏矩阵或稠密矩阵。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from sklearn.feature_extraction import DictVectorizer data = [ {'city' : '北京' , 'temperature' : 10 }, {'city' : '上海' , 'temperature' : 20 }, {'city' : '广州' , 'temperature' : 30 }, {'city' : '广州' , 'temperature' : 29 }] vec = DictVectorizer(sparse=False ) data_new = vec.fit_transform(data) print (vec.get_feature_names_out()) print (data_new)
结果:
1 2 3 4 5 ['city=上海' 'city=北京' 'city=广州' 'temperature'] [[ 0. 1. 0. 10.] [ 1. 0. 0. 20.] [ 0. 0. 1. 30.] [ 0. 0. 1. 29.]]
可以看到原先的数据集中含有中文特殊字符,在进行转化时转换器就把每个包含中文的键值对当作一个特征名保存。而打印出的特征矩阵中,其中每一行每个数字对应的位置就是特征名列表中的位置,为1则代表是该特征,为0则代表不是该特征。
再来看看三元组的表示:
1 2 3 4 5 6 7 8 9 10 11 vec = DictVectorizer(sparse=True ) data_new = vec.fit_transform(data) print (vec.get_feature_names_out()) print (data_new)
结果:
1 2 3 4 5 6 7 8 9 10 11 12 ['city=上海' 'city=北京' 'city=广州' 'temperature'] <Compressed Sparse Row sparse matrix of dtype 'float64' with 8 stored elements and shape (4, 4)> Coords Values (0, 1) 1.0 (0, 3) 10.0 (1, 0) 1.0 (1, 3) 20.0 (2, 2) 1.0 (2, 3) 30.0 (3, 2) 1.0 (3, 3) 29.0
三元组(稀疏矩阵)显示的就是除了0以外的所有数值的索引,也就可以根据索引可以还原之前的特征矩阵。
2.4 CountVectorizer 文本特征提取 API:
sklearn.feature_extraction.text.CountVectorizer()
参数:
stop_words : 又叫黑名单,其中存储的是停用词即不会被提取的词,值类型为list
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from sklearn.feature_extraction.text import CountVectorizer data = ["I love machine learning." , "I love coding." , "I love both" ] cv = CountVectorizer(stop_words=["machine" , "learning" , "coding" ]) data_new1 = cv.fit_transform(data)print (cv.get_feature_names_out())print (data_new1)print (data_new1.toarray())
结果:
1 2 3 4 5 6 7 8 9 10 11 ['both' 'love'] <Compressed Sparse Row sparse matrix of dtype 'int64' with 4 stored elements and shape (3, 2)> Coords Values (0, 1) 1 (1, 1) 1 (2, 1) 1 (2, 0) 1 [[0 1] [0 1] [1 1]]
可以看到,其将每个英文单词提取出来作为特征,矩阵中的数字就是出现的次数(频率)。我们也可以不提取某些词,而且这个函数内部也隐式地去掉了一些特殊字符。
但,我们一般用的都是中文,而这又是特殊字符,能正常使用吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from sklearn.feature_extraction.text import CountVectorizer data = ["第一个句子" ,"第二个句子" ] cv = CountVectorizer() data_new1 = cv.fit_transform(data)print (cv.get_feature_names_out())print (data_new1)print (data_new1.toarray())
结果:
1 2 3 4 5 6 7 8 ['第一个句子' '第二个句子'] <Compressed Sparse Row sparse matrix of dtype 'int64' with 2 stored elements and shape (2, 2)> Coords Values (0, 0) 1 (1, 1) 1 [[1 0] [0 1]]
很明显,这个地方有大问题,由于英文单词天生就用空格分隔,所以可以直接提取。但中文有自己的分词规则,我们需要用其他分词工具进行分词,比如jieba
。
使用下面的命令进行下载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from sklearn.feature_extraction.text import CountVectorizerimport jieba data = "第一个句子" data = jieba.cut(data) data = list (data)print (data) data = " " .join(data)print (data) vec = CountVectorizer() data_new = vec.fit_transform([data]) print (vec.get_feature_names_out())print (data_new.toarray())
结果:
1 2 3 4 ['第一个', '句子'] 第一个 句子 ['句子' '第一个'] [[1 1]]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from sklearn.feature_extraction.text import CountVectorizerimport jieba data = ["第一个句子" ,"第二个句子" ] def cut_words (str ): return " " .join(list (jieba.cut(str ))) data = [cut_words(i) for i in data] vec = CountVectorizer() data_new = vec.fit_transform(data) print (vec.get_feature_names_out())print (data_new.toarray())
结果:
1 2 3 ['句子' '第一个' '第二个'] [[1 1 0] [1 0 1]]
2.5 TfidfVectorizer TF-IDF文本特征词的重要程度特征提取 词频(Term Frequency, TF), 表示一个词在当前篇文章中的重要性。
逆文档频率(Inverse Document Frequency, IDF), 反映了词在整个文档集合中的稀有程度。
API:
sklearn.feature_extraction.text.TfidfVectorizer()
参数:
使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from sklearn.feature_extraction.text import TfidfVectorizerimport jieba data = ["第一个句子" ,"第二个句子" ]def cut_words (str ): return " " .join(list (jieba.cut(str ))) data = [cut_words(i) for i in data] tool = TfidfVectorizer() data_new = tool.fit_transform(data) print (tool.get_feature_names_out())print (data_new.toarray())
结果:
1 2 3 4 5 6 7 8 9 Building prefix dict from the default dictionary ... Loading model from cache C:\Users\Clocky7\AppData\Local\Temp\jieba.cache Loading model cost 0.529 seconds. Prefix dict has been built successfully. ['句子' '第一个' '第二个'] [[0.57973867 0.81480247 0. ] [0.57973867 0. 0.81480247]]
可以看到,有几个句子(文档)就有几个列表,其中的数据表明对应词语在当前文档中的重要程度 。
扩展:
在sklearn库中 TF-IDF算法做了一些细节的优化:
下面是手动实现TF-IDF算法的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import numpy as npfrom sklearn.feature_extraction.text import CountVectorizerfrom sklearn.preprocessing import normalizeimport jieba data = ["第一个句子" ,"第二个句子" ]def cut_words (str ): return " " .join(list (jieba.cut(str ))) data = [cut_words(i) for i in data] def tfidf (x ): cv = CountVectorizer() tf = cv.fit_transform(x).toarray() idf = np.log((len (tf)+1 )/(np.sum (tf!=0 ,axis=0 )+1 ))+1 tfidf = tf*idf tfidf = normalize(tfidf, norm='l2' , axis=1 ) return tfidf data_new = tfidf(data)print (data_new)
结果:
1 2 [[0.57973867 0.81480247 0. ] [0.57973867 0. 0.81480247]]