5.用转换器抽取特征

# -*- coding: utf-8 -*-
"""
Created on Sat Sep 29 15:43:18 2018

@author: asus
"""
#5 用转换器抽取特征

#5.1 特征抽取
#特征抽取是数据挖掘任务最为重要的一个环节,一般而言,它对最终结果的影响要过高数据挖掘
#算法本身。

#5.1.1 在模型中表示事实
#特征选择,降低真实世界的复杂度,模型比现实更容易操纵。
#简化要以数据挖掘应用的目标为核心。
import pandas as pd
adult = pd.read_csv("Adult/adult.data.txt", 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)
adult.columns

#5.1.2 通用的特征创建模式
#一些通用特征关注的是所研究对象的物理属性。
#另一些特征可能与对象的使用或历史相关。
#还有一些特征从组成成分角度描述对象。
#序数特征可对其排序、分组。

#Hours-per-week特征表示一个人每周的工作时间。
adult["Hours-per-week"].describe()
#这些统计方法对其他特征可能没有意义。

#计算Education(教育)均值等没有意义,但近似可以用Education-Num(受教育年限)。
adult["Education-Num"].median()

#特征也可以是类别型的,也称为名义特征。
#类被指特征二值化后就变成了数值型特征。
adult["Work-Class"].unique
#数值特征也可以通过离散化过程转化为类别特征
adult["LongHours"] = adult["Hours-per-week"] > 40

#5.1.3 创建好的特征
#要拥有数据来源领域的知识,没有的话,要积极去掌握。弄清楚问题是什么后,了解有哪些可用
#数据后,在此基础上,才能创建解决问题所需的模型

#5.2 特征选择
#降低复杂度;降低杂音;增加模型的可读性。

#在开展数据挖掘之前,有些基础性测试我们要做,比如确保特征值是不同的。如果特征值都相同,
#就跟没提供什么信息一样,挖掘就失去了意义。
#scikit-learn中VarianceThreshold转换器可用来删除特征值的方差达不到最低标准的特征。
import numpy as np
x = np.arange(30).reshape((10, 3))
x
x[:,1] = 1 #把所有第二列都改为1
x
from sklearn.feature_selection import VarianceThreshold
vt = VarianceThreshold() #转换器
xt = vt.fit_transform(x)
xt
print(vt.variances_) #输出每一列的方差

#选择最佳特征
#特征很多的情况下,怎么选出最佳的几个,可有点难度。计算量非常大。
#其中一个变通的方法是不要找表现好的子集,而只是去找表现好的单个特征(单变量),依据是
#它们各自所能达到的精确度。
#scikit-learn提供了几个用于选择单变量特征的转换器,其中SelectKBest返回k个最佳特征,
#SelectPercentile返回表现最佳的前r%个特征。
#单个特征和某一类别之间相关性的计算方法有很多。最常用的有卡方检验。还有互信息和信息熵。

x = adult[["Age", "Education-Num", "Capital-gain", "Capital-loss", 
           "Hours-per-week"]].values
#判断Earning-Raw(税前收入)是否达到五万美元,创建目标类别列表。如果达到,类别为True,
#否则,类别为False。
y = (adult["Earnings-Raw"] == ' >50K').values  #此处要注意,是否成功分类了
#再使用SelectKBest转换器类,用卡房函数打分,初始化转换器。
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
transformer = SelectKBest(score_func=chi2, k=3)
#调用fit_transform方法,对相同的数据集进行预处理和转换。结果为分类效果较好的三个特征。
xt_chi2 = transformer.fit_transform(x, y)
#生成的矩阵只包括三个特征。我们还可以得到每一列的相关性,这样就可以知道都使用了哪些特
#征。
print(transformer.scores_)
#年龄"Age", 资本收益"Capital-gain", 资本损失"Capital-loss"三个特征相关性最好,从单
#变量特征选取的角度来说,这些就是最佳特征。

#还可以用其他方法计算相关系数,如皮尔逊(Pearson)相关系数
from scipy.stats import pearsonr
#pearsonr函数参数为两个数组,但要注意第一各参数x为一维数组。我们来实现一个包装器函数,
#来处理多维数组。
def multivariate_pearsonr(x, y):
    scores, pvalues = [], []
    for column in range(x.shape[1]):
        cur_score, cur_p = pearsonr(x[:,column], y)
        scores.append(abs(cur_score))
        pvalues.append(cur_p)
    return (np.array(scores), np.array(pvalues))
#现在,我们就可以像之前那样使用转换器类,根据皮尔逊相关系数对特征进行排序。
transformer = SelectKBest(score_func=multivariate_pearsonr, k=3)
xt_pearson = transformer.fit_transform(x, y)
print(transformer.scores_)
#返回的特征跟用卡方检验计算相关性得到的特征不一样。这表明哪些特征是最好的这个问题没有
#标准答案——取决于度量标准。

#在分类器中看看哪个特征集合效果更好
from sklearn.tree import DecisionTreeClassifier #决策树
from sklearn.cross_validation import cross_val_score #交叉检验
clf = DecisionTreeClassifier(random_state=14)
scores_chi2 = cross_val_score(clf, xt_chi2, y, scoring='accuracy')
scores_pearson = cross_val_score(clf, xt_pearson, y, scoring='accuracy')
print(np.mean(scores_chi2) * 100)
print(np.mean(scores_pearson) * 100)

