算法任务:

1. 给定一个文件,统计这个文件中所有字符的相对频率(相对频率就是这些字符出现的概率——该字符出现次数除以字符总个数,并计算该文件的熵)。

2. 给定另外一个文件,按上述同样的方法计算字符分布的概率,然后计算两个文件中的字符分布的KL距离。

(熵和KL距离都是NLP自然语言处理中术语,仅仅是涉及到一两个公式而已,不影响您对代码的理解,so just try!)

说明:

1. 给定的文件可以是两个中文文件或两个英文文件,也可以是两个中英文混合文件。对于中文,计算字符,对于英文,计算词。

2.有效字符不包括 空格 换行符 标点符号。

3.将中文字符、英文单词、其他非有效字符及其出现次数,分别写入三个文件中。

4.代码用java完成。

文章的重点:

1.如何判断一个字符是汉字,而不是ASCII、标点、日文、阿拉伯文……

2.了解汉字是如何编码的。“UTF8”绝逼是要花你一整个下午时间去弄明白的东西。

推荐博文:http://www.cnblogs.com/chenwenbiao/archive/2011/08/11/2134503.html

3.正则表达式。对于计算机科班出身的人应该不陌生,在此我就不造次了。

代码如下:

 import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern; public class NLPFileUnit {
public HashMap<String, Integer> WordOccurrenceNumber;//The Occurrence Number of the single Chinese character
//or Single English word in the file
public HashMap<String, Float> WordProbability;//The probability of single Chinese character or English word
public HashMap<String, Integer> Punctuations;//The punctuation that screened out from the file
public float entropy;//熵,本文主要计算单个汉字,或者单个英文单词的熵值
private String filePath; //构造函数
public NLPFileUnit(String filePath) throws Exception {
this.filePath = filePath;
WordOccurrenceNumber = createHash(createReader(filePath));
Punctuations = filterPunctuation(WordOccurrenceNumber);
WordProbability = calProbability(WordOccurrenceNumber);
this.entropy = calEntropy(this.WordProbability); System.out.println("all punctuations were saved at " + filePath.replace(".", "_punctuation.") + "!");
this.saveFile(Punctuations, filePath.replace(".", "_punctuation."));
System.out.println("all words(En & Ch) were saved at " + filePath.replace(".", "_AllWords.") + "!");
this.saveFile(this.WordOccurrenceNumber, filePath.replace(".", "_AllWords."));
} /**
* get the English words form the file to HashMap
* @param hash
* @param path
* @throws Exception
*/
public void getEnWords(HashMap<String, Integer> hash, String path) throws Exception {
FileReader fr = new FileReader(path);
BufferedReader br = new BufferedReader(fr); //read all lines into content
String content = "";
String line = null;
while((line = br.readLine())!=null){
content+=line;
}
br.close(); //extract words by regex正则表达式
Pattern enWordsPattern = Pattern.compile("([A-Za-z]+)");
Matcher matcher = enWordsPattern.matcher(content);
while (matcher.find()) {
String word = matcher.group();
if(hash.containsKey(word))
hash.put(word, 1 + hash.get(word));
else{
hash.put(word, 1);
}
}
} private boolean isPunctuation(String tmp) {
//Punctuation should not be EN words/ Chinese
final String cnregex = "\\p{InCJK Unified Ideographs}";
final String enregex = "[A-Za-z]+";
return !(tmp.matches(cnregex) || tmp.matches(enregex)) ;
} /**
* judge whether the file is encoded by UTF-8 (UCS Transformation Format)format.
* @param fs
* @return
* @throws Exception
*/
private boolean isUTF8(FileInputStream fs) throws Exception {
if (fs.read() == 0xEF && fs.read() == 0xBB && fs.read() == 0xBF)//所有utf8编码的文件前三个字节为0xEFBBBF
return true;
return false;
} /**
* utf8格式编码的字符,其第一个byte的二进制编码可以判断该字符的长度(汉字一般占三个字节)ASCII占一byte
* @param b
* @return
*/
private int getlength(byte b) {
int v = b & 0xff;//byte to 十六进制数
if (v > 0xF0) {
return 4;
}
// 110xxxxx
else if (v > 0xE0) {
return 3;
} else if (v > 0xC0) {
return 2;//该字符长度占2byte
}
return 1;
} /**
* 通过读取头一个byte来判断该字符占用字节数,并读取该字符,如1110xxxx,表示这个字符占三个byte
* @param fs
* @return
* @throws Exception
*/
private String readUnit(FileInputStream fs) throws Exception {
byte b = (byte) fs.read();
if (b == -1)
return null;
int len = getlength(b);
byte[] units = new byte[len];
units[0] = b;
for (int i = 1; i < len; i++) {
units[i] = (byte) fs.read();
}
String ret = new String(units, "UTF-8");
return ret;
} /**
* 把单词,标点,汉字等全都读入hashmap
* @param inputStream
* @return
* @throws Exception
*/
private HashMap<String, Integer> createHash(FileInputStream inputStream)
throws Exception {
HashMap<String, Integer> hash = new HashMap<String, Integer>();
String key = null;
while ((key = readUnit(inputStream)) != null) {
if (hash.containsKey(key)) {
hash.put(key, 1 + (int) hash.get(key));
} else {
hash.put(key, 1);
}
}
inputStream.close();
getEnWords(hash, this.filePath);
return hash;
} /**
* FileInputStream读取文件,若文件不是UTF8编码,返回null
* @param path
* @return
* @throws Exception
*/
private FileInputStream createReader(String path) throws Exception {
FileInputStream br = new FileInputStream(path);
if (!isUTF8(br))
return null;
return br;
} /**
* save punctuation filtered form (HashMap)hash into (HashMap)puncs,
* @param hash;remove punctuation form (HashMap)hash at the same time
* @return
*/
private HashMap<String, Integer> filterPunctuation(
HashMap<String, Integer> hash) {
HashMap<String, Integer> puncs = new HashMap<String, Integer>();
Iterator<?> iterator = hash.entrySet().iterator(); while (iterator.hasNext()) {
Entry<?, ?> entry = (Entry<?, ?>) iterator.next();
String key = entry.getKey().toString();
if (isPunctuation(key)) {
puncs.put(key, hash.get(key));
iterator.remove();
}
}
return puncs;
} /**
* calculate the probability of the word in hash
* @param hash
* @return
*/
private HashMap<String, Float> calProbability(HashMap<String, Integer> hash) {
float count = countWords(hash);
HashMap<String, Float> prob = new HashMap<String, Float>();
Iterator<?> iterator = hash.entrySet().iterator();
while (iterator.hasNext()) {
Entry<?, ?> entry = (Entry<?, ?>) iterator.next();
String key = entry.getKey().toString();
prob.put(key, hash.get(key) / count);
}
return prob;
} /**
* save the content in the hash into file.txt
* @param hash
* @param path
* @throws Exception
*/
private void saveFile(HashMap<String, Integer> hash, String path)
throws Exception {
FileWriter fw = new FileWriter(path);
fw.write(hash.toString());
fw.close();
} /**
* calculate the total words in hash
* @param hash
* @return
*/
private int countWords(HashMap<String, Integer> hash) {
int count = 0;
for (Entry<String, Integer> entry : hash.entrySet()) {
count += entry.getValue();
}
return count;
} /**
* calculate the entropy(熵) of the characters
* @param hash
* @return
*/
private float calEntropy(HashMap<String, Float> hash) {
float entropy = 0;
Iterator<Entry<String, Float>> iterator = hash.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Float> entry = (Entry<String, Float>) iterator.next();
Float prob = entry.getValue();//get the probability of the characters
entropy += 0 - (prob * Math.log(prob));//calculate the entropy of the characters
}
return entropy;
}
} import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry; public class NLPWork { /**
* calculate the KL distance form file u1 to file u2
* @param u1
* @param u2
* @return
*/
public static float calKL(NLPFileUnit u1, NLPFileUnit u2) {
HashMap<String, Float> hash1 = u1.WordProbability;
HashMap<String, Float> hash2 = u2.WordProbability;
float KLdistance = 0;
Iterator<Entry<String, Float>> iterator = hash1.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Float> entry = iterator.next();
String key = entry.getKey().toString(); if (hash2.containsKey(key)) {
Float value1 = entry.getValue();
Float value2 = hash2.get(key);
KLdistance += value1 * Math.log(value1 / value2);
}
}
return KLdistance;
} public static void main(String[] args) throws IOException, Exception {
//all punctuation will be saved under working directory
System.out.println("Now only UTF8 encoded file is supported!!!");
System.out.println("PLS input file 1 path:");
BufferedReader cin = new BufferedReader(
new InputStreamReader(System.in));
String file1 = cin.readLine();
System.out.println("PLS input file 2 path:");
String file2 = cin.readLine();
NLPFileUnit u1 = null;
NLPFileUnit u2 = null;
try{
u1 = new NLPFileUnit(file1);//NLP:Nature Language Processing
u2 = new NLPFileUnit(file2);
}
catch(FileNotFoundException e){
System.out.println("File Not Found!!");
e.printStackTrace();
return;
}
float KLdistance = calKL(u1, u2);
System.out.println("KLdistance is :" + KLdistance);
System.out.println("File 1 Entropy: " + u1.entropy);
System.out.println("File 2 Entropy: " + u2.entropy);
}
}

