最大熵的Java实现

这是一个最大熵的简明Java实现,提供训练与预测接口。训练采用GIS训练算法,附带示例训练集。本文旨在介绍最大熵的原理、分类和实现,不涉及公式推导或其他训练算法,请放心食用。

最大熵理论

简介

最大熵属于辨识模型,能够满足所有已知的约束, 对未知的信息不做任何过分的假设。

什么叫已知的约束?本文不会使用晦涩的术语迷惑你,请看这样一个例子:

你的朋友每天都会“出门”或者“自宅”,这两种活动是同时受“天气”“心情”“湿度”(因为她是女孩子)影响的,我们可以称其为特征。

接下来我们从她的微博历史记录收集到了一些“活动<->特征”的对应例子,比如:

  1. “今天天气真好,我很开心,所以出门逛街了”
  2. “太干燥了,我要睡个美容觉!”
  3. “我的备胎2号又来踩我的微博主页了,气死我了!魔都的雨冷死了,干脆看美剧算了!”
  4. “男神约我逛街,就算天气差,我也要去!”
  5. ……

我们从直觉上可以感受到,这是一个……绿茶婊( ̄_ ̄|||) 跑题了……我们从直觉上可以感受到,“天气好”对“出门”是正相关的,“心情好”也是如此,心情差则是负相关,但是这并非绝对的,可能只有在“不干燥”的情况才成立。

最大熵可以将我们的直觉数字化,将其作为一种特征(或称特征函数),并且计算出每一种特征有多重要。约束指的是,预测出的结果的分布都满足对特征统计出的概率,且这些概率均匀分布,最终的结果是,导致系统的熵最大。

最大熵没有假设“天气”与“心情”独立分布,也没有承认“天气”对“心情”有影响,也许它的确有影响,但是最大熵只保证最终结果符合概率约束。

如果你有深厚的数学修养和足够的时间,可以选择阅读附录中的论文与推导过程,在那里你会得到严密的描述与公式推导。

分类

最大熵模型根据样本信息进行概率估计可分为2 种:联合最大熵模型和条件最大熵模型。假设a 是某个事件,b 是事件a 发生的环境(或称上下文),则a 和b 的联合概率记为p(a, b)。一般地,设所有可能发生的事件组成的集合为A,所有环境组成的集合是B,则对任意给定的a∈A, b∈B,求概率p(a, b)须建立联合最大熵模型。若要计算在b 的条件下,事件a 发生的概率,即概率p(a | b),则须建立条件最大熵模型。

本文实现的最大熵模型属于条件最大熵模型。

实现

已经将项目开源在https://github.com/hankcs/MaxEnt ,请检出Java代码后进行下一步。

(PS:主要代码来自“CSDN厚”,请参考Reference)

训练集

假如我们把上文采集到的微博制作成计算机可读的数据集data/train.txt(已经包含在该开源项目中):

Outdoor Sunny Happy
Outdoor Sunny Happy Dry
Outdoor Sunny Happy Humid
Outdoor Sunny Sad Dry
Outdoor Sunny Sad Humid
Outdoor Cloudy Happy Humid
Outdoor Cloudy Happy Humid
Outdoor Cloudy Sad Humid
Outdoor Cloudy Sad Humid
Indoor Rainy Happy Humid
Indoor Rainy Happy Dry
Indoor Rainy Sad Dry
Indoor Rainy Sad Humid
Indoor Cloudy Sad Humid
Indoor Cloudy Sad Humid

我们看到数据最长有4列,每一行第一列表示当天的活动,其余的表示当天的环境。

训练

训练的目的其实是计算出一组最优的拉格朗日乘子,对应表示每个特征函数有多重要。

GIS算法

定义λi为特征函数i的拉格朗日乘子,C为每个事件最多有多少个特征,log中的分子与分母分别表示经验分布期望与模型估计期望。

GIS算法用第N次迭代的模型来估算每个特征在训练数据中的分布。如果超过了实际的(分式小于1,log得到负数),就把相应参数变小(加上负数就变小)。否则,将它们变大。当训练样本的特征分布和模型的特征分布相同时,就求得了最优参数。

这个式子用Java描述如下:

        for (int i = 0; i < maxIt; ++i)
        {
            computeModeE(modelE);
            for (int w = 0; w < weight.length; w++)
            {
                lastWeight[w] = weight[w];
                weight[w] += 1.0 / C * Math.log(empiricalE[w] / modelE[w]);
            }
            if (checkConvergence(lastWeight, weight)) break;
        }

预测

