文章目录

  • Python数据挖掘框架
  • 项目背景与分析
  • 数据读入与检查
  • 数据预处理
  • 数据校正
  • 缺失值填充
  • 均值填充
  • 填充固定值0值填充
  • 众数填充
  • 中位数填充
  • 中位数或均值+随机标准差
  • 填充上下条的数据
  • 插值填充
  • 填充KNN数据
  • 填充模型预测的值
  • 数据创建
  • 数据转换
  • 最大最小标准化(max-min标准化)
  • z-score变换
  • 对数变换
  • box-cox变换
  • 数据清洗
  • 缺失值
  • 异常值
  • 无关值
  • 噪音
  • 重复值
  • 数据集成
  • 数据规约
  • 维归约
  • 属性子集选择
  • 启发式的(探索性的)方法
  • 数据压缩
  • 数值归约
  • 多元回归
  • 无参方法
  • 数据划分
  • 留出法
  • 交叉验证法
  • 自助法
  • 探索性分析
  • **单变量分析**
  • **双变量分析**
  • **多变量分析**
  • 多变量方差分析
  • 主成分分析
  • 因子分析
  • 典型相关分析
  • 聚类分析
  • 判别分析
  • 多维量表分析
  • 线性结构方程
  • 逻辑斯蒂回归分析
  • 对数线性方程
  • Logit对数线性模型
  • 列联表分析
  • 相关分析
  • 方差分析
  • 建模分析
  • 模型评估与优化
  • 交叉验证
  • 超参数调整
  • 特征选择
  • 模型验证
  • 改进与总结


Python数据挖掘框架

参考:https://zhuanlan.zhihu.com/p/258542655

项目背景与分析

以泰坦尼克号生存者问题为例。使用机器学习工具来预测哪些乘客可以幸免于悲剧。

数据读入与检查

  1. 导入与数据处理相关的库,并检查版本与数据文件夹
import sys 
print("Python version: {}". format(sys.version))

import pandas as pd 
print("pandas version: {}". format(pd.__version__))

import matplotlib 
print("matplotlib version: {}". format(matplotlib.__version__))

import numpy as np 
print("NumPy version: {}". format(np.__version__))

import scipy as sp 
print("SciPy version: {}". format(sp.__version__)) 

import IPython
from IPython import display 
print("IPython version: {}". format(IPython.__version__)) 

import sklearn 
print("scikit-learn version: {}". format(sklearn.__version__))

import random
import time

#忽略警号
import warnings
warnings.filterwarnings("ignore")
print('-'*25)

# 将三个数据文件放入主目录下 

from subprocess import check_output
print(check_output(["ls"]).decode("utf8"))
  1. 导入与建模预测相关的库
from sklearn import svm, tree, linear_model, neighbors, naive_bayes, ensemble, discriminant_analysis, gaussian_process
from xgboost import XGBClassifier

from sklearn.preprocessing import OneHotEncoder, LabelEncoder
from sklearn import feature_selection
from sklearn import model_selection
from sklearn import metrics

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.pylab as pylab
import seaborn as sns
from pandas.plotting import scatter_matrix
  1. 使用info()sample()函数来快速概览变量数据类型
#可视化相关设置
%matplotlib inline
mpl.style.use('ggplot')
sns.set_style('white')
pylab.rcParams['figure.figsize'] = 12,8
data_raw = pd.read_csv('train.csv')
data_val  = pd.read_csv('test.csv')

data1 = data_raw.copy(deep = True)
data_cleaner = [data1, data_val]

print (data_raw.info()) 
data_raw.sample(10)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId    891 non-null int64
Survived       891 non-null int64
Pclass         891 non-null int64
Name           891 non-null object
Sex            891 non-null object
Age            714 non-null float64
SibSp          891 non-null int64
Parch          891 non-null int64
Ticket         891 non-null object
Fare           891 non-null float64
Cabin          204 non-null object
Embarked       889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.6+ KB
None
  • 存活变量是我们的结果或因变量。这是一个二进制标称数据类型。1幸存,0没有生存。所有其他变量都是潜在的预测变量或独立变量。重要的是要注意,更多的预测变量并不会形成更好的模型,而是正确的变量才会。
  • 乘客ID票证变量被假定为随机唯一标识符,对结果变量没有影响。因此,他们将被排除在分析之外。
  • Pclass变量是票券类的序数数据,是社会经济地位(SES)的代表,代表1 =上层,2=中产阶级,3 =下层。
  • Name变量是一个标称数据类型。用于提取特征中,可以从标题、家庭大小、姓氏中获得性别,如SES可以从医生或硕士来判断。因为这些变量已经存在,我们将利用它来查看title(如master)是否会产生影响。
  • 性别装载变量是一种名义数据类型。它们将被转换为数学计算的哑变量
  • 年龄费用变量是连续的定量数据类型。
  • SIBSP代表相关上船的兄弟姐妹/配偶的数量,而PARCH代表上船的父母/子女的数量。两者都是离散的定量数据类型。这可以特征工程创建一个关于家庭大小的变量
  • 舱室变量是一个标称数据类型,可用于特征工程中描述事故发生时船舶上的大致位置和从甲板上的船位。然而,由于有许多空值,它不增加值,因此被排除在分析之外

数据预处理

在本节我们将通过数据清洗4c原则进行处理

  • 校正(Correcting)
  • 填充(Completing)
  • 创建(Creating)
  • 转换(Converting)

数据校正

检查数据,似乎没有任何异常或不可接受的数据输入。
此外,我们发现我们在年龄和票价上可能存在潜在异常值。但是,由于它们是合理的值,我们将等到完成探索性分析后再确定是否应从数据集中包括或排除。应该注意的是,如果它们是不合理的值,例如age = 800而不是80,那么现在修复是一个安全的决定。但是,从原始值修改数据时,我们要格外小心,因为可能需要创建准确的模型。

