前几篇文章所用到的数据集都是用特征来描述的。 虽然的用到的数据集为交易类型的数据,形式
稍有不同,但归根结底还是一种用特征来描述的数据集。
除此之外,还有很多其他类型的数据集,比如文本、图像、声音、视频甚至是真实的物体。
然而,大多数数据挖掘算法都依赖于数值或类别型特征。 这表明在使用数据挖掘算法处理它们之
前,需要找到一种表示它们的方法。
本文所讨论的是如何从数据集中抽取数值和类别型特征,并选出最佳特征,前提是数据集确
实包含这些特征。 我们还会介绍特征抽取的常用模式和技巧。
本文主要介绍以下几个概念。
- 从数据集中抽取特征
- 创建新特征
- 选取好特征
- 创建转换器,处理数据集
特征抽取
特征抽取是数据挖掘任务最为重要的一个环节,一般而言,它对最终结果的影响要高过数据挖掘算法本身。 不幸的是,关于怎样选取好的特征,还没有严格、快捷的规则可循,其实这也是数据挖掘科学更像是一门艺术的所在。 创建好的规则离不开直觉,还需要专业领域知识和数据挖掘经验,光有这些还不够,还得不停地尝试、摸索,在试错中前进,有时多少还要靠点运气。
1.在模型中表示事实
不是所有的数据集都是用特征来表示的。 数据集可以是一位作家所写的全部书籍,也可以是
1979
年以来所有电影的胶片,还可以是馆藏的一批历史文物。
5.1
特征抽取
63
1
我们可能想对以上数据集做数据挖掘。 对于作家的作品,我们想知道这位作家都写过哪些主题;对于电影,我们想知道女性形象是怎么塑造的;对于文物,我们想知道它们是何方产物。 我们没办法把实物直接塞进决策树来得到结果。
只有先把现实用特征表示出来,才能借助数据挖掘的力量找到问题的答案。 特征可用于建模, 模型以机器挖掘算法能够理解的近似的方式来表示现实。 因此可以说,模型描述了客观世界中对象的某些方面,是它的一个简化版本。 举例来说,象棋就是对过往战事简化后得到的一种模型。
特征选择的另一个优点在于:降低真实世界的复杂度,模型比现实更容易操纵。 想象一下,向一个没有任何背景知识的人介绍一种新事物,要给出恰如其分、精确又不失全面的描述需要提供多少信息。 我们可能需要介绍其尺寸、重量、质地、成分、年龄、瑕疵、用途、产地等信息。
实物的复杂性对目前的算法而言过于复杂,我们退而求其次,使用更为简洁的模型来表示实物。
简化要以数据挖掘应用的目标为核心。 本书后面会讲到聚类,对这类应用而言,特征选取至关重要,如果随意选取特征,分簇结果因选择的特征而异,呈现出很强的随机性。
降低复杂性有好处,但也有不足,简化会忽略很多细节,甚至会抛弃很多对数据挖掘算法能起到帮助作用的信息。
我们应该始终关注怎么用模型来表示现实,要多考虑数据挖掘的目标,而不是轻率地用我们过去用过的特征。 要经常想想我们的目标是什么。 第3
章创建特征时充分考虑目标(预测赢家), 使用篮球比赛领域相关知识,找出哪些因素与比赛结果密切相关,据此再创建新特征。
用
Adult
数据集讲解如何借助特征为复杂的现实世界建模再好不过。 我们这里数据挖掘的目
标是,预测一个人是否年收入多于五万美元。 数据集下载地址为
http://archive.ics.uci.edu/ml/
datasets/Adult
,点击
Data Folder
链接。 下载
adult.data
和
adult.names
文件,在数据集文件夹(主目录下Data
文件夹)中创建
Adult
文件夹,将这两个文件放到里面。
数据集用特征描述了一个个活生生的人及其他们所处的环境、背景和生活状况。
打开
IPython Notebook
,新建一个笔记本文件用于本章实验,导入
pandas
模块,指定数据集文
件的路径,用
pandas
加载数据集文件。
import os
import pandas as pd
data_folder = os.path.join(os.path.expanduser("~"), "Data",
"Adult")
adult_filename = os.path.join(data_folder, "adult.data")
Using pandas as before, we load the file with read_csv:
adult = pd.read_csv(adult_filename, header=None,
names=["Age", "Work-Class", "fnlwgt",
"Education", "Education-Num",
"Marital-Status", "Occupation",
"Relationship", "Race", "Sex",
"Capital-gain", "Capital-loss",
"Hours-per-week", "Native-Country",
"Earnings-Raw"])
大部分代码前几篇文章都见过。
adult.data
文件末尾有两处空行。
pandas
默认把倒数第二行空行作为一条有效数据读入(只不
过各列的值为空)。 我们需要删除包含无效数字的行(设置
inplace
参数为真,表示改动当前数
据框,而不是新建一个)。
adult.dropna(how='all', inplace=True)
下面为所有保存在
pandas
的
Index
对象中的特征名称。
Index(['Age', 'Work-Class', 'fnlwgt', 'Education',
'Education-Num', 'Marital-Status', 'Occupation', 'Relationship',
'Race', 'Sex', 'Capital-gain', 'Capital-loss', 'Hours-per-week',
'Native-Country', 'Earnings-Raw'], dtype='object')
2.通用的特征创建模式
纵然有数不清的特征创建方法,但其中有一些是适用于不同学科的通用模式。然而,选择合适的特征是项技术活,需要考虑特征和最终结果之间的相互关系。正如谚语所说的,不要用封面来评价书的好坏——
如果你对书的内容感兴趣,书的大小当然也不用考虑。
一些通用特征关注的是所研究对象的物理属性。
- 空间属性,比如对象的长、宽、高
- 重量和(或)密度
- 年龄、使用年限或成分
- 种类
- 品质
另一些特征可能与对象的使用或历史相关。
- 生产商、出版商或创造者
- 生产时间
- 使用方法
还有一些特征从组成成分角度描述对象。
- 次级成分的频率,如一本书中某个单词的词频
- 次级成分的数量和(或)次级成分种类的数量
- 次级成分的平均大小,例如平均句长
序数特征可对其排序、分组。正如前几章所见到的,特征可以是数值或类别型特征。数值特
征通常被看作是
有顺序的
(
ordinal
)。例如,爱丽丝、鲍勃、查理三个人身高分别为
1.5m
、
1.6m
和
1.7m
。我们可以说爱丽丝和鲍勃,比起爱丽丝和查理,在身高上更相似。
我们导入的数据集,包含连续特征、序数特征。例如,
Hours-per-week
特征表示一个人每周的工作时间。这个特征可用来计算平均工作时间、标准差、最大值和最小值。pandas
提供了常见统计量的计算方法。
adult["Hours-per-week"].describe()
输出结果让我们对这个特征有了更多了解。
count 32561.000000
mean 40.437456
std 12.347429
min 1.000000
25% 40.000000
50% 40.000000
75% 45.000000
max 99.000000
dtype: float64
这些统计方法对其他特征可能没有意义。例如,计算受教育程度的和就讲不通
还有些特征,它们虽然不是数值,但仍然属于序数值,比如
Adult
数据集中的
Education
(教
育)特征,学士学位比高中毕业,在受教育程度上,要高一个层次,而高中毕业又比没有完成高
中学业高一个层次。计算它俩的均值就没有意义,但是我们可以找到一种近似的表示方法。数据
集有个叫作
Education-Num
(受教育年限)的特征,它的取值基本上就是每个教育阶段的年限。
这样我们就能快速计算受教育年限的均值。
adult["Education-Num"].median()
结果为
10
,或者可以表述为刚好读完高一。如果没有受教育年限数据,我们为不同教育阶段
指定数字编号,也可以计算均值。
array([' State-gov', ' Self-emp-not-inc', ' Private', ' Federal-gov',
' Local-gov', ' ?', ' Self-emp-inc', ' Without-pay',
' Never-worked', nan], dtype=object)
上做类似的区分
——
它们要么是同
一类,要么不是。
类别型特征二值化后就变成了数值型特征,第
3
章中曾经用过。对于上述球的种类,可以创建三个二值特征:“是网球”“是棒球”和“是足球”。如果是网球的话,特征向量就是[1, 0, 0]
, 棒球[0, 1, 0]
,足球
[0, 0, 1]
。这些特征都只有两个取值,很多算法都可以把它们作为连续型特征使用。二值化的好处是,便于直接进行数字上的比较(例如计算个体之间的距离)。
Adult
数据集包含一些类别型特征,例如
Work-Class
(工作),其中它的有些值可以进行量
级上的比较,比如不同的就业状况影响收入(例如有工作的人比没有工作的人收入高)。再比如,
州政府职员的工资不太可能比私企职工工资高。
用数据框的
unique
函数就能得到所有的工作情况。
from scipy.stats import pearsonr
输出结果如下:
array([' State-gov', ' Self-emp-not-inc', ' Private', ' Federal-gov',
' Local-gov', ' ?', ' Self-emp-inc', ' Without-pay',
' Never-worked', nan], dtype=object)
数据集部分数据缺失,但不会影响这里的计算。
同理,数值型特征也可以通过
离散化
过程转换为类别型特征,第
4
章中曾用过。例如,高于1.7m的人,我们称其为高个子,低于