一、什么是特征工程
(一)数据集的构成
常用数据集是由特征值和目标值构成的,比如:
可以将前三列当作特征,根据人口、经济、教育水平来判断下面两个样本的处于那个区域(目标值)。但是有些数据集也可以是没有目标值得,比如文本数据(一篇文章)。
(二)什么是特征工程
特征工程是将原始数据转换为更好地代表预测模型的潜在问题的特征的过程,从而提高了对未知数据的模型准确性。特征工程的意义就是直接影响模型预测的结果。
二、特征抽取
(一)字典特征抽取
1、Scikit-learn安装
Scikit-learn是Python语言机器学习的工具,其中包括很多知名的机器学习的算法。Scikit-learn安装也很简单,只需要在虚拟环境中通过pip命令安装即可。
conda install Scikit-learn
Scikit-learn中针对特征抽取的API是:
sklearn.feature_extraction
特征抽取针对的是非连续性的数据
2、字典特征抽取
字典特征抽取使用的API是:
sklearn.feature_extraction.DictVectorizer
- DictVectorizer.fit_transform(X)
X:字典或者包含字典的迭代器 返回值:返回sparse矩阵
- DictVectorizer.inverse_transform(X)
X:array数组或者sparse矩阵 返回值:转换之前数据格式
- DictVectorizer.get_feature_names() 返回类别名称
DictVectorizer.transform(X) 按照原先的标准转换
对字典进行特征值化的步骤如下:
- 实例化类DictVectorizer
- 调用方法fit_transform,传入X字典的列表组成形式参数
from sklearn.feature_extraction import DictVectorizer def dictVec(): """ 字典数据进行特征抽取 :return: """ #准备字典数据列表 d_list = [ {"fruit":"apple","price":12}, {"fruit":"pear", "price": 6}, {"fruit":"banana", "price": 10}, ] #实例化DictVectorizer dictVectorizer = DictVectorizer(sparse=False) #调用fit_transform data = dictVectorizer.fit_transform(d_list) print(data) """ [[ 1. 0. 0. 12.] [ 0. 0. 1. 6.] [ 0. 1. 0. 10.]] """ print(dictVectorizer.get_feature_names()) """ ['fruit=apple', 'fruit=banana', 'fruit=pear', 'price'] """ print(dictVectorizer.inverse_transform(data)) """ [{'price': 12.0, 'fruit=apple': 1.0}, {'price': 6.0, 'fruit=pear': 1.0}, {'fruit=banana': 1.0, 'price': 10.0}] """ return None if __name__ == '__main__': dictVec()
从上面的执行结果看:
调用fit_transform默认返回的是sparse类型,但是我们传入sparse=False后返回的就是ndarray的二维数组,对于字典数据就是将其类别数据,转成特征数据,就是One-hot编码(出现的类别就用1表示,没有出现的就用0表示)。值得注意的是数值型数据并没有进行转化,因为数值型数据是没有必要进行转化的。
调用get_feature_names我们可以知道将字典数据分成哪几类,这几类对应的就是ndarray中的列数。
(二)文本特征抽取
1、文本特征抽取
文本特征抽取使用的API是:
sklearn.feature_extraction.text.CountVectorizer
- CountVectorizer.fit_transform(X,y)
X:文本或者包含文本字符串的可迭代对象 返回值:返回sparse矩阵
- CountVectorizer.inverse_transform(X)
X:array数组或者sparse矩阵 返回值:转换之前数据格式
- CountVectorizer.get_feature_names()
返回值:单词列表
对文本进行特征值化的步骤如下:
- 实例化类DictVectorizer
- 调用方法fit_transform,传入X文本的列表组成形式参数,注意调用toarray转成ndarray
from sklearn.feature_extraction.text import CountVectorizer def countVec(): """ 对文本进行特征值化 :return: """ #准备文本数据 text_list = ["我喜欢各种水果","水果被人们喜欢,因为富含各种营养"] #实例化CountVectorizer cv = CountVectorizer() #调用fit_transform data = cv.fit_transform(text_list)
print(data) """ (0, 1) 1 (1, 0) 1 (1, 2) 1 """ print(data.toarray()) """ [[0 1 0] [1 0 1]] """ print(cv.get_feature_names()) """ ['因为富含各种营养', '我喜欢各种水果', '水果被人们喜欢'] """ if __name__ == '__main__': countVec()
但是如果上面的三个句子中间用空格隔离就会进行分词:
from sklearn.feature_extraction.text import CountVectorizer def countVec(): """ 对文本进行特征值化 :return: """ #准备文本数据 text_list = ["我 喜欢 各种 水果","水果 被 人们 喜欢,因为 富含 各种 营养"] #实例化CountVectorizer cv = CountVectorizer() #调用fit_transform data = cv.fit_transform(text_list) """ print(data.toarray()) """ [[0 1 1 0 0 1 0] [1 1 1 1 1 1 1]] """ print(cv.get_feature_names()) """ ['人们', '各种', '喜欢', '因为', '富含', '水果', '营养'] """
注意,不支持单个中文词,可以看到上面第一次是以句子作为分类的,这并非我们要的结果,所以需要对这些文章或者句子进行中文分词,然后再进行特征抽取。但是我们不能手动的进行空格这样的操作,可以借助分词jieba,然后再进行特征抽取。
2、文本特征抽取优化
- jieba安装
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple jieba
- 使用
使用cut方法进行分词:
c = jieba.cut("我喜欢各种水果") #词语生成器 <generator object Tokenizer.cut at 0x0000000004B26A98> print(c) #['我', '喜欢', '各种', '水果']
- 文本特征抽取
from sklearn.feature_extraction.text import CountVectorizer import jieba def cutWord(): # 准备文本数据 article1 = "我喜欢各种水果,以及各种甜食" article2 = "水果被人们喜欢" article3 = "因为富含各种营养" #生成器 c1 = jieba.cut(article1) c2 = jieba.cut(article2) c3 = jieba.cut(article3) #转成列表 c1_list = list(c1) c2_list = list(c2) c3_list = list(c3) #把列表转成字符串 c1_str = " ".join(c1_list) #我 喜欢 各种 水果 c2_str = " ".join(c2_list) c3_str = " ".join(c3_list) return c1_str,c2_str,c3_str def countVecWord(): #获取中文分词后的结果 c1_str, c2_str, c3_str = cutWord() #实例化CountVectorizer cv = CountVectorizer() #传入分词后的字符串列表 data = cv.fit_transform([c1_str,c2_str,c3_str]) print(cv.get_feature_names()) """ ['人们', '以及', '各种', '喜欢', '因为', '富含', '水果', '甜食', '营养'] """ print(data.toarray()) """ [[0 1 2 1 0 0 1 1 0] [1 0 0 1 0 0 1 0 0] [0 0 1 0 1 1 0 0 1]] """ if __name__ == '__main__': countVecWord()
上面就是将文本数据先进行分词,比如将三篇文章分别进行分词,然后再将分词后的三篇文章放在列表中进行特征值化,注意特征值化ndarray数组中的分组是每个特征值分类的个数,比如article1中“各种”出现2次。这样可以将文章进行分类。
(三)TF-IDF
上面是可以对文章进行分类的,但是假如一篇文章中像因为、所以等等这样的词语太多,它就会作为整个文章的主要特征词,这词语显然是不能作为文章的主题的,所以我们需要使用TF-TDF来解决的。
TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
TF-IDF作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。
1、API介绍
- TfidfVectorizer(stop_words=None,…)
返回词的权重矩阵
- TfidfVectorizer.fit_transform(X,y)
X:文本或者包含文本字符串的可迭代对象 返回值:返回sparse矩阵
- TfidfVectorizer.inverse_transform(X)
X:array数组或者sparse矩阵 返回值:转换之前数据格式
- TfidfVectorizer.get_feature_names()
返回值:单词列表
2、使用
from sklearn.feature_extraction.text import TfidfVectorizer import jieba def cutWord(): # 准备文本数据 article1 = "我喜欢各种水果,以及各种甜食" article2 = "水果被人们喜欢" article3 = "因为富含各种营养" #生成器 c1 = jieba.cut(article1) c2 = jieba.cut(article2) c3 = jieba.cut(article3) #转成列表 c1_list = list(c1) c2_list = list(c2) c3_list = list(c3) #把列表转成字符串 c1_str = " ".join(c1_list) #我 喜欢 各种 水果 c2_str = " ".join(c2_list) c3_str = " ".join(c3_list) return c1_str,c2_str,c3_str def tfiVec(): #获取中文分词后的结果 c1_str, c2_str, c3_str = cutWord() #实例化CountVectorizer cv = TfidfVectorizer() 7 data = cv.fit_transform([c1_str,c2_str,c3_str]) print(cv.get_feature_names()) """ ['人们', '以及', '各种', '喜欢', '因为', '富含', '水果', '甜食', '营养'] """ print(data.toarray()) """ [[0. 0.42755362 0.6503311 0.32516555 0. 0. 0.32516555 0.42755362 0. ] [0.68091856 0. 0. 0.51785612 0. 0. 0.51785612 0. 0. ] [0. 0. 0.40204024 0. 0.52863461 0.52863461 0. 0. 0.52863461]] """ if __name__ == '__main__': tfiVec()
可以看到特征值化后是每一个词语的所占的比重,也就是相对文章的重要程度,由此我们可以根据重要程度得到文章的主题,从而进行分类。
那么重要性程度是怎样计算呢?这与TF和IDF有关,TF(term frequency)表示词的频率也就是词出现的次数;IDF(inverse document freequency)逆文档频率也就是:总文档数量/该词出现的文档数量。然后使用:
TF*IDF
这就是对应词语在对应文章中的重要程度。