缺失值填充

参考:

  • 删除记录:缺失严重确实较多的情况
  • 估算缺失值

均值填充

train_data.fillna(train_data.mean(),inplace=True) # 填充均值

填充固定值0值填充

train_data.fillna(0, inplace=True) # 填充 0

众数填充

train_data.fillna(train_data.mode(),inplace=True) # 填充众数,该数据缺失太多众数出现为nan的情况
features_mode = {}
for f in features:
    print f,':', list(train_data[f].dropna().mode().values)
    features_mode[f] = list(train_data[f].dropna().mode().values)[0]
train_data.fillna(features_mode,inplace=True)

中位数填充

train_data.fillna(train_data.median(),inplace=True) # 填充中位数

中位数或均值+随机标准差

填充上下条的数据

对每一条数据的缺失值,填充其上下条数据的值。

train_data.fillna(method='pad', inplace=True) # 填充前一条数据的值,但是前一条也不一定有值
train_data.fillna(0, inplace=True)
 
train_data.fillna(method='bfill', inplace=True) # 填充后一条数据的值,但是后一条也不一定有值
train_data.fillna(0, inplace=True)

插值填充

用插值法拟合出缺失的数据,然后进行填充。

for f in features: # 插值法填充
    train_data[f] = train_data[f].interpolate()
    
train_data.dropna(inplace=True)

填充KNN数据

填充近邻的数据,先利用knn计算临近的k个数据,然后填充他们的均值。
- (安装fancyimpute)除了knn填充,fancyimpute还提供了其他填充方法。

from fancyimpute import KNN
 
train_data_x = pd.DataFrame(KNN(k=6).fit_transform(train_data_x), columns=features)

填充模型预测的值

把缺失值作为新的label,建立模型得到预测值,然后进行填充。这里选择某个缺失值数量适当的特征采用随机森林RF进行拟合,其他缺失特征采用均值进行填充

new_label = 'SNP46'
new_features = []
for f in features:
    if f != new_label:
        new_features.append(f)
        
new_train_x = train_data[train_data[new_label].isnull()==False][new_features]
new_train_x.fillna(new_train_x.mean(), inplace=True) # 其他列填充均值
new_train_y = train_data[train_data[new_label].isnull()==False][new_label]
 
new_predict_x = train_data[train_data[new_label].isnull()==True][new_features]
new_predict_x.fillna(new_predict_x.mean(), inplace=True) # 其他列填充均值
new_predict_y = train_data[train_data[new_label].isnull()==True][new_label]
 
rfr = RandomForestRegressor(random_state=666, n_estimators=10, n_jobs=-1)
rfr.fit(new_train_x, new_train_y)
new_predict_y = rfr.predict(new_predict_x)
 
new_predict_y = pd.DataFrame(new_predict_y, columns=[new_label], index=new_predict_x.index)
new_predict_y = pd.concat([new_predict_x, new_predict_y], axis=1)
new_train_y = pd.concat([new_train_x, new_train_y], axis=1)
new_train_data = pd.concat([new_predict_y,new_train_y]) 
 
train_data_x = new_train_data[features]
train_data_y = train_data['label']

年龄机舱出发区域中存在空值或缺少数据。缺少值可能是不好的,因为某些算法不知道如何处理空值,并且会失败。而其他决策树等可以处理空值。因此,在开始建模之前进行修复很重要,因为我们将比较和对比多个模型。有两种常用方法,即删除记录或使用合理的输入填充缺失值。不建议删除该记录,尤其是大部分记录,除非它确实代表不完整的记录。相反,最好估算缺失的值。定性数据的基本方法是估算使用模式。定量数据的基本方法是使用均值,中位数或均值+随机标准差估算。中间方法是根据特定标准使用基本方法。例如按舱位划分的平均年龄,或按票价和SES出发前往港口。有更复杂的方法,但是在部署之前,应将其与基本模型进行比较,以确定复杂性是否真正增加了价值。对于此数据集,年龄将用中位数来估算机舱属性将被删除,而登船将以模型进行估算。随后的模型迭代可能会修改此决策,以确定它是否会提高模型的准确性。

数据创建

特征工程是当我们使用现有特征来创建新特征以确定它们是否提供新信号来预测我们的结果时。对于此数据集,我们将创建标题功能以确定其是否在生存中发挥作用。

数据转换

在进行数据预处理中经常用到数据变换,通过相应的变换操作,能够将数据变换到正态分布中,消除数据之间的量纲问题,使数据看起来更加的规整,这样建模得出来的结果才会更准确。

最大最小标准化(max-min标准化)

最大最小标准化方法主要用于将数据缩放到[0,1]范围内,避免数据的分布太过广泛,但是这种方法有一个致命的缺点,就是其容易受到异常值的影响,一个异常值可能会将变换后的数据变为偏左或者是偏右的分布,因此在做最大最小标准化之前一定要去除相应的异常值才行。

数据挖掘技术架构 数据挖掘的框架_缺失值

from sklearn.preprocessing import minmax_scale,MinMaxScaler
from sklearn.datasets import load_iris

iris = load_iris()
iris_x = iris['data']


# 方法一  常用
print(iris_x)
minmax_scalar = MinMaxScaler()
minmax_scalar = minmax_scalar.fit(iris_x)
iris_x_scala1 = minmax_scalar.transform(iris_x)

print(iris_x_scala1)

# 方法二
iris_x_scala2 = minmax_scale(iris_x)
print(iris_x_scala2)
z-score变换

z-score变换通常用于将数据变换为正态分布,因为一般的统计分析方法都在假设数据服从正态分布,所有有的模型要求输入数据需为正态分布,遇到这类的模型时需要应用z-score变换。