计算结果:

[NLP自然语言处理]计算熵和KL距离,java实现汉字和英文单词的识别,UTF8变长字符读取的更多相关文章

  1. 各种形式的熵函数,KL距离

    自信息量I(x)=-log(p(x)),其他依次类推. 离散变量x的熵H(x)=E(I(x))=-$\sum\limits_{x}{p(x)lnp(x)}$ 连续变量x的微分熵H(x)=E(I(x)) ...

  2. KL距离,Kullback-Leibler Divergence

    http://www.cnblogs.com/ywl925/p/3554502.html http://www.cnblogs.com/hxsyl/p/4910218.html http://blog ...

  3. (转载)KL距离,Kullback-Leibler Divergence

    转自:KL距离,Kullback-Leibler Divergence   KL距离,是Kullback-Leibler差异(Kullback-Leibler Divergence)的简称,也叫做相对 ...

  4. 【机器学习基础】熵、KL散度、交叉熵

    熵(entropy).KL 散度(Kullback-Leibler (KL) divergence)和交叉熵(cross-entropy)在机器学习的很多地方会用到.比如在决策树模型使用信息增益来选择 ...

  5. 深度学习中交叉熵和KL散度和最大似然估计之间的关系

    机器学习的面试题中经常会被问到交叉熵(cross entropy)和最大似然估计(MLE)或者KL散度有什么关系,查了一些资料发现优化这3个东西其实是等价的. 熵和交叉熵 提到交叉熵就需要了解下信息论 ...

  6. 【转载】 KL距离(相对熵)

    原文地址: https://www.cnblogs.com/nlpowen/p/3620470.html ----------------------------------------------- ...

  7. KL距离(相对熵)

    KL距离,是Kullback-Leibler差异(Kullback-Leibler Divergence)的简称,也叫做相对熵(Relative Entropy).它衡量的是相同事件空间里的两个概率分 ...

  8. NLP 自然语言处理实战

    前言 自然语言处理 ( Natural Language Processing, NLP) 是计算机科学领域与人工智能领域中的一个重要方向.它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和 ...

  9. 最大熵与最大似然,以及KL距离。

    DNN中最常使用的离散数值优化目标,莫过于交差熵.两个分布p,q的交差熵,与KL距离实际上是同一回事. $-\sum plog(q)=D_{KL}(p\shortparallel q)-\sum pl ...

