数据挖掘 workfolw 总结

  
个人将数据挖掘的流程简单表示为“ 数据特征模型 ”。
 
  • 首先,明确问题的性质和任务(分类、回归、聚类、推荐、排序、关联分析、异常检测等);
  • 其次,理解数据(含义、类型、值的范围),并通过描述性统计分析(describing data)和可视化分析(visualizing data)等工作对数据进行探索性分析(exploratory data analysis, EDA);
  • 然后,明确与预测结果显著相关的特征/变量(以kaggle-Titanic为例),进行数据预处理(特征选择、特征工程);
  • 最后,进行模型选择、建模、调参、交叉验证、模型评估,并得出最终的解决方案。
 
思考下来整个数据建模的过程,重点不在于建模,而在于前者,即如何理解数据,处理数据,针对模型的需求和特点做数据工程、特征工程,将数据以更好的方式特征化。在实际的数据挖掘过程中,前者占据差不多70%的工作量。

以 Titanic 为例,以下是数据挖掘 workflow 总结。

明确任务目标:预测泰坦尼克号的乘客是否生还。它是个二分类任务,生还为1,否则为0。

前期准备:导入相应的库

pandas → 载入数据
matplotlibseaborn → 可视化
sklearn → 机器学习
 
# data analysis and wrangling
import pandas as pd
import numpy as np
import random as rnd

# visualization import seaborn as sns import matplotlib.pyplot as plt # machine learning from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC,LinearSVC from sklearn.ensemble import RandomForestClassifierfrom sklearn.tree import DecisionTreeClassifier ......

 

step 1. 读取数据

使用Pandas DataFrame读取数据。
# 使用Pandas DataFrame读取数据

train_df = pd.read_csv('./xxx/train.csv')
test_df = pd.read_csv('./xxx/test.csv')
combine = [train_df, test_df]

step 2.1 描述性统计分析

  • 查看总共有哪些特征;
    •  ['PassengerId' 'Survived' 'Pclass' 'Name' 'Sex' 'Age' 'SibSp' 'Parch' 'Ticket' 'Fare' 'Cabin' 'Embarked'] 共12个特征/变量
  • 简单展示数据;
  • 查看数据的类型和缺失值;分辨清楚数据的类型有助于挑选合适的图案进行可视化。
  • 查看数据离散分布情况(箱型图:均值、标准差、最小值、分位数、最大值、众数、中位数),描述事件总体情况及相关细节。
  • 查看离散型变量的分布情况。
# column 列名 index 行名  查看总共有哪些特征
print(train_df.columns.values)
# preview the data
train_df.head() train_df.tail()
# 查看数据类型和缺失值
train_df.info() print('_'*40) test_df.info()
# 查看数据离散分布情况
train_df.describe()
# 只输出离散型变量的分布情况
train_df.describe(include=['O'])

下图介绍了不同的数据类型。数据可以按 Nominal(名义)、Ordinal(顺序)、Interval(区间) 以及 Ratio(比率) 分;也可以按 Discrete (离散)、Continuous (连续)分;还能按照 Int (整数)、Float (浮点数)或者 String (字符串)、Object (对象)区分。

数据挖掘 workfolw 总结 

数据观察和假设

Correlating

我们想知道哪些特征与 Survival 相关。

Completing

  1. 我们想填充 Age 特征的缺失值,因为这个特征与 Survival 显著相关。
  2. 我们也想填充 Embarked 特征因为它可能与 Survival 相关。

Correcting

  1. Ticket 特征可能会在我们的分析中被移除,因为它有较高的重复率(24%),因此 Ticket 与 Survival 之间可能不存在联系。
  2. Cabin 特征可能会被移除,因为它在训练集以及测试集中存在大量缺失值。
  3. PassengerID 可能会被移除,因为它对 Survival 没有贡献。
  4. Name 特征不是非标准的数据,不能直接对 Survival 产生贡献,因此可能被移除。

Creating

  1. 我们可能基于 Parch 和 SibSp 新建一个 “Family” 特征,计算每个家庭登船的总成员数。
  2. 我们可能要从 Name 特征里提取新特征 Title 
  3. 我们可能根据 Age 进行分组,新建特征。将连续型数值特征转化为次序级分类特征。
  4. 我们也可能创建 Fare 分类特征如果它有助于我们进行分析。

Classifing

  1. Women(Sex=Female)更容易幸存下来。
  2. Children(Age<?)更容易幸存下来。
  3. The upper-class passengers(Pclass=1)更容易幸存下来。

step 2.2 旋转特征分析

特征,即变量。在建模之前,我们要寻找与预测结果显著相关的特征【特征选择】,判断哪些特征与预测结果具备显著相关性(正相关或者负相关)。