数据挖掘技术架构 数据挖掘的框架_scala_02

from sklearn.preprocessing import scale,StandardScaler
from sklearn.datasets import load_iris

iris =load_iris()
iris_x = iris['data']

# 方法一
standar_scaler = StandardScaler()
standar_scaler.fit(iris_x)
iris_x_scala1 = standar_scaler.transform(iris_x)
print(iris_x_scala1)

# 方法二
iris_x_scala2 = scale(iris_x)
print(iris_x_scala2)
对数变换

对数变换能够缩小数据的绝对范围,取乘法操作相当于对数变换后的加法操作。

数据挖掘技术架构 数据挖掘的框架_数据挖掘技术架构_03

box-cox变换

box-cox变换是统计建模中常用的数据变换方法,用于连续的响应变量不满足正态分布的情况。Box-Cox变换之后,可以一定程度上减小不可观测的误差和预测变量的相关性。

数据挖掘技术架构 数据挖掘的框架_数据挖掘技术架构_04


从上面的式子中能够看出box-cox变换最终的形式是由数据挖掘技术架构 数据挖掘的框架_数据_05

(1)当 数据挖掘技术架构 数据挖掘的框架_数据挖掘技术架构_06

(2)当数据挖掘技术架构 数据挖掘的框架_缺失值_07

(3)当数据挖掘技术架构 数据挖掘的框架_scala_08

Python中的scipy.stats.boxcox() 定义了boxcox变换,确定了 数据挖掘技术架构 数据挖掘的框架_数据_05

最后但同样重要的是,我们将对数据格式进行转换。对于此数据集,我们将对象数据类型转换为分类虚拟变量。

print('Train columns with null values:\n', data1.isnull().sum())
print("-"*10)

print('Test/Validation columns with null values:\n', data_val.isnull().sum())
print("-"*10)

data_raw.describe(include = 'all')

数据清洗

完成这个步骤你需要对下面的Pandas功能有一定的了解

pandas.DataFrame
pandas.DataFrame.info
pandas.DataFrame.describe
Indexing and Selecting Data
pandas.isnull
pandas.DataFrame.sum
pandas.DataFrame.mode
pandas.DataFrame.copy
pandas.DataFrame.fillna
pandas.DataFrame.drop
pandas.Series.value_counts
pandas.DataFrame.loc

缺失值

1、删除:数量较少,对整体数据没什么影响的直接删除该条数据。
2、对缺失数据插补:方法较多,例如用该属性的均值、众数、中位数插补
3、最近邻插补,使用与缺失样本最接近的样本的该属性值插补;
4、回归法(建模预测):就是根据样本集的其他属性来建立一个拟合模型预测缺失属性的值,根据模型来计算缺失值。常用的缺失值处理方法就这些,还有许多其他的方法,如拉格朗日插值等等。

异常值

首先要知道如何找出某个属性的异常值。一般用的方法是画箱型图

数据挖掘技术架构 数据挖掘的框架_缺失值_10

下四分位数(Q1)=(数据个数+1)0.25

上四分位数(Q3)=(数据个数+1)0.75

盒子长度IQR = Q3-Q1

最小观测值(下边缘)=Q1 - 1.5IQR

最大观测值(上边缘)=Q3+ 1.5IQR

不在最小最大观测值范围内的视为异常值

处理异常值:1、直接删除,2、当作缺失值、用缺失值的处理方法;3、暂时保留。

无关值

像id这种无关的属性直接删掉即可,样本集中可能还有其它的无关属性,需要根据业务情况具体分析才行可进行无关属性的转换或删除。

噪音

1、分箱:通过考察相邻数据来确定最终值。实际上就是按照属性值划分的子区间,如果一个属性值处于某个子区间范围内,就称把该属性值放进这个子区间所代表的“箱子”内。把待处理的数据(某列属性值)按照一定的规则放进一些箱子中,考察每一个箱子中的数据,采用某种方法分别对各个箱子中的数据进行处理。分箱的方法一般有等深分箱法、等宽分箱法、最小熵法和用户自定义区间法。数据平滑方法按平均值平滑、按边界值平滑和按中值平滑。按平均值平滑:对同一箱值中的数据求平均值,用平均值替代该箱子中的所有数据。按边界值平滑:用距离较小的边界值替代箱中每一数据。按中值平滑:取箱子的中值,用来替代箱子中的所有数据
2、聚类:将物理的或抽象对象的集合分组为由类似的对象组成的多个类。找出并清除那些落在簇之外的值(孤立点),这些孤立点被视为噪声
3、回归;试图发现两个相关的变量之间的变化模式,通过使数据适合一个函数来平滑数据,即通过建立数学模型来预测下一个数值,包括线性回归和非线性回归。

重复值

对于重复项的判断,基本思想是“排序与合并”,先将数据集中的记录按一定规则排序,然后通过比较邻近记录是否相似来检测记录是否重复。这里面其实包含了两个操作,一是排序,二是计算相似度。一般过程中主要是用duplicated方法进行判断,然后将重复的样本进行简单的删除处理。

###缺失值处理
for dataset in data_cleaner:    
    #用中位数填充
    dataset['Age'].fillna(dataset['Age'].median(), inplace = True)
    dataset['Embarked'].fillna(dataset['Embarked'].mode()[0], inplace = True)
    dataset['Fare'].fillna(dataset['Fare'].median(), inplace = True)
    
#删除部分数据
drop_column = ['PassengerId','Cabin', 'Ticket']
data1.drop(drop_column, axis=1, inplace = True)

print(data1.isnull().sum())
print("-"*10)
print(data_val.isnull().sum())

接下来我们将把分类数据转换成用于数学分析的哑变量。有多种方法来对分类变量进行编码,在这个步骤中,我们还将定义X(独立/特征/解释/预测器/等)和Y(依赖/目标/结果/响应/等)变量用于数据建模。