#5.3 创建特征
import pandas as pd
import numpy as np
from collections import defaultdict
#前几个特征是数值,但是pandas会把它们当作字符串。我们需要把字符串转换为数字的函数,该
#函数能够把只包含数字的字符串转换为数字,把其余的转化为“NaN”。并且数据集中有些缺失值,
#用“?”表示的,我们也将其转换为NaN。

#转换函数
def convert_number(x):
    try:
        return float(x)
    except ValueError:
        return np.nan
#我们创建一个字典存储所有特征及其转换结果,把所有的特征值转换为浮点型。
converters = defaultdict(convert_number)
#还想把最后一列的值转换为0或1,该列表示每条数据的类别。
converters[1558] = lambda x: 1 if x.strip() == "ad." else 0
#加载数据集,在参数中指定我们刚创建的转化函数。
ads = pd.read_csv("Adult/ad.data", header=None, converters=converters)
ads = ads.replace('?', np.nan)
ads = ads.replace('   ?', np.nan)   #第1,2列转换为NAN
ads = ads.replace('     ?', np.nan) #第3列转换为NAN
ads = ads.replace(np.nan, 0) #缺失值处理不到位,以后不能直接化0。看情况处理,本题应该取前2列取均值,第三列为前两列的比。
ads[:5]
#数据集所描述的是网上的图像,目标是确定图像是不是广告。
#从数据集表头中无法获知梅列数据的含义。其他文件有更多的信息。前三个特征分别指图像的高
#度、宽度和宽高比。最后一列是数据的类别,1表示是广告,0表示不是广告。

#抽取用于分类算法的x矩阵和y数组,x矩阵为数据框除去最后一列的所有列,y数组包含数据框的
#最后一列。
X = ads.drop(1558, axis=1).values
y = ads[1558]

#主成分分析(PCA)
#该算法的目的是找到能用较少信息描述数据集的特征组合。
from sklearn.decomposition import PCA
pca = PCA(n_components=5)
Xd = pca.fit_transform(X)
#返回的结果只有五个特征,看一下每个特征的方差
np.set_printoptions(precision=3, suppress=True)
pca.explained_variance_ratio_
#提升分类任务的正确率
clf = DecisionTreeClassifier(random_state=14)
scores_reduced = cross_val_score(clf, Xd, y, scoring='accuracy')
scores_reduced.mean()
#将数据集绘制成图形,如,把PCA返回的前两个特征作为图形
from matplotlib import pyplot as plt
classes = set(y)
colors = ['red', 'green'] #指定在图形中的颜色
for cur_class, color in zip(classes, colors):
    mask = (y == cur_class).values
    plt.scatter(Xd[mask, 0], Xd[mask, 1], marker='o', color=color, 
                label=int(cur_class))
plt.legend()
plt.show()

#5.4 创建自己的转换器
#5.4.1 转换器API
#fit():接收训练数据,设置内部参数。
#transform():转换过程。接收训练数据集或相同格式的新数据集

#fit()和transform()函数的输入应该为同一种数据类型,但是transform()可以返回不同的数据
#类型。

#转换器接收numpy数组作为输入,根据均值将其离散化。任何高于均值的特征值(训练集中)替换
#为1,小于或等于均值的替换为0.

#5.4.2 实现细节
#执行5.1节的数据集,得到x,y
from sklearn.base import TransformerMixin
from sklearn.utils import as_float_array
class MeanDiscrete(TransformerMixin):
    def fit(self, X, y=None):
        X = as_float_array(X) #尝试对X进行转换,例如X是浮点型列表是就可以进行转换
        self.mean = X.mean(axis=0) #计算数组的均值,用内部变量保存。每个特征的均值
        return self   #fit函数返回自身
    def transform(self, X):
        X = as_float_array(X) 
        assert X.shape[1] == self.mean.shape[0] #输入必须是numpy数组(或等价的数据结构),还需要检查数据列数是否一致。X中的特征数应改与训练集中的特征数一致。
        return X > self.mean #函数返回X中大于均值的数据
mean_discrete = MeanDiscrete()
X_mean = mean_discrete.fit_transform(x)

#5.4.3 单元测试
from numpy.testing import assert_array_equal
#用来检测两个数组是否相等

#创建测试函数
def test_meandiscrete():
    X_test = np.array([[0, 2],
                       [3, 5],
                       [6, 8],
                       [9, 11],
                       [12, 14],
                       [15, 17],
                       [18, 20],
                       [21, 23],
                       [24, 26],
                       [27, 29]])
    mean_discrete = MeanDiscrete()
    mean_discrete.fit(X_test)
    assert_array_equal(mean_discrete.mean, np.array([13.5, 15.5]))
    X_transformed = mean_discrete.transform(X_test)
    X_expected = np.array([[0, 0],
                           [0, 0],
                           [0, 0],
                           [0, 0],
                           [0, 0],
                           [1, 1],
                           [1, 1],
                           [1, 1],
                           [1, 1],
                           [1, 1]])
    assert_array_equal(X_transformed, X_expected)
#调用函数,开始测试
test_meandiscrete()

#5.4.4 组装起来
#第一步用MeanDiscrete转换器,第二步用决策树分类器,然后进行交叉检验
from sklearn.pipeline import Pipeline
from sklearn.tree import DecisionTreeClassifier #决策树
from sklearn.cross_validation import cross_val_score #交叉检验
pipeline = Pipeline([('mean_discrete', MeanDiscrete()),
                     ('classifier', DecisionTreeClassifier(random_state=14))])
scores_mean_discrete = cross_val_score(pipeline, x, y, scoring='accuracy')
print("Mean Discrete performance:{0:.3f}".format(scores_mean_discrete.mean()))




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值