特征工程介绍

特征工程是 为了提高了对未知数据的模型准确性,将原始数据转换为更好地代表预测模型的潜在问题的特征的过程。

例如预测一篇文章所在的类别,是否是新闻,首先得提取这篇文章的特征,如若这篇文章的特征更大程度上满足新闻的特征,那么我们便可预测其属于新闻类别。

其中主要包括了数据认知,数据清洗,特征提取,特征选择四个部分。
a) 数据认知:基于实际业务场景理解数据内容,发现数据与研究问题的关系。
b) 数据清洗:对数据进行规整,移除重复变量、处理缺失、异常数据等。
c) 特征提取:通过业务理解和技术实施,构造出描述研究问题的特征。
d) 特征选择:在构造的特征中筛选出最能刻画研究问题的特征。

工具:Scikit-learn

image.png
Python语言的机器学习工具 Scikit-learn包括许多知名的机器学习算法的实现 Scikit-learn文档完善,容易上手,丰富的API,使其在学术界颇受欢迎。

安装

pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple Scikit-learn

导入

import sklearn


特征提取

特征抽取针对非连续型数据,对文本等进行特征值化。

api

sklearn.feature_extraction

字典特征提取

类:sklearn.feature_extraction.DictVectorizer
Vectorizer 矢量器
DictVectorizer(sparse=True,…) 返回一个sparse矩阵,如果是false 则返回ndarray数组

方法 解释
DictVectorizer.fit_transform(X) X:字典或者包含字典的迭代器 返回值:返回sparse矩阵
DictVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格式
DictVectorizer.get_feature_names() 返回类别名称
DictVectorizer.transform(X) 按照原先的标准转换

文本特征提取

类:sklearn.feature_extraction.text.CountVectorizer

方法 解释
CountVectorizer.fit_transform(X,y) X:文本或者包含文本字符串的可迭代对象 返回值:返回sparse矩阵
CountVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格式
CountVectorizer.get_feature_names() 返回值:单词列表

注意点:一个字母的单词不会统计(因为ta无法代表文章的含义?)

  1. >>> from sklearn.feature_extraction.text import CountVectorizer
  2. >>> texts = ['life is short, i love python','life is too long,i love python too']
  3. >>> cv = CountVectorizer()
  4. >>> data = cv.fit_transform(texts)
  5. >>> print(data)
  6. (0, 4) 1
  7. (0, 3) 1
  8. (0, 5) 1
  9. (0, 0) 1
  10. (0, 1) 1
  11. (1, 2) 1
  12. (1, 6) 2
  13. (1, 4) 1
  14. (1, 3) 1
  15. (1, 0) 1
  16. (1, 1) 1
  17. >>> print(cv.get_feature_names())
  18. ['is', 'life', 'long', 'love', 'python', 'short', 'too']
  19. >>> print(data.toarray())
  20. [[1 1 0 1 1 1 0]
  21. [1 1 1 1 1 0 2]]

但是如果是中文怎么办呢?
对于连续中文是不支持的,但是分词后的中文(以空格分开),同样可以特征提取。

简单介绍下jieba分词

cut

  1. >>> import jieba
  2. >>> import os
  3. >>> f = '对于连续中文是不支持的,但是分词后的中文(以空格分开),同样可以特征提取。'
  4. >>> seg_list = jieba.cut(f)
  5. >>> print("jingque:","/".join(seg_list))

提取关键词

  1. >>> import jieba.analyse
  2. >>> tags = jieba.analyse.extract_tags(f,topK = 10)
  3. >>> print("Keyword:","/".join(tags))

栗子

  1. >>> f = '对于连续中文是不支持的,但是分词后的中文(以空格分开),同样可以特征提取。'
  2. >>> a = ' '.join(list(jieba.cut(f)))
  3. >>> a
  4. '对于 连续 中文 是 不 支持 的 , 但是 分词 后 的 中文 ( 以 空格 分开 ) , 同样 可以 特征提取 。'

我有一个疑问,在中文中,长度为一的字是有含义的,能够影响文本的特征 这样忽略单一字符串是不是有些欠妥呢?我想给ta组词或许能够增加准确性。


另外一种文本特征提取:tf-idf

image.png

主要思想

TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高, 并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分 能力,适合用来分类。

Tf:term frequyency 词的频率
idf:inverse document frequyency 逆文档频率。log(总文档数量/该词出现的文档数量)
tf*idf = 该词的重要性程度
根据上方的定义,许多词语出现的次数多,但是它是不重要的。
**

使用

类:sklearn.feature_extraction.text.TfidfVectorizer
TfidfVectorizer(stop_words=None,…) 返回词的权重矩阵

方法 解释
TfidfVectorizer.fit_transform([X],y) X:文本或者包含文本字符串的可迭代对象 返回值:返回sparse矩阵
TfidfVectorizer.inverse_transform(X) X:array数组或者sparse矩阵 返回值:转换之前数据格式
TfidfVectorizer.get_feature_names() 返回值:单词列表

栗子

  1. >>> from sklearn.feature_extraction.text import CountVectorizer,TfidfVectorizer
  2. >>> tv = TfidfVectorizer()
  3. >>> a
  4. '对于 连续 中文 是 不 支持 的 , 但是 分词 后 的 中文 ( 以 空格 分开 ) , 同样 可以 特征提取 。'
  5. >>> data = tv.fit_transform([a]) #可以传入多个 代表不同文档
  6. >>> print(data.toarray())
  7. [[0.53452248 0.26726124 0.26726124 0.26726124 0.26726124 0.26726124
  8. 0.26726124 0.26726124 0.26726124 0.26726124 0.26726124]]
  9. >>> print(tv.get_feature_names())
  10. ['中文', '但是', '分开', '分词', '可以', '同样', '对于', '支持', '特征提取', '空格', '连续']

接着上面 第五行可以增加其他文本

  1. # 例如增加一个b
  2. >>> b = 'TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高, 并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分 能力,适合用来分类。'
  3. >>> b = ' '.join(list(jieba.cut(b)))
  4. >>> b
  5. 'TF - IDF 的 主要 思想 是 : 如果 某个 词 或 短语 在 一篇 文章 中 出现 的 概率 高 , 并且 在 其他 文章 中 很少 出现 , 则 认为 此词 或者 短语 具有 很 好 的 类别 区分 能力 , 适合 用来 分类 。'
  6. >>> data = tv.fit_transform([a,b])
  7. >>> print(tv.get_feature_names())
  8. ['idf', 'tf', '一篇', '中文', '主要', '但是', '其他', '具有', '出现', '分开', '分类', '分词', '区分', '可以', '同样', '如果', '对于', '并且', '很少', '思想', '或者', '支持', '文章', '某个', '概率', '此词', '特征提取', '用来', '短语', '空格', '类别', '能力', '认为', '连续', '适合']
  9. >>> print(data.toarray())
  10. [[0. 0. 0. 0.53452248 0. 0.26726124
  11. 0. 0. 0. 0.26726124 0. 0.26726124
  12. 0. 0.26726124 0.26726124 0. 0.26726124 0.
  13. 0. 0. 0. 0.26726124 0. 0.
  14. 0. 0. 0.26726124 0. 0. 0.26726124
  15. 0. 0. 0. 0.26726124 0. ]
  16. [0.17407766 0.17407766 0.17407766 0. 0.17407766 0.
  17. 0.17407766 0.17407766 0.34815531 0. 0.17407766 0.
  18. 0.17407766 0. 0. 0.17407766 0. 0.17407766
  19. 0.17407766 0.17407766 0.17407766 0. 0.34815531 0.17407766
  20. 0.17407766 0.17407766 0. 0.17407766 0.34815531 0.
  21. 0.17407766 0.17407766 0.17407766 0. 0.17407766]]
  22. >>>