label = LabelEncoder()
for dataset in data_cleaner:    
    dataset['Sex_Code'] = label.fit_transform(dataset['Sex'])
    dataset['Embarked_Code'] = label.fit_transform(dataset['Embarked'])
    dataset['Title_Code'] = label.fit_transform(dataset['Title'])
    dataset['AgeBin_Code'] = label.fit_transform(dataset['AgeBin'])
    dataset['FareBin_Code'] = label.fit_transform(dataset['FareBin'])

Target = ['Survived']

data1_x = ['Sex','Pclass', 'Embarked', 'Title','SibSp', 'Parch', 'Age', 'Fare', 'FamilySize', 'IsAlone'] #pretty name/values for charts
data1_x_calc = ['Sex_Code','Pclass', 'Embarked_Code', 'Title_Code','SibSp', 'Parch', 'Age', 'Fare'] #coded for algorithm calculation
data1_xy =  Target + data1_x
print('Original X Y: ', data1_xy, '\n')
#为原始特征定义x变量以删除连续变量
data1_x_bin = ['Sex_Code','Pclass', 'Embarked_Code', 'Title_Code', 'FamilySize', 'AgeBin_Code', 'FareBin_Code']
data1_xy_bin = Target + data1_x_bin
print('Bin X Y: ', data1_xy_bin, '\n')

data1_dummy = pd.get_dummies(data1[data1_x])
data1_x_dummy = data1_dummy.columns.tolist()
data1_xy_dummy = Target + data1_x_dummy
print('Dummy X Y: ', data1_xy_dummy, '\n')

data1_dummy.head()

现在我们已经基本完成了数据的清洗,让我们再次进行检查

print('Train columns with null values: \n', data1.isnull().sum())
print("-"*10)
print (data1.info())
print("-"*10)

print('Test/Validation columns with null values: \n', data_val.isnull().sum())
print("-"*10)
print (data_val.info())
print("-"*10)

data_raw.describe(include = 'all')

数据集成

数据集成就是为了将不同数据源的数据整合导一个数据库中,需要注意的是集成过程中可能产生的问题。

  1. 属性(字段名)意义问题:即同一字段名所代表的含义不一样,例如’日期‘,可能一个数据源中表示生产日期,一个数据源表示’保质日期‘;
  2. 字段结构问题:即不同的字段名表示的是一样的数据;字段的数据类型不同;字段数据格式不同;字段单位不同等;
  3. 字段冗余问题:集成后的字段之间具有较强的相关性,可以相互推导出。(ps:相关性的计算可以用卡方检验或者协方差皮尔逊相关系数等)
  4. 一般在集成前,可以先做个表将个数据源的字段名,类型等统计一下,再做处理

数据规约

数据规约则是对减少过多的属性(维度、特征)对预测的模型的影响,常用方法:合并属性主成成分分析(PCA)逐步向前(向后删除)低方差特征过滤one-hot编码等。

维归约

通过删除不相干的额属性和维数减少数据量

属性子集选择
1. 找出最小的属性集,使得数据类的概率分布尽可能接近所有属性的原分布 
  2. 减少出现在出现模式上的属性的数目,使得模式更容易于理解
启发式的(探索性的)方法
1. 逐步向前选择
    2. 逐步向后删除
    3. 向前选择和向后删除相结合 
    4. 判定归纳树(分类算法)
    5. **基于统计分析的归约:主成分分析,回归分析**
数据压缩
- 有损压缩 vs 无损压缩
  -  字符串压缩 
    有广泛的理论基础和精妙的算法 
    通常是无损压缩 
    在解压缩前对字符串的操作非常有限
    音频/视频 压缩 
    通常是有损压缩,压缩精度可以递进选择 
    有时候可以在不解压整体数据的情况下,重构某个片段
- 两种有损数据压缩的方法: **小波变换**和**主要成分分析**

数值归约

- 通过选择替代的、较小的数据表示形式来减少数据量
  - 有参方法:使用一个参数模型估计数据,最后只要存储参数即可。
    线性回归方法

多元回归

对数线性模型:近似离散的多维数据概率分布

无参方法

直方图
聚类
选样

数据划分

[]

留出法

“留出法”直接将数据集 D划分为两个互斥的集合,一个为训练集 S ,一个为测试集 T ,即 D = S ∪ T , S ∩ T = ∅ .在S上进行模型学习,然后用T来评估其测试误差,作为对泛化误差的估计.
[单次使用留出法得到的估计结果往往不够稳定可靠,在使用留出法时,一般要采用若干次随机划分、重复进行模型评估后取平均值作为留出法的评估结果]

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC #导入支持向量机分类算法
from sklearn.metrics import accuracy_score
data = datasets.load_iris() #导入数据集
X = data['data']
y = data['target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3) #对数据集进行划分
clf = SVC()
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)

print(accuracy_score(y_test, y_pred)) #打印准确率

交叉验证法

“交叉验证法”先将数据集D划分为k个大小相同的互斥子集,即 D = D 1 ∪ D 2 ∪ ⋯ ∪ D k , D i ∩ D j = ∅ ( i ≠ j ) . 其中每个子集 D i D_i Di都应尽量保持数据分布的一致性,即从 D中通过分层采样得到。
然后,每次都用其中的k−1个子集的并集作为训练集,余下一个作为测试集,这样就可以得到 k组训练集/测试集,从而可以进行 k次模型的学习,并把这 k 个测试结果的均值作为评估结果,通常我们把交叉验证法称为“k折交叉验证”。
将数据集 D划分为 k个子集存在多种划分方式,为了减小因样本划分不同而引入的差别, k 折交叉验证可以随机使用不同的划分重复 p次,最终的评估的结果是这 p 次 k折交叉验证结果的均值。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Feb 25 11:27:09 2019