为了证实我们的假设,我们可以通过旋转特征来分析特征的相关性。在这一阶段,我们只能分析不存在缺失值的特征。比如 categorical(Sex)ordinal(Pclass)以及discrete(SibSp,Parch)类型的特征。

    • Pclass
      一等座(Pclass=1)的幸存率高达62%,符合假设(classifing #3).
    • Sex
      女性的幸存率(Sex=Female)高达74%,符合假设(classifing #1).
    • SibsP和Parch
      对于确定的值没有显著相关性。建议创建新特征(creating #1).
# 分别计算一等座、二等座、三等座的存活率,并按存活率从高到低进行排序
train_df[['Pclass', 'Survived']].groupby(['Pclass'],as_index=False).mean().sort_values(by='Survived', ascending=False)
# 得出结果 存活率:一等座>二等座>三等座

# 分别计算男性和女性的存活率,并按存活率从高到低排序
train_df[['Sex','Survived']].groupby(['Sex'],as_index=False).mean().sort_values(by='Survived',ascending=False)
# 得出结论 存活率:女性>男性

# 分别计算不同的配偶和兄弟姐妹数量的存活率,并按存活率从高到低排序
train_df[['SibSp','Survived']].groupby(['SibSp'],as_index=False).mean().sort_values(by='Survived',ascending=False)
# 分别计算不同的父母和子女数量的存活率,并按存活率从高到低排序
train_df[['Parch','Survived']].groupby(['Parch'],as_index=False).mean().sort_values(by='Survived',ascending=False)
# 没有规律可循,后面创建新特征查看

step 2.3 可视化分析

以 Age 变量为例。

直方图对于分析连续的数值变量(比如 Age )很有用,能够通过形状以及范围来识别样本特征。直方图还可以指定样本分布的区间,有助于我们分析特定问题(婴儿的生还率是否更高?)。

X轴:Age

Y轴:Survived

Observations

  • 婴孩(Age<=4)有很高的生还率。
  • 高龄乘客(80岁)幸存下来。
  • 大多数乘客年龄在15~35岁之间。
  • 15~25岁年龄段的乘客大部分没有生还。

Decisions

这一阶段的分析帮助我们证实假设并为后面的工作作出决定。

  • 我们应该在模型训练中考虑 Age(classifing #2)。
  • 我们应该为 Age 填补缺失值(completing #1)。
  • 我们应该将连续的数值 Age 离散化。(creating #3)。

数据挖掘 workfolw 总结

step 3 特征工程

在特征选择后,根据做出的decisions,我们要进行特征工程,下图为特征工程的工作内容。
数据挖掘 workfolw 总结
 

Correcting by dropping features(删除特征)

这是一个很好的开头。通过删除特征,我们可以处理更少的数据点,提高运行速度,简化分析。

根据我们的 assumptions 和 decisions ,我们将删除Cabin(correcting #2)和Ticket(Correcting #1)特征。

注意,在合适的情况下,我们同时对训练集和测试集执行操作,以保持一致

print("Before", train_df.shape, test_df.shape, combine[0].shape, combine[1].shape)
# 删除特征 train_df
= train_df.drop(['Ticket','Cabin'], axis=1) test_df = test_df.drop(['Ticket','Cabin'], axis = 1) combine = [train_df, test_df] "After",train_df.shape, test_df.shape,combine[0].shape,combine[1].shape

Creating new feature extracting from existing (从现有特征里提取新特征)

在删除 Name 和 Passengerid 特征之前,我们尝试从 Name 提取 Title 特征 (头衔/称谓),并测试 Title 和 survival 之间的相关性。

在下面的代码中,我们使用正则表达式提取 Title 特征。RegEx pattern (w+) 匹配 Name 特征中以点字符结尾的第一个单词。expand=false 标志返回 Dataframe。

# 使用正则表达式提取 Title 特征。RegEx pattern (w+) 匹配 Name 特征中以点字符结尾的第一个单词。expand=false 标志返回 Dataframe。
for dataset in combine:
    dataset['Title'] = dataset.Name.str.extract('([A-Za-z]+).', expand=False)

pd.crosstab(train_df['Title'],train_df['Sex'])

# 用更加常见的名称来替换大量 titles ,或者将它们归类为 Rare(稀有的)。
for dataset in combine:
    dataset['Title'] = dataset['Title'].replace(['Lady','Countess','Capt','Col',
                                                 'Don','Dr','Major','Rev','Sir','Jonkheer','Dona'],'Rare')
    
    dataset['Title'] = dataset['Title'].replace('Mlle','Miss')
    dataset['Title'] = dataset['Title'].replace('Ms','Miss')
    dataset['Title'] = dataset['Title'].replace('Mme','Mrs')
    
train_df[['Title','Survived']].groupby(['Title'], as_index=False).mean()

# 将分类变量(categorical)转换为顺序变量(ordinal)。
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}
for dataset in combine:
    dataset['Title'] = dataset['Title'].map(title_mapping)
    dataset['Title'] = dataset['Title'].fillna(0)

train_df.head()

Completing a categorical feature(填充分类特征)

Embarked 特征涵盖 S、Q、C 值。我们的训练集缺少两个值。我们简单地用众数来进行填充。

# 众数填充
freq_port = train_df.Embarked.dropna().mode()[0]

for dataset in combine:
    dataset['Embarked'] = dataset['Embarked'].fillna(freq_port)
    
# 旋转特征分析
train_df[['Embarked','Survived']].groupby(['Embarked'],as_index=False).mean().sort_values(by='Survived',ascending=False)

Create new feature combining existing features(从现有特征创建新特征)

结合 Parch 和 Sibsp, 为 FamilySize 创建一个新特征。这使我们能够从数据集中删除 Parch 和 Sibsp 。

for dataset in combine:
    dataset['FamilySize']=dataset['SibSp'] + dataset['Parch']+1
    
train_df[['FamilySize','Survived']].groupby(['FamilySize'],as_index=False).mean().sort_values(by='Survived',ascending=False)

# 创建一个名为 IsAlone 的新特征
for dataset in combine:
    dataset['IsAlone'] = 0
    dataset.loc[dataset['FamilySize']==1,'IsAlone']=1
    
train_df[['IsAlone','Survived']].groupby(['IsAlone'], as_index=False).mean()

 

converting a categorical feature (分类特征离散化)

现在,将包含字符串的特征转换为数值。这是大多数模型算法所要求的,同时也将帮助我们实现特征 completing 的目标。

首先,将 sex 特征转换为一个名为 gender 的新特征,其中 female=1,male=0。

for dataset in combine:
    dataset['Sex'] = dataset['Sex'].map({'female':1, 'male':0}).astype(int)

train_df.head()

 

Quick completing and converting a numeric feature(快速填充和离散化数值特征)

使用 mode 获取 Fare 特征最常出现的值并填充测试集中存在单个缺失值的 Fare 特征。

test_df['Fare'].fillna(test_df['Fare'].dropna().median(),inplace=True)
test_df.head()

# 创建新特征 FareBand
train_df['FareBand'] = pd.qcut(train_df['Fare'],4)

train_df[['FareBand','Survived']].groupby(['FareBand'],as_index=False).mean().sort_values(by='Survived',ascending=True)

# 基于 FareBand 将 Fare 特征转换为 顺序级
for dataset in combine:
    dataset.loc[ dataset['Fare'] <= 7.91, 'Fare'] = 0
    dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454), 'Fare'] = 1
    dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31), 'Fare']   = 2
    dataset.loc[ dataset['Fare'] > 31, 'Fare'] = 3
    dataset['Fare'] = dataset['Fare'].astype(int)

train_df = train_df.drop(['FareBand'], axis=1)
combine = [train_df, test_df]
    
train_df.head(10)

 

 

现在,训练模型并预测解决方案。有60多种预测建模算法可供选择。我们必须了解问题的类型和解决方案的要求,以便将建模算法的选择范围缩小。我们的问题是一个分类和回归问题,确定输出(存活与否)与其他变量或特征(性别、年龄、港口…)之间的关系。当我们使用给定的数据集训练模型时,我们也在执行一类称为监督学习的机器学习。有了这两个准则——监督学习加上分类和回归,我们可以将模型的选择范围缩小到少数。其中包括:

  • Logistic Regression
  • KNN or k-Nearest Neighbors
  • Support Vector Machines
  • Naive Bayes classifier
  • Decision Tree
  • Random Forrest
  • Perceptron
  • Artificial neural network
  • RVM or Relevance Vector Machine

Random Forrest

随机森林模型是最流行的模型之一。随机森林或随机决策森林是一种用于分类、回归和其他任务的集成学习方法。它在训练时构造多个决策树(n_estimators=100),并通过输出类别(分类)或预测个别树均值(回归)来输出分类结果。-参考维基百科。

到目前为止,随机森林模型的置信度得分是所有模型中最高的。我们决定使用此模型的输出(y_pred)来提交预测结果。

# Random Forrest

random_forest = RandomForestClassifier(n_estimators=100)
random_forest.fit(X_train, Y_train)
Y_pred = random_forest.predict(X_test)
acc_random_forest = round(random_forest.score(X_train, Y_train)*100, 2)
acc_random_forest

保存预测结果。

submission = pd.DataFrame({
        "PassengerId": test_df["PassengerId"],
        "Survived": Y_pred
    })

submission.to_csv('submission.csv', index=False)