随机推荐

  1. 【高德地图API】从零开始学高德JS API(七)——定位方式大揭秘

    原文:[高德地图API]从零开始学高德JS API(七)——定位方式大揭秘 摘要:关于定位,分为GPS定位和网络定位2种.GPS定位,精度较高,可达到10米,但室内不可用,且超级费电.网络定位,分为w ...

  2. 教你一步一步部署.net免费空间OpenShift系列之四------绑定域名、使用CDN加速

    很抱歉这几天没有时间,有人问我怎么绑定域名的问题也没有答复,下面进入正题,惊闻ASP.Net要开源了,难道.Net春天要来了?不废话,上回书说,部署完毕ASP.Net网站后,直接访问不能访问(嗯,众所 ...

  3. 通过EA导入数据库存在表结构并生成文档

    通过EA导入数据库存在表结构并生成文档   慕课网,程序员升职加薪神器,点击免费学习 目录[-] 导入数据源,表结构 生成表结构的文档 Enterprise Architect 是超级强大项目管理功能 ...

  4. 针对不同手机系统的LBS地图定位解决方案

    原文:针对不同手机系统的LBS地图定位解决方案 摘要: 针对目前的三种手机系统:Android安卓.S60塞班.IOS苹果,做出的三种不同的手机地图应用解决方案. 查阅了多数地图API对手机的支持情况 ...

  5. PHP_零基础学php_2变量、预定义变量、预定义常量、表达式、运算符、程序控制流程

    1.变量 PHP中使用$后跟变量名表示一个变量,变量名区分大小写. 变量的数据类型 整数类型 浮点类型 字符串类型 布尔类型 数组类型 对象 <html> <head> < ...

  6. asp.net 发邮件

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  7. C语言库函数大全及应用实例三

    原文:C语言库函数大全及应用实例三 [编程资料]C语言库函数大全及应用实例三 函数名: ecvt 功 能: 把一个浮点数转换为字符串 用 法: char ecvt(double value, int ...

  8. MVC 分页1 标准的url分页

    一. 将mvcpager ddl 引用到web服务项目中. 二. 在view加入 <%@ Import Namespace="Webdiyer.WebControls.Mvc" ...

  9. Spring IOC 之个性化定制the nature of a bean

    1.生命周期回调 为了影响容器管理的bean的生命周期,你可以实现Spring的InitializingBean和DisposableBean接口.容器首先调用afterPropertiesSet() ...

  10. 使用STM32CubeMX来创建属于自己的工程

    使用STM32CubeMX的好处就是GPIO口可以使用图形化的方式进行配置,配置完成之后可以立即生成支持多种编译器的工程文件,之后打开即可编译通过了,非常方便. 操作很简单,如下所述: 1 从ST的官 ...