@author: lihui
"""

from sklearn import datasets
from sklearn.model_selection import KFold, RepeatedKFold
from sklearn.linear_model import LogisticRegression #导入逻辑回归分类算法
from sklearn.metrics import accuracy_score

data = datasets.load_iris() #导入数据集
X = data['data']
y = data['target']

clf = LogisticRegression(solver='newton-cg') #设置优化方法为牛顿法

k_fold = 10 #设置为10折划分
kf = KFold(n_splits=k_fold) 
averg_score = 0
for train_index, test_index in kf.split(X):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
    clf.fit(X_train, y_train)
    y_pred = clf.predict(X_test)
    averg_score += accuracy_score(y_test, y_pred)
print("%d折交叉验证的准确率的平均值为%f"%(k_fold, averg_score / k_fold))

averg_score = 0
repeats_num = 10
rkf = RepeatedKFold(n_splits=k_fold, n_repeats=repeats_num)
for train_index, test_index in rkf.split(X):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
    clf.fit(X_train, y_train)
    y_pred = clf.predict(X_test)
    averg_score += accuracy_score(y_test, y_pred)
averg_score = averg_score / (repeats_num * k_fold)
print("%d次%d折交叉验证的准确率的平均值为%f"%(repeats_num, k_fold, averg_score))

如果令 k = m,则得到了交叉验证的一个特例:留一法,留一法使用的训练集与初始数据集相比只少了一个样本,这就使得留一法中被实际评估的模型与期望评估的用 D训练出的模型很相似。因此,留一法的评估结果往往被认为比较准确,但是缺陷就是碰到大数据集时,计算开销时无法接受的。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Feb 25 12:07:23 2019

@author: lihui
"""

from sklearn import datasets
from sklearn.model_selection import KFold, RepeatedKFold, LeaveOneOut
from sklearn.linear_model import LogisticRegression #导入逻辑回归分类算法
from sklearn.metrics import accuracy_score

data = datasets.load_iris() #导入数据集
X = data['data']
y = data['target']

clf = LogisticRegression(solver='newton-cg') #设置优化方法为牛顿法

averg_score = 0
loo = LeaveOneOut()
for train_index, test_index in loo.split(X):
        X_train, X_test = X[train_index], X[test_index]
        y_train, y_test = y[train_index], y[test_index]
        #print(X_train, X_test, y_train, y_test)
        clf.fit(X_train, y_train)
        y_pred = clf.predict(X_test)
        averg_score += accuracy_score(y_test, y_pred)
averg_score = averg_score / len(y)
print("留一法准确率的平均值为%f"%averg_score)

自助法

在留出法和交叉验证法中保留了一部分样本用于测试,但是我们希望模型是利用 D D D训练出来的。因此,“自助法”是一个比较好的解决方法,它对数据集 D D D进行采样产生新数据集 D ′ D^{'} D′:每次从 D D D中进行有放回的随机采样,取得样本放入 D ′ D^{'} D′中,直至 D ′ D^{'} D′的样本个数也为 m . m. m.显然, D D D中的一部分样本有可能会多次出现在 D ′ D^{'} D′中,对任意一个样本,在 m m m次采样中没有被取到的概率为 ( 1 − 1 m ) m (1-\frac{1}{m})^{m} (1−m1)m,当样本个数 m → + ∞ m\to+\infty m→+∞时,有

数据挖掘技术架构 数据挖掘的框架_scala_11