终于到了最激动人心的时刻了,作为备胎2号,你准备明天约她看电影。你从天气预报得知,明天天气晴朗,湿度良好。那么她答应你出门的概率是多大呢?

        String path = "data/train.txt";
        MaxEnt maxEnt = new MaxEnt();
        maxEnt.loadData(path);
        maxEnt.train(200);
        List<String> fieldList = new ArrayList<String>();
        fieldList.add("Sunny"); // 假如天晴
        fieldList.add("Humid"); // 并且湿润
        Pair<String, Double>[] result = maxEnt.predict(fieldList);  // 预测出门和自宅的概率各是多少
        System.out.println(Arrays.toString(result));

输出

  1. [Outdoor=0.9747657631914007, Indoor=0.025234236808599233]

看来出门的概率高达97%。

转自:http://www.hankcs.com/nlp/maximum-entropy-java-implementation.html

时间: 2024-11-05 08:43:41

最大熵的Java实现的相关文章

maxent:最大熵模型的java实现,GIS训练

先给出实现的代码,以后再进行一些理论的概述 训练样本 Outdoor Sunny Happy Outdoor Sunny Happy Dry Outdoor Sunny Happy Humid Outdoor Sunny Sad Dry Outdoor Sunny Sad Humid Outdoor Cloudy Happy Humid Outdoor Cloudy Happy Humid Outdoor Cloudy Sad Humid Outdoor Cloudy Sad Humid Ind

最大熵依存句法分析器的实现

这是一个判别式汉语句法分析器的Java实现,基于最大熵模型和最大生成树模型,实现了中文依存句法的自动分析,在封闭测试集(取自训练集)上取得了99.20%的准确率(UA),分析速度达到 570.7句/秒.判别式的分析方法该方法采用条件概率模型,将所有依存关系概率的累积作为目标函数的score,取score最大的依存关系树作为输出.最大生成树模型最大生成树模型(maximum spanning trees, MST) 定义整棵句法树的打分是树中各条边打分的加权和:s 表示打分值,y 是句子x 的一棵

Android学习必备--java工具15个

Weka 1.Weka集成了数据挖掘工作的机器学习算法.这些算法可以直接应用于一个数据集上或者你可以自己编写代码来调用.Weka包括一系列的工具,如数据预处理.分类.回归.聚类.关联规则以及可视化. MassiveOnlineAnalysis 2.MassiveOnlineAnalysis(MOA)是一个面向数据流挖掘的流行开源框架,有着非常活跃的成长社区.它包括一系列的机器学习算法(分类.回归.聚类.异常检测.概念漂移检测和推荐系统)和评估工具.关联了WEKA项目,MOA也是用Java编写的,

Java多线程学习(吐血超详细总结)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程

Java TM 已被阻止,因为它已过时需要更新的解决方法

公司的堡垒机需要通过浏览器登陆,且该堡垒机的网站需要Java的支持,最近通过浏览器登陆之后总是提示"java TM 已被阻止,因为它已过时需要更新的解决方法"导致登陆之后不能操作, 但是操作系统中确实已经安装了比较新的JDK,安装的JDK版本是jdk-7u67-windows-i586,因为太烦人,所以决定搞清楚报错的原因,一劳永逸,彻底解决这个问题 准备工作:安装JDK,安装版本jdk-7u67-windows-i586.exe,因为机器的Eclipse还依赖64位的JDK,所以另安

Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? Java new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start(); 1 2 3 4 5 6 7 new Thread(new

由@NotNull 注解引出的关于Java空指针的控制(转)

Java 小技巧和在java应用避免NullPonintException的最佳方法 在java应用程序中,一个NullPonintException(空指针异常)是最好解决(问题)的方法.同时,空指针也是写健壮的顺畅运行的代码的关键.“预防好过治疗”这句话也同样适用于令人不爽的NullPonintException.通过应用防御性的编码技术和在遵守多个部分之间的约定,你可以再很大程度上避免NullPointException.下面的这些java小技巧可以最小化像!=null这种检查的代码.作为

Java注解(2)-注解处理器(运行时|RetentionPolicy.RUNTIME)

如果没有用来读取注解的工具,那注解将基本没有任何作用,它也不会比注释更有用.读取注解的工具叫作注解处理器.Java提供了两种方式来处理注解:第一种是利用运行时反射机制:另一种是使用Java提供的API来处理编译期的注解. 反射机制方式的注解处理器 仅当定义的注解的@Retention为RUNTIME时,才能够通过运行时的反射机制来处理注解.下面结合例子来说明这种方式的处理方法. Java中的反射API(如java.lang.Class.java.lang.reflect.Field等)都实现了接

jvm系列(一):java类的加载机制

java类的加载机制 原文:http://www.cnblogs.com/ityouknow/p/5603287.html 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构.类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口. 类加载器并不需要等到某个