Hadoop学习笔记三 -- 决策树算法实现用户风险等级分类

原创 2017年01月02日 23:08:04

前言

刚刚过去的2016年被称为人工智能的元年,在AlphaGo大战李世石取得里程碑式的胜利后,神经网络和深度学习的概念瞬间进入了人们的视野,各大商业巨头也纷纷将自己的目标转移到这个还没有任何明确方向但所有人都知道它一旦出手将改变世界的人工智能方向中。在这个过程中,人们也突然发现在过去几年大数据存储技术和硬件处理能力不断发展,而产出却有限,主要是面对如此纷繁复杂的数据,人们却不知道如何利用。答案就在那里,却不知道如何寻找答案。所以数据挖掘、机器学习的算法的学习和研究又成了高度热门的话题。本文继上一篇博客中研究的KNN算法,对机器学习中另一个比较简单的算法 – 决策树算法进行学习和研究。KNN算法是基于节点之间的欧式距离进行分类,算法简单易懂,比较大的缺陷是计算量比较大而且无法给出数据的内在含义,而决策树算法相对而言在数据内在含义方面有比较大的优势,得到的结果也容易在业务上被理解。

决策树算法

决策树算法的规则跟人脑决策非常相似,通过一系列IF-ELSE的问题进行决策实现最终的分类。以下是一个极简单的决策树例子。


这里写图片描述
决策树算法运行的过程也是决策树构造的过程,面对庞杂的数据,在构造决策树时,需要解决的第一个问题就是当前数据集上哪个特征在划分数据分类时起决定性作用。如在上一个博客中用户风险等级划分的案例,用户有股票、基金及贵金属投资,理财产品投资,存款机货币市场投资三个方面的数据,而实际的商业用户有更多维度的数据,我们必须找到决定性的特征,才能划分最好的结果,所以我们必须评估每个特征的重要性。在找到第一个决策点后,整个数据集就会被划分成几个分支,接下来再检查这几个分支下的数据是否属于同一类,如果是同一类数据,则停止划分,如果不属于同一类数据,则需要继续寻找决策点,创建分支的伪代码如下:

    检测数据集中每个子项是否属于同一分类:
        If so return 类标签;
        Else 
            寻找划分数据集的最好特征

            划分数据集
            创建分支节点
                For 每个划分的子集
                    迭代并增加返回结果到分支节点中
            return 分支节点

信息增益

划分数据集的最大原则是将无序的数据变得更加有序,在划分数据集之前和之后信息发生的变化称为信息增益,在计算完每个特征值划分数据集获得的信息增益后,获得信息增益最高的特征就是最好的选择。而集合信息的度量方式称为香农熵。香农熵的计算公式为

这里写图片描述

在MapReduce中实现每个维度信息增益的计算。

public class CalcShannonEntMapper extends
        Mapper<LongWritable, Text, Text, AttributeWritable> {

    @Override
    protected void setup(Context context) throws IOException,
            InterruptedException {
        super.setup(context);
    }

    @Override
    protected void map(LongWritable key, Text value, Context context)
            throws IOException, InterruptedException {
        String line = value.toString();
        StringTokenizer tokenizer = new StringTokenizer(line);
        Long id = Long.parseLong(tokenizer.nextToken());
        String category = tokenizer.nextToken();
        boolean isCategory = true;
        while (tokenizer.hasMoreTokens()) {
            isCategory = false;
            String attribute = tokenizer.nextToken();
            String[] entry = attribute.split(":");
            context.write(new Text(entry[0]), new AttributeWritable(id,
                    category, entry[1]));
        }
        if (isCategory) {
            context.write(new Text(category), new AttributeWritable(id,
                    category, category));
        }
    }

    @Override
    protected void cleanup(Context context) throws IOException,
            InterruptedException {
        super.cleanup(context);
    }
}

public class CalcShannonEntReducer extends
        Reducer<Text, AttributeWritable, Text, AttributeGainWritable> {

    @Override
    protected void setup(Context context) throws IOException,
            InterruptedException {
        super.setup(context);
    }

    @Override
    protected void reduce(Text key, Iterable<AttributeWritable> values,
            Context context) throws IOException, InterruptedException {
        String attributeName = key.toString();
        double totalNum = 0.0;
        Map<String, Map<String, Integer>> attrValueSplits = new HashMap<String, Map<String, Integer>>();
        Iterator<AttributeWritable> iterator = values.iterator();
        boolean isCategory = false;
        while (iterator.hasNext()) {
            AttributeWritable attribute = iterator.next();
            String attributeValue = attribute.getAttributeValue();
            if (attributeName.equals(attributeValue)) {
                isCategory = true;
                break;
            }
            Map<String, Integer> attrValueSplit = attrValueSplits
                    .get(attributeValue);
            if (null == attrValueSplit) {
                attrValueSplit = new HashMap<String, Integer>();
                attrValueSplits.put(attributeValue, attrValueSplit);
            }
            String category = attribute.getCategory();
            Integer categoryNum = attrValueSplit.get(category);
            attrValueSplit.put(category, null == categoryNum ? 1
                    : categoryNum + 1);
            totalNum++;
        }
        if (isCategory) {
            System.out.println("is Category");
            int sum = 0;
            iterator = values.iterator();
            while (iterator.hasNext()) {
                iterator.next();
                sum += 1;
            }
            System.out.println("sum: " + sum);
            context.write(key, new AttributeGainWritable(attributeName, sum,
                    true, null));
        } else {
            double gainInfo = 0.0;
            double splitInfo = 0.0;
            for (Map<String, Integer> attrValueSplit : attrValueSplits.values()) {
                double totalCategoryNum = 0;
                for (Integer categoryNum : attrValueSplit.values()) {
                    totalCategoryNum += categoryNum;
                }
                double entropy = 0.0;
                for (Integer categoryNum : attrValueSplit.values()) {
                    double p = categoryNum / totalCategoryNum;
                    entropy -= p * (Math.log(p) / Math.log(2));
                }
                double dj = totalCategoryNum / totalNum;
                gainInfo += dj * entropy;
                splitInfo -= dj * (Math.log(dj) / Math.log(2));
            }
            double gainRatio = splitInfo == 0.0 ? 0.0 : gainInfo / splitInfo;
            StringBuilder splitPoints = new StringBuilder();
            for (String attrValue : attrValueSplits.keySet()) {
                splitPoints.append(attrValue).append(",");
            }
            splitPoints.deleteCharAt(splitPoints.length() - 1);
            context.write(key, new AttributeGainWritable(attributeName,
                    gainRatio, false, splitPoints.toString()));
        }
    }

    @Override
    protected void cleanup(Context context) throws IOException,
            InterruptedException {
        super.cleanup(context);
    }

}  

实验

我们还是用上一篇博客中用户风险等级分类的例子中的数据,去测试决策树算法的优劣,但由于决策树算法只能对是或者否进行判断,所以,对案例中的数据进行了改造,示例如下:

用户 股票、基金及贵金属投资 理财产品投资 存款及货币市场投资 风险分类
1 1 1 1 high
2 0 1 1 middle
3 0 0 1 low



把一组已经打好标签的数据作为训练数据,另一组没打标签的数据作为测试数据,测试的结果如下:


这里写图片描述
实验结果非常具有可读性,也符合业务的常理,但是由于决策树算法只能输入0-1数据,运算结果的错误率为13.6%,相对KNN来说是错误率是提高了,要进一步降低错误率,可以增加判断的维度,比如对于理财产品来说,有不同类型的理财产品,可以依据理财产品的类型增加几个维度等。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

TCP网络通讯如何解决分包粘包问题

TCP数据传输是以无边界的数据流传输形式,所谓无边界是指数据发送端发送的字节数,在数据接收端接受时并不一定等于发送的字节数,可能会出现粘包情况。 TCP粘包情况: 1. 发送端发送了数量比较的数据,接...

数据挖掘(6):决策树分类算法

http://blog.jobbole.com/90165/ 原文出处: fengfenggirl(@也爱数据挖掘)   欢迎分享原创到伯乐头条 从这篇开始,我将介绍分类问题,主要介绍...

Hadoop之K-Means聚类算法

Begin 读取inputPath,从中选取前k个点作为初始质心,将质心数据写入centerPath; While 聚类终止条件不满足 ...

hadoop之Kmeans数据挖掘算法实现

本篇内容主要借鉴hadoop前辈的kmeans代码实现方案,改进距离计算方案等原有代码中的一些小问题,基于低版本的hadoop重新进行编写并实现,欢迎参考,未经允许,不得转载。

数据挖掘笔记-分类-决策树-MapReduce实现-1

之前写的相关程序都是单机上跑的,发现现在很流行hadoop

Hadoop之K-Means聚类算法

在Hadoop分布式环境下实现K-Means聚类算法的伪代码如下: 输入:参数0--存储样本数据的文本文件inputfile;             参数1--存储样本数据的Seque...

Hadoop学习笔记二 - kNN算法实现用户风险分类

在银行这个极其庞杂的交易体系中,每天都能收集到大量的用户信息和用户数据。而伴随着我国利率市场化的不断深化,净利差的迅速收窄,各大银行都希望利用手头的大量用户信息和实时产生的用户数据,对用户进行深度分析...

数据挖掘学习笔记-决策树算法浅析(含Java实现)

目录 一、通俗理解决策树算法原理 二、举例说明算法执行过程 三、Java实现 本文基于书籍《数据挖掘概念与技术》,由于刚接触Data Mining,所以可能有理解不到位的情况,记录学习笔记,提升自...

Apache Spark MLlib学习笔记(五)MLlib决策树类算法源码解析 1

从这章开始分析spark MLlib的decision tree的源码实现。 首先看下官方给的java使用决策树的例子,路径是/home/yangqiao/codes/spark/examples/...

Apache Spark MLlib学习笔记(六)MLlib决策树类算法源码解析 2

上篇说道建立分类决策树模型调用了trainClassifier方法,这章分析trainClassifier方法相关内容 按照以下路径打开源码文件: /home/yangqiao/codes/spa...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)