即通过自住法采样,数据集 D D D中约有 36.8 36.8% 36.8的样本未出现在数据集 D ′ D^{'} D′中,于是可以将 D ′ D^{'} D′用作训练集, D / D ′ D/D^{'} D/D′用作测试集.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Feb 25 12:17:03 2019

@author: lihui
"""

import numpy as np
from sklearn import datasets
from sklearn.linear_model import LogisticRegression #导入逻辑回归分类算法
from sklearn.metrics import accuracy_score
import random

data = datasets.load_iris() #导入数据集
X = data['data']
y = data['target']

clf = LogisticRegression(solver='newton-cg') #设置优化方法为牛顿法

train_index = [random.randint(0, len(y)-1) for i in range(len(y))] #随机产生训练集的下标
test_index = list(set(np.arange(len(y))) - set(train_index)) 
X_train = X[train_index] #根据随机产生的下标在X中采样得到训练集
X_test = X[test_index]
y_train = y[train_index]
y_test = y[test_index]
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
print("自助法的准确率为%f"%accuracy_score(y_test, y_pred))

自助法在数据集较小、难以有效划分训练/测试集时很有用。此外,自助法能从初始数据集中产生多个不同的训练集,这对集成学习等方法有很大好处。但是,自助法产生的数据集改变了初始数据集的分布,这会引入偏差。因此,在初始数据集足够多时,留出法和交叉验证法更加常用

  • 划分测试集与训练集
train1_x, test1_x, train1_y, test1_y = model_selection.train_test_split(data1[data1_x_calc], data1[Target], random_state = 0)
train1_x_bin, test1_x_bin, train1_y_bin, test1_y_bin = model_selection.train_test_split(data1[data1_x_bin], data1[Target] , random_state = 0)
train1_x_dummy, test1_x_dummy, train1_y_dummy, test1_y_dummy = model_selection.train_test_split(data1_dummy[data1_x_dummy], data1[Target], random_state = 0)

print("Data1 Shape: {}".format(data1.shape))
print("Train1 Shape: {}".format(train1_x.shape))
print("Test1 Shape: {}".format(test1_x.shape))

train1_x_bin.head()

探索性分析

计数型数据:非连续性数据,以字符串(文本,日期)等表现的数据;
计量型数据:连续性数据,以数字(整形,浮点型)表示的数据;

单变量分析

  • 确定频数分布与频率分布
  • 进行集中趋势分析 :众数、中位数和平均数
  • 进行离散趋势分析:离散趋势分析是指用一个特别的数值将一组数据相互之间的离散程度反映出来。离散趋势分析可以通过计算标准差和离散系数等方式来实现。
  • 进行区间估计
  • 进行假设检验
    目的:此分析主要看计数型有哪些子名称,每个子名称是字段有限,如姓名列中有三个名字,即可知道从三个名字对数据进行理解,计量型的主要看字段的分布情况以及范围,如年龄,分布在18-40岁之间,主要分布在25-35之间;从而更加有效的对数据进行识别;
    计数型数据:计数汇总,一般通过饼图,柱形图等查看各字段的分布情况,占比情况;
    计量型数据:直方图,通过频率统计各区间段的分布,确定各区间的主要情况,一般正常的数据符合正态分布;
    注:柱形图和直方图都是条状,区别在于柱形图有两个字段(x轴显示的为字段名称(一般为不重复的字段名称),y轴显示的是各字段的计数,即总共出现的次数),直方图由一个字段生成,通过对各字段进行合理的分组,进行显示(x轴显示的为字段的范围,y轴显示的是各字段出现的频数)

双变量分析

【】

  • 相关分析
  • 回归分析

多变量分析

多变量方差分析

MANOVA适用于同时探讨一个或多个自变量与两个以上因变量间因果关系的统计方法,依照研究者所操作自变量的个数,可以分为单因素(一个自变量)或多因素(两个以上自变量)MANOVA。进行多变量方差分析时,自变量必须是离散的定类或定序变量,而因变量则必须是定距以上层次的变量。

主成分分析

主成分分析的主要功能在分析多个变量间的相关,以建构变量间的总体性指标(overall indicators)。当研究者测量一群彼此间具有高度相关的变量,则在进行显著性检验钱,为避免变量数过多,造成解释上的复杂与困扰,常会先进行主成分分析,在尽量不丧失原有信息的前提下,抽取少数几个主成分,作为代表原来变量的总体性指标,达到资料缩减(data reduction)的功能。进行主成分分析时,并无自变量和因变量的区别,但是所有的变量都必须是定距以上层次变量。

因子分析

因子分析与主成分分析常被研究者混用,因为二者的功能都是通过对变量间的相关分析,以达到简化数据功能。但不同的是,主成分分析是在找出变量间最佳线性组合(linear combination)的主成分,以说明变量间最多的变异量;至于因子分析,则在于找出变量间共同的潜在结构(latent structure)或因子,以估计每一个变量在各因子上的负荷量(loading)。进行因子分析时,并无自变量和因变量的区分,但是所有变量都必须是定距以上层次变量。

典型相关分析

典型相关可视为积差相关或多元回归分析的扩展,主要功能在分析两个变量间的相关。进行多元回归分析的目的,是在分析一个或多个自变量与一个因变量间的关系,而典型相关中因变量也可以是多个;也就是说,典型相关的目的在于通过计算得到两个变量线性组合的加权系数。以使(maximum)两个变量间的相关达到最大化。进行典型相关时,并无自变量和因变量的区分,但是所有变量都必须是定距以上层次变量。

聚类分析

聚类分析的主要功能在进行分类(classification),当研究者有观测值时,常会根据观测值的相似性或差异性进行分类,以形成几个性质不同的类别,简化解释的工作。也就是说,聚类分析根据对变量进行测量的观察值进行分类,以达到组内同质、组间异值的目的。其次,聚类分析完成后,通常可以进行判别分析,以识别分类的效度。当然,在某些时候也可以对变量进行分类(此功能类似因子分析,因此多采用因子分析解决问题)。进行聚类分析时,并无自变量和因变量的区分,但是所有变量都必须是定距以上层次变量。

判别分析

判别分析是多变量分析中应用相当广泛的统计方法,它可以用来对样本进行分类的工作;也可以用来了解不同类别样本在某些变量上的差异情形;同时也可以根据不同类别的样本在某些变量的实际表现,用来预测新的样本属于某一类别的概率。因此,在行为科学中,常见的研究者单独使用判别分析,建立判别函数(discriminant function),以对新样本进行预测;或是多变量方差分析的检验值达到显著性水平后,比较不同组别样本在因变量平均数的差异情形;或是聚类分析后,检验聚类分析的正确性。进行判别分析时,自变量是定距以上层次变量,至于因变量通常是离散变量。

多维量表分析

多维量表分析基本上也是一种分类的统计方法,他在市场上普遍被应用。当研究者想要解释一群受试者(例如消费者)对一组客体(例如商品)在某些变量上相似性的测量中所包含的信息,此时多维量表分析就是一个相当适用的方法。研究者只要将这一组客体在变量上的测量值转化成多维度的几何表征,就能够将这些客体有效地显示在这个几何空间中,达到分类的目的,同时也可以进一步解释这些几何表征所代表的潜在结构或意义。进行多维量表分析时,并无自变量和因变量的区分,同时变量可以是等距以上变量,也可以是定类或定序变量。

线性结构方程

  • 线性结构方程是一个相当具有变通与弹性的统计方法,随着研究者对变量间关系界定的差异,LISREL的常见名称包括协方差结构分析,潜变量分析、线性结构模型或验证性因子分析。LISREL可视为多元回归分析与因子分析两个方法论的整合模型,让研究者可以探讨变量间的线性关系(回归分析),并对可测量显变量与不可测量的潜变量见(因子分析)的因果模型作假设检验。

逻辑斯蒂回归分析

逻辑斯蒂回归可视为传统多元回归分析的一个特列。它和多元回归分析一样,都具有解释自变量与因变量之间的关系,并可进行预测。所不同的是在进行多元回归分析时,包括自变量与因变量都必须是定距以上层次变量;但在进行逻辑斯蒂回归分析时,自变量仍是定距以上层次变量,因变量则是二分的定类变量或多分定类变量或定序变量。

对数线性方程

在基本统计学中,当研究者面对探讨两个定类或定序变量间关系的研究问题时,都是以卡方检验来进行假设检验。当问题的性质是探讨两个定类变量间是否独立或是关联强度时,是以卡方独立性检验来进行假设检验。进行卡方独立性检验时,研究者必须将样本在两个定类变量上的反应,建立二维列联表(contingency table),以进一步根据列联表中各单元格(cell)的次数反应,进行显著性检验。但当研究者面对三个或三个以上的定类变量时,所建立的多元列联表间变量关联的分析,卡方独立性检验将无法解决这样的问题,此时适合的方法就是对数线性模型。利用对数线性模型来解决多元列联表的问题的目的,主要就在于探讨构成列联表的多个定类变量间的关系,进而在精简原则下构建拟合的解释模型,并根据所建立的模型估计单元格参数值,以了解各变量效果对单元格次数的影响。

Logit对数线性模型

-在对数线性模型中,多个定类变量间是互为因果的关系(即相关关系),并无自变量与因变量的区分,研究目的在于探讨变量间的关联强度和性质。但有时研究者会面临变量间有自变量和因变量的区分的情境。在基本统计学中,当研究者面对的问题性质是两个定类变量间有自变量和因变量的区别,目的在于探讨两个变量间的因果关系时,多是以卡方齐性检验来进行假设检验。但自变量个数在两个以上时,卡方齐性检验就不再适用,而必须改用logit对数线性模型方法来对数据进行分析。Logit对数线性模型的功能与多元回归分析相当类似,都可以用来探讨与解释因变量与自变量间的关系,但不同的是,多元回归分析的变量都是定距以上层次变量,通常以最小二乘法进行模型估计与检验;logit对数线性模型的变量都是定类变量,通常以最大似然估计法进行模型估计与检验。

现在,我们的数据已清理完毕,我们将使用描述性和图形统计数据探索数据,以描述和总结变量。 在此阶段,你将发现自己对特征进行了分类,并确定了它们与目标变量的相互关系。

列联表分析

用于分析离散变量定型变量之间是否存在相关。
对于二维表,可进行卡方检验,对于三维表,可作Mentel-Hanszel分层分析
列联表分析还包括配对计数资料的卡方检验、行列均为顺序变量的相关检验。

相关分析

研究现象之间是否存在某种依存关系,对具体有依存关系的现象探讨相关方向相关程度
1、单相关: 两个因素之间的相关关系叫单相关,即研究时只涉及一个自变量和一个因变量;
2、复相关 :三个或三个以上因素的相关关系叫复相关,即研究时涉及两个或两个以上的自变量和因变量相关;
3、偏相关:在某一现象与多种现象相关的场合,当假定其他变量不变时,其中两个变量之间的相关关系称为偏相关。

方差分析

使用条件:各样本须是相互独立的随机样本;各样本来自正态分布总体;各总体方差相等
1、单因素方差分析:一项试验只有一个影响因素,或者存在多个影响因素时,只分析一个因素与影响变量的关系
2、多因素有交互方差分析:一顼实验有多个影响因素,分析多个影响因素与响应变量的关系,同时考虑多个影响因素之间的关系
3、多因素无交互方差分析:分析多个影响因素与响应变量的关系,但是影响因素之间没有影响关系或忽略影响关系
4、协方差分祈:传统的方差分析存在明显的弊端,无法控制分析中存在的某些随机因素,使之影响了分祈结果的准确度。协方差分析主要是在排除了协变量的影响后再对修正后的主效应进行方差分析,是将线性回归与方差分析结合起来的一种分析方法。

for x in data1_x:
    if data1[x].dtype != 'float64' :
        print('Survival Correlation by:', x)
        print(data1[[x, Target[0]]].groupby(x, as_index=False).mean())
        print('-'*10, '\n')
        
print(pd.crosstab(data1['Title'],data1[Target[0]]))

接下来是一些可视化的分析:

  • 首先探索各个标签的不同特征值的生存结果对比
  • 我们知道阶级对生存很重要,现在让我们比较不同阶级的特征

数据挖掘技术架构 数据挖掘的框架_缺失值_12

由图可看出:1)船舱等级越高,票价越贵。2)船舱等级高的人的年龄相对较大。 3)船舱等级越高,家庭出游人数越少。死亡比例与船舱等级关系不大,另外我们知道性别对生存很重要,现在我们来比较一下性别和第二个特征

数据挖掘技术架构 数据挖掘的框架_scala_13

可以看到女性的存活比例大于男性,且C甲板、独自出行的女士存活率较高,接着观察更多比较

数据挖掘技术架构 数据挖掘的框架_scala_14

数据挖掘技术架构 数据挖掘的框架_缺失值_15

接下来绘制幸存或未幸存乘客的年龄分布

数据挖掘技术架构 数据挖掘的框架_数据_16

绘制幸存者性别年龄等直方图

数据挖掘技术架构 数据挖掘的框架_数据挖掘技术架构_17

最后对整个数据集进行可视化

数据挖掘技术架构 数据挖掘的框架_缺失值_18

数据挖掘技术架构 数据挖掘的框架_缺失值_19

建模分析

首先,我们必须了解机器学习的目的是解决人类问题。机器学习可分为:监督学习无监督学习强化学习。在监督学习中,您可以通过向模型提供包含正确答案的训练数据集来训练模型。在无监督学习中,您可以使用未包含正确答案的训练数据集来训练模型。强化学习是前两种方法的混合,在这种情况下,模型不会立即得到正确答案,而是在一系列事件之后才得到强化学习。我们正在进行有监督的机器学习,因为我们正在通过向算法展示一组功能及其对应的目标来训练我们的算法。然后,我们希望从相同的数据集中为它提供一个新的子集,并且在预测准确性方面具有相似的结果。
机器学习算法有很多,但是根据目标变量数据建模目标的不同,它们可以分为四类:分类回归聚类降维。我们将重点放在分类和回归上。可以概括地说,连续目标变量需要回归算法,而离散目标变量则需要分类算法。另外逻辑回归虽然名称上具有回归,但实际上是一种分类算法。由于我们的问题是预测乘客是否幸存下来,因此这是一个离散的目标变量。我们将使用sklearn库中的分类算法来开始我们的分析。并使用交叉验证和评分指标(在后面的部分中进行讨论)来对算法的性能进行排名和比较。
常见的机器学习分类算法有:

  • EM方法
  • 广义线性模型(GLM)
  • 朴素贝叶斯
  • K近邻
  • 支持向量机(SVM)
  • 决策树

模型评估与优化

让我们回顾一下,通过一些基本的数据清理,分析和机器学习算法(MLA),我们能够以约82%的准确度预测乘客的存活率。几行代码还不错。但是,我们始终提出的问题是,我们可以做得更好,更重要的是,我们可以为所投资的时间获得应有的投资回报率吗?例如,如果我们仅将精度提高1%,那么真的值得进行3个月的开发?因此,在改进模型时请牢记这一点。
在决定如何改善模型之前,让我们确定我们的模型是否值得保留。为此,我们必须返回到数据科学101的基础知识。我们知道这是一个二元问题,因为只有两种可能的结果。乘客幸存或死亡。将其视为硬币翻转问题。如果有一个硬币,并且猜到了正面或反面,那么您就有50-50的机会猜对了。所让我们将50%设为最差的模型性能

交叉验证

接下来应该是交叉验证,但是重要的是我们使用不同的子集来训练数据来构建模型,并使用测试数据来评估模型。否则,我们的模型将过拟合。这意味着在“预测”已经看到的数据方面很棒,但是在预测尚未看到的数据方面很糟糕;这根本不是预测。这就像在学校测验中作弊以获得100%的成绩,但是然后当您去参加考试时,就会失败,

超参数调整

当我们使用sklearn决策树(DT)分类器时,我们接受了所有功能默认值。 这使我们有机会了解各种超参数设置将如何改变模型的准确性。 (单击此处以了解有关参数与超参数的更多信息。)
但是,为了调整模型,我们需要实际了解它。 这就是为什么我在前几节中花时间向您展示预测的原理,因此你需要具体了解决策树算法的优点与不足在哪!
下面是使用ParameterGrid, GridSearchCVcustomizedsklearn scoring评分来调整我们的模型结果

  • ParameterGrid
  • GridSearchCV
    【https://zhuanlan.zhihu.com/p/37310443】
  • customizedsklearn scoring
dtree = tree.DecisionTreeClassifier(random_state = 0)
base_results = model_selection.cross_validate(dtree, data1[data1_x_bin], data1[Target], cv  = cv_split)
dtree.fit(data1[data1_x_bin], data1[Target])

print('BEFORE DT Parameters: ', dtree.get_params())
print("BEFORE DT Training w/bin score mean: {:.2f}". format(base_results['test_score'].mean()*100)) 
print("BEFORE DT Test w/bin score mean: {:.2f}". format(base_results['test_score'].mean()*100))
print("BEFORE DT Test w/bin score 3*std: +/- {:.2f}". format(base_results['test_score'].std()*100*3))
#print("BEFORE DT Test w/bin set score min: {:.2f}". format(base_results['test_score'].min()*100))
print('-'*10)

param_grid = {'criterion': ['gini', 'entropy'],  #scoring methodology; two supported formulas for calculating information gain - default is gini
              #'splitter': ['best', 'random'], #splitting methodology; two supported strategies - default is best
              'max_depth': [2,4,6,8,10,None], #max depth tree can grow; default is none
              #'min_samples_split': [2,5,10,.03,.05], #minimum subset size BEFORE new split (fraction is % of total); default is 2
              #'min_samples_leaf': [1,5,10,.03,.05], #minimum subset size AFTER new split split (fraction is % of total); default is 1
              #'max_features': [None, 'auto'], #max features to consider when performing split; default none or all
              'random_state': [0] #seed or control random number generator: https://www.quora.com/What-is-seed-in-random-number-generation
             }

tune_model = model_selection.GridSearchCV(tree.DecisionTreeClassifier(), param_grid=param_grid, scoring = 'roc_auc', cv = cv_split)
tune_model.fit(data1[data1_x_bin], data1[Target])

#print(tune_model.cv_results_.keys())
#print(tune_model.cv_results_['params'])
print('AFTER DT Parameters: ', tune_model.best_params_)
#print(tune_model.cv_results_['mean_train_score'])
print("AFTER DT Training w/bin score mean: {:.2f}". format(tune_model.cv_results_['mean_test_score'][tune_model.best_index_]*100)) 
#print(tune_model.cv_results_['mean_test_score'])
print("AFTER DT Test w/bin score mean: {:.2f}". format(tune_model.cv_results_['mean_test_score'][tune_model.best_index_]*100))
print("AFTER DT Test w/bin score 3*std: +/- {:.2f}". format(tune_model.cv_results_['std_test_score'][tune_model.best_index_]*100*3))
print('-'*10)

特征选择

正如一开始所说的,不是说预测变量越多模型就越好,而正确的预测因子可以提高模型的准确率。因此,数据建模的另一个步骤是特征选择。在Sklearn中我们将使用recursive feature elimination(RFE)与cross validation(CV)。
【】

模型验证

#不同算法比较
correlation_heatmap(MLA_predict)

改进与总结