前言

本文承接上文 决策树

特征提取

将任意数据(如文本或图像)转换为可用于机器学习的数字特征

注:特征值化是为了计算机更好的去理解数据

  • 特征提取分类:
    • 字典特征提取(特征离散化)
    • 文本特征提取

特征提取API

sklearn.feature_extraction

字典特征提取

作用:对字典数据进行特征值化

  • sklearn.feature_extraction.DictVectorizer(sparse=True,…)
    • DictVectorizer.fit_transform(X)
      • X:字典或者包含字典的迭代器返回值
      • 返回sparse矩阵
    • DictVectorizer.get_feature_names() 返回类别名称

demo如下:

from sklearn.feature_extraction import DictVectorizer

def dict_demo():
data = [{'city': '北京', 'temperature': 100},
{'city': '上海', 'temperature': 60},
{'city': '深圳', 'temperature': 30}]
#实例化转换器
transfer = DictVectorizer()
#调用fit_transform
train_data = transfer.fit_transform(data)

print(train_data)

print("特征名字: \n", transfer.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=上海', 'city=北京', 'city=深圳', 'temperature']

这样返回的是一个spare矩阵,对于数量大的数据而言,spare矩阵的可读性更高

我们在pandas中也有类似的效果 :pd.get_dummies()

我们把这个处理数据的技巧叫做”one-hot“编码

我们对于特征值中存在类别信息的时候,都会进行one-hot处理

文本特征提取

作用:对文本数据进行特征值化

  • sklearn.feature_extraction.text.CountVectorizer(stop_words=[])
    • 返回词频矩阵
    • CountVectorizer.fit_transform(X)
      • X:文本或者包含文本字符串的可迭代对象
      • 返回值:返回sparse矩阵
    • CountVectorizer.get_feature_names() 返回值:单词列表
  • sklearn.feature_extraction.text.TfidfVectorizer

demo如下:

from sklearn.feature_extraction.text import CountVectorizer
def enlish_count_demo():
str = ["life is short,i like python",
"life is too long,i dislike python"]
#实例化转换器
transfer = CountVectorizer()
#调用fit_transform
train_str = transfer.fit_transform(str)
print(train_str)
print("抽取结果 \n", train_str.toarray())
print("返回特征名字\n", transfer.get_feature_names())

返回结果为:

  (0, 2)	1
(0, 1) 1
(0, 6) 1
(0, 3) 1
(0, 5) 1
(1, 2) 1
(1, 1) 1
(1, 5) 1
(1, 7) 1
(1, 4) 1
(1, 0) 1
抽取结果
[[0 1 1 1 0 1 1 0]
[1 1 1 0 1 1 0 1]]
返回特征名字
['dislike', 'is', 'life', 'like', 'long', 'python', 'short', 'too']

中文文本特征提取

我们不能直接使用CountVectorizer这个API来对于中文文本直接进行处理

因为英文默认是以空格分开的。其实就达到了一个分词的效果API可以直接使用默认的分词机制而中文并不是这样分词的,所以我们要对中文进行分词处理

这里我们需要使用一个第三方库jieba,可以直接pip安装

pip install jieba

假设这是我们需要处理的中文文本:

“一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。”,
“我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。”,
“如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。”

我们使用jieba可以处理成这样

import jieba
data=["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
"我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
"如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"
]
for i in data:
text=" ".join(list(jieba.cut(i)))
print(text)

运行结果为:

一种 还是 一种 今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝对 大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。
我们 看到 的 从 很 远 星系 来 的 光是在 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。
如果 只用 一种 方式 了解 某样 事物 , 你 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。

这样我们的中文文本的分词就完成了

接下来就是我们的特征提取了

demo如下:

from sklearn.feature_extraction.text import CountVectorizer
import jieba
def cut_word(text):
text = " ".join(list(jieba.cut(text)))
return text


def jieba_demo_CountVectorizer():
data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
"我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
"如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]
text_list = []
for i in data:
text_list.append(cut_word(i))

tranfser = CountVectorizer()
train_data = tranfser.fit_transform(text_list)
print(train_data)
print("抽取结果: \n", train_data.toarray())
print("特征名字返回: \n", tranfser.get_feature_names())

运行返回结果为:

  (0, 0)	2
(0, 35) 1
(0, 6) 2
(0, 26) 2
(0, 22) 2
(0, 12) 1
(0, 32) 1
(0, 31) 1
(0, 14) 1
(0, 24) 1
(0, 19) 1
(0, 27) 1
(0, 2) 1
(0, 20) 1
(1, 18) 3
(1, 28) 2
(1, 23) 1
(1, 7) 1
(1, 8) 1
(1, 3) 1
(1, 9) 1
(1, 36) 1
(1, 17) 1
(1, 34) 1
(2, 0) 1
(2, 18) 1
(2, 16) 1
(2, 11) 1
(2, 21) 1
(2, 4) 4
(2, 25) 1
(2, 5) 3
(2, 1) 1
(2, 29) 2
(2, 13) 1
(2, 30) 1
(2, 10) 1
(2, 15) 1
(2, 33) 1
抽取结果:
[[2 0 1 0 0 0 2 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 2 0 1 0 2 1 0 0 0 1 1 0 0 1
0]
[0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 1 3 0 0 0 0 1 0 0 0 0 2 0 0 0 0 0 1 0
1]
[1 1 0 0 4 3 0 0 0 0 1 1 0 1 0 1 1 0 1 0 0 1 0 0 0 1 0 0 0 2 1 0 0 1 0 0
0]]
特征名字返回:
['一种', '不会', '不要', '之前', '了解', '事物', '今天', '光是在', '几百万年', '发出', '取决于', '只用', '后天', '含义', '大部分', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某样', '残酷', '每个', '看到', '真正', '秘密', '绝对', '美好', '联系', '过去', '还是', '这样']

但是这样提取出的只是每种词汇在该训练文本中出现的频率

如果我们想知道文本类型的时候,应该更多去考虑词频

f-idf文本特征提取

  • TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
  • TF-IDF作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。

公式

  • 词频(term frequency,tf)指的是某一个给定的词语在该文件中出现的频率
  • 逆向文档频率(inverse document frequency,idf)是一个词语普遍重要性的度量。某一特定词语的idf,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取以10为底的对数得到

mark

举例:
假如一篇文章的总词语数是100个,而词语"非常"出现了5次,那么"非常"一词在该文件中的词频就是5/100=0.05。
而计算文件频率(IDF)的方法是以文件集的文件总数,除以出现"非常"一词的文件数。
所以,如果"非常"一词在1,0000份文件出现过,而文件总数是10,000,000份的话,
其逆向文件频率就是lg(10,000,000 / 1,0000)=3。
最后"非常"对于这篇文档的tf-idf的分数为0.05 * 3=0.15

demo如下:

import jieba
from sklearn.feature_extraction.text import TfidfVectorizer

def cut_word(text):
text = " ".join(list(jieba.cut(text)))
return text
def jieba_demo_TfidfVectorizer():
data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
"我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
"如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]
text_list = []
for i in data:
text_list.append(cut_word(i))

transfer = TfidfVectorizer()
train_data = transfer.fit_transform(text_list)
print(train_data)
print("抽取结果: \n", train_data.toarray())
print("特征名字返回: \n", transfer.get_feature_names())

返回结果如下:

(0, 20)	0.20280347192512724
(0, 2) 0.20280347192512724
(0, 27) 0.20280347192512724
(0, 19) 0.20280347192512724
(0, 24) 0.20280347192512724
(0, 14) 0.20280347192512724
(0, 31) 0.20280347192512724
(0, 32) 0.20280347192512724
(0, 12) 0.20280347192512724
(0, 22) 0.4056069438502545
(0, 26) 0.4056069438502545
(0, 6) 0.4056069438502545
(0, 35) 0.20280347192512724
(0, 0) 0.3084745355009243
(1, 34) 0.24108220270067757
(1, 17) 0.24108220270067757
(1, 36) 0.24108220270067757
(1, 9) 0.24108220270067757
(1, 3) 0.24108220270067757
(1, 8) 0.24108220270067757
(1, 7) 0.24108220270067757
(1, 23) 0.24108220270067757
(1, 28) 0.48216440540135513
(1, 18) 0.5500476874707075
(2, 33) 0.15780489008821472
(2, 15) 0.15780489008821472
(2, 10) 0.15780489008821472
(2, 30) 0.15780489008821472
(2, 13) 0.15780489008821472
(2, 29) 0.31560978017642943
(2, 1) 0.15780489008821472
(2, 5) 0.4734146702646441
(2, 25) 0.15780489008821472
(2, 4) 0.6312195603528589
(2, 21) 0.15780489008821472
(2, 11) 0.15780489008821472
(2, 16) 0.15780489008821472
(2, 18) 0.1200146864046492
(2, 0) 0.1200146864046492
抽取结果:
[[0.30847454 0. 0.20280347 0. 0. 0.
0.40560694 0. 0. 0. 0. 0.
0.20280347 0. 0.20280347 0. 0. 0.
0. 0.20280347 0.20280347 0. 0.40560694 0.
0.20280347 0. 0.40560694 0.20280347 0. 0.
0. 0.20280347 0.20280347 0. 0. 0.20280347
0. ]
[0. 0. 0. 0.2410822 0. 0.
0. 0.2410822 0.2410822 0.2410822 0. 0.
0. 0. 0. 0. 0. 0.2410822
0.55004769 0. 0. 0. 0. 0.2410822
0. 0. 0. 0. 0.48216441 0.
0. 0. 0. 0. 0.2410822 0.
0.2410822 ]
[0.12001469 0.15780489 0. 0. 0.63121956 0.47341467
0. 0. 0. 0. 0.15780489 0.15780489
0. 0.15780489 0. 0.15780489 0.15780489 0.
0.12001469 0. 0. 0.15780489 0. 0.
0. 0.15780489 0. 0. 0. 0.31560978
0.15780489 0. 0. 0.15780489 0. 0.
0. ]]
特征名字返回:
['一种', '不会', '不要', '之前', '了解', '事物', '今天', '光是在', '几百万年', '发出', '取决于', '只用', '后天', '含义', '大部分', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某样', '残酷', '每个', '看到', '真正', '秘密', '绝对', '美好', '联系', '过去', '还是', '这样']

决策树API

class sklearn.tree.DecisionTreeClassifier(criterion=’gini’, max_depth=None,random_state=None)

  • criterion
    • 特征选择标准
    • “gini"或者"entropy”,前者代表基尼系数,后者代表信息增益。一默认"gini",即CART算法。
  • min_samples_split
    • 内部节点再划分所需最小样本数
    • 这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择最优特征来进行划分。 默认是2.如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。我之前的一个项目例子,有大概10万样本,建立决策树时,我选择了min_samples_split=10。可以作为参考。
  • min_samples_leaf
    • 叶子节点最少样本数
    • 这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝。 默认是1,可以输入最少的样本数的整数,或者最少样本数占样本总数的百分比。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。之前的10万样本项目使用min_samples_leaf的值为5,仅供参考。
  • max_depth
    • 决策树最大深度
    • 决策树的最大深度,默认可以不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间
  • random_state
    • 随机数种子

案例:泰坦尼克号乘客生存预测

数据集部分展示:

mark

age列中存在数据缺失

乘坐班是指乘客班(1,2,3),是社会经济阶层的代表。

基本步骤:

  • 1.获取数据
  • 2.数据基本处理
    • 2.1 确定特征值,目标值
    • 2.2 缺失值处理
    • 2.3 数据集划分
  • 3.特征工程(字典特征抽取)
  • 4.机器学习(决策树)
  • 5.模型评估

代码如下:

import numpy as np
import pandas as pd
from sklearn.tree import DecisionTreeClassifier,export_graphviz#决策树模型
from sklearn.model_selection import train_test_split#数据分割
from sklearn.feature_extraction import DictVectorizer#特征提取

#读取数据
data=pd.read_csv("./titanic.txt")

#处理缺失值
data=data["age"].fillna(data['age'].mean(),inplace=True)
#确定特征值和目标值
x=data[["age","pclass","sex"]]
y=data['survived']
#进行数据分割
x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=22,test_size=0.2)
#实例化转换器
transfer=DictVectorizer()
#特征值提取
x_train=transfer.fit_transform(x_train.to_dict(orient='records'))
x_test=transfer.fit_transform(x_test.to_dict(orient='records'))
#决策树模型
estimator=DecisionTreeClassifier(criterion='entropy', max_depth=3)

#模型训练
estimator.fit(x_train,y_train)
#预测值
y_pre=estimator.predict(x_test)

print("预测值\n",y_pre)
#评估模型
score=estimator.score(x_test,y_test)
print("准确率: \n",score)

运行结果:

预测值
[0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 1 0 1 0 0 0
0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0
0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 1 0 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0
0 1 0 1]
准确率:
0.7756653992395437

注:to_dict这个函数作用为将数据转换为字典类型

x_train转换后大概是这个样子的

mark

具体可以用法可以参考这篇博客

https://blog.csdn.net/weixin_42512684/article/details/104782158?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

可视化

同时决策树中也有可视化的API

sklearn.tree.export_graphviz() 该函数能够导出DOT格式

  • tree.export_graphviz(estimator,out_file='tree.dot’,feature_names=[‘’,’’])

在上面的案例中加一行代码

from sklearn.tree import export_graphviz
......
export_graphviz(estimator, out_file="./tree.dot", feature_names=['age', 'pclass=1st', 'pclass=2nd', 'pclass=3rd', '女性', '男性'])

这样生成的dot的文件

去这个网站http://webgraphviz.com/上粘贴上去就能生成可视化页面

mark

可视化页面大概如上图所示

对于决策树的介绍,大概就到这里了,本文完,下文大概是集成学习了