求java中文分类实现过程代码

作者&投稿:狂钥 (若有异议请与网页底部的电邮联系)
寻求Java类库中各类及方法具体实现过程。~

把所有你想知道的类和方法写到MyEclipse中,然后把鼠标放在上面,按下ctrl+鼠标左键,sun公司开源的代码就会出现了。研究一个两个也就算了,要是都研究的话,估计研究完了你 也可以编一门语言了...

#include
#include
#include
using namespace std;
#define NATTRS 5 //number of attributes
#define MAXSZ 1700 //max size of training set
#define MAXVALUE 10000.0 //the biggest attribute's value is below 10000(int)
#define K 5
struct vector {
double attributes[NATTRS];
double classlabel;
};
struct item {
double distance;
double classlabel;
};
struct vector trSet[MAXSZ];//global variable,the training set
struct item knn[K];//global variable,the k-neareast-neighbour set
int curTSize = 0; //current size of the training set
int AddtoTSet(struct vector v)
{
if(curTSize>=MAXSZ) {
cout<<endl<<"The training set has "<<MAXSZ<<" examples!"<<endl<<endl;
return 0;
}
trSet[curTSize] = v;
curTSize++;
return 1;
}
double Distance(struct vector v1,struct vector v2)
{
double d = 0.0;
double tem = 0.0;
for(int i = 0;i < NATTRS;i++)
tem += (v1.attributes[i]-v2.attributes[i])*(v1.attributes[i]-v2.attributes[i]);
d = sqrt(tem);
return d;
}
int max(struct item knn[]) //return the no. of the item which has biggest distance(
//should be replaced)
{
int maxNo = 0;
if(K > 1)
for(int i = 1;i < K;i++)
if(knn[i].distance>knn[maxNo].distance)
maxNo = i;
return maxNo;
}double Classify(struct vector v)//decide which class label will be assigned to
//a given input vetor with the knn method
{
double dd = 0;
int maxn = 0;
int freq[K];
double mfreqC = 0;//the class label appears most frequently
int i;
for(i = 0;i < K;i++)
knn[i].distance = MAXVALUE;
for(i = 0;i < curTSize;i++)
{
dd = Distance(trSet[i],v);
maxn = max(knn);//for every new state of the training set should update maxn
if(dd < knn[maxn].distance) {
knn[maxn].distance = dd;
knn[maxn].classlabel = trSet[i].classlabel;
}
}
for(i = 0;i < K;i++)//freq[i] represents knn[i].classlabel appears how many times
freq[i] = 1;
for(i = 0;i < K;i++)
for(int j = 0;j < K;j++)
if((i!=j)&&(knn[i].classlabel == knn[j].classlabel))
freq[i]+=1;
int mfreq = 1;
mfreqC = knn[0].classlabel;
for(i = 0;i < K;i++)
if(freq[i] > mfreq) {
mfreq = freq[i];//mfreq represents the most frepuences
mfreqC = knn[i].classlabel; //mfreqNo is the item no. with the most frequent
//classlabel
}
return mfreqC;
}
void main()
{ double classlabel;
double c;
double n;
struct vector trExmp;
int i;
ifstream filein("G:\\data\\for knn\\data.txt");
if(filein.fail()){cout<<"Can't open data.txt"<<endl; return;}
while(!filein.eof()) {
filein>>c;
trExmp.classlabel = c;
cout<<trExmp.classlabel<<" "; for(int i = 0;i < NATTRS;i++) {
filein>>n;
trExmp.attributes[i] = n;
cout<<trExmp.attributes[i]<<" ";
} cout<<endl;
if(!AddtoTSet(trExmp))
break;
}filein.close();struct vector testv={{142,188,11,1159,0.5513196},17};
classlabel = Classify(testv);
cout<<"The classlable of the testv is: ";
cout<<classlabel<<endl;
for(i = 0;i < K;i++)
cout<<knn[i].distance<<""<<knn[i].classlabel<<endl;
//cout<<max(knn);
}

前几天读到google研究员吴军的数学之美系列篇,颇有感触。而恰好自己前段时间做了个基于统计语言模型的中文切分系统的课程项目,于是乎,帖出来与大家共同学习。

分词技术在搜索引擎,信息提取,机器翻译等领域的重要地位与应用就不敖述了。步入正题:)

<!--[if !supportLists]-->一、 <!--[endif]-->项目概述

本切分系统的统计语料是用我们学校自己开放的那部分,大家可以在 这里 下载,中文字符约184万,当然这都是已切分好了的,可以用此建立一个比较小的语料库。本系统我主要分下面四个步骤完成:

<!--[if !supportLists]-->1、 <!--[endif]-->语料预处理

<!--[if !supportLists]-->2、 <!--[endif]-->建立 2-gram(统计二元模型)

<!--[if !supportLists]-->3、 <!--[endif]-->实现全切分

<!--[if !supportLists]-->4、 <!--[endif]-->评估测试

下面我分别对这四个方面一一道来。

<!--[if !supportLists]-->1、 <!--[endif]-->语料预处理

下载的已切分的语料都是形如“19980131-04-012-001/m 现实/n 的/u 顿悟/vn 却/d 被/p 描/v 出/v 形/Ng 来/v 。/w ” ,有的前面还保留了日期编号,因为这些切分语料的来源是人民日报。预处理主要是按标点符号分句,句子简单定义为( 。?! : ;)这五种标点符号结尾的词串,句子首尾分别添加<BOS>和<EOS>这两个表示句子开始和结束的标记,这在2-gram建模时要用的,后面会提到。处理过程中,忽略词类信息和前面的日期信息,因为我这个切分系统不考虑词类标注。如前面这句预处理后应该为下面形式 “<BOS>现实 的 顿悟 却 被 描 出 形 来 。<EOS>” ,当然切分词之间你可以用你想用的符号标记,而不必是空格。因为考虑到所有的英文字符和数字的ASCII,我用了下面方法实现之:

out ; //输出流

in; //输入流

StringBuffer s1 = new StringBuffer(); //缓冲

char a = in.read();

while (a != -1) //判断是否已到流的终点

{

if ((a == '。' || a == '?' || a == '!' || a == ':' || a == ';' )) //一句结束

{

String s2 = new String(s1);

out.write("<BOS>"); //在句子前加 <BOS>

out.write(s2);

out.write("<EOS>"); //在句子末尾加 <EOS>

out.write('/n'); //换行

s1 = new StringBuffer();

}

else if ( a == '/')

s1 = s1.append((char)32); //分词位置空格

else if (a > 256 )

s1 = s1.append((char)a);

a = in.read();

}

out.close();

in.close();

<!--[if !supportLists]-->2、 <!--[endif]-->建立 2-gram模型(统计二元模型)

在这里首先简单介绍一下n-gram模型和2-gram模型。

根据语言样本估计出的概率分布P就称为语言L的语言模型。对给定的句子s = w1w2…wn,(数字,n,i都为下标,wi为句子s的一个词)。由链式规则(Chain rule),P(s) = p(w1)p(w2|w1)p(w3|w1w2)……p(wn|w1w2w3…w(n-1)) , 对p(wi|w1w2…w(i-1))而言,(w1w2…w(i-1))即为wi的历史。考虑前面n-1个词构成历史的模型即为n-gram模型。 n越大,提供的语境信息也越多,但代价就越大,且需训练语料多;n较小时,提供的信息比较少,但计算代价小,且无需太多训练语料。

令c(w1,…,wi)表示词串w1,w2…wi在训练语料中出现的次数,则由最大似然估计, P(wn|w1,…,w(n-1)) = c(w1,…,wn) / c(w1,…,w(n-1)). 同理,则2-gram为 P(wn|w(n-1)) = c(w(n-1),wn) / c(w(n-1)).

若想了解更多相关知识,大家找相关资料看看,随便把大学时的那本概率与统计课本拿出来翻翻,数学真是一个好东东:)

回归项目:) 训练语料一共有5万多个不同的词。建立2-gram统计模型时不断要把每个词在训练语料中出现频率统计出来,还要把每个词及其后面的那个词组成的2-gram在训练语料中出现频率统计出来。因为在切分时会频繁的在建立的2-gram模型中查找相关的数据,所有,存储这个2-gram模型数据的数据结构一定要能提供高效的查找。故选择hash表,它能提供常数时间的查找。Java类库里提供了HashMap类,基于数据两还不是非常大,故可直接拿来用。在存储时,每一个key值对应一个在训练语料中出现过的词语,而每一个key值对应的value值又是一个HashMap。暂且称为子hashmap.这个结构有点类似文件结构里的二级索引。 其相关代码如下:

怎么在预处理文件里把词分别读出来就不罗嗦了,方法:每读入一行,按空格分成String数组,用个正则表达式匹配下即能得到。

//此方法传入的两个词组成一个2-gram,prewd为前一个词,currwd为紧随其后的词

public static void add(String prewd , String currwd){

String key = prewd;

String curr = currwd;

boolean bb = HMap.containsKey(key); //Hmap是一个已存在的HashMap,用来存储2-gram统计模型。在这里判断 preword 是否在 主map 中

if (bb == false) { //若 主map 中无,则添加

HashMap hm = new HashMap(); //首先,新构造一个 子MAP

hm.put(key , new Integer(1)); //存储 主KEY 的频率 hm.put(curr , new Integer(1)); //存储 主KEY 后面紧接着的那个词频率

HMap.put(key,hm); //将 主KEY 和对应的 子MAP 放入 主MAP 中

}

else //若 主map 中含有该词

{

HashMap temp = (HashMap)HMap.get(key); //返回 主KEY 所对应的 子MAP ,进行值的修改

int count = ((Integer)temp.get(key)).intValue() + 1; //在 子map 中将 主key 次数加 1

temp.put(key , new Integer(count));

if (temp.containsKey(curr)) //判断 子map 中是否含有该词

{

int value = ((Integer)temp.get(curr)).intValue() + 1; temp.put(curr , new Integer(value));

}

else

temp.put(curr, new Integer(1)); //若无,则将其存入子map

HMap.put(key , temp); //子map 修改完毕 ,将其重新放入 主map

}

}

}

因为语言中的大部分词属于低频词,所以稀疏问题肯定存在。而MLE(最大似然估计)给在训练语料中没有出现的2-gram的赋给0概率。所以还得对2-gram模型进行数据平滑,以期得到更好的参数。目前平滑技术比较多,如Add-one,Add-delta,Witten-Bell,held-out留存平滑等。本系统主要采用了Add-delta和held-out两中平滑方式,下面就Add-delta平滑技术为例,对2-gram进行平滑。对2-gram模型,其平滑公式为:

P(wn|w(n-1)) = [c(w(n-1),wn) + delta ] / ( N + delta * V) ,这里去delta为0.5

其中,N:训练语料中所有的2-gram的数量

V:所有的可能的不同的2-gram的数量

平滑思路 :1.产生主hashmap的迭代器iterator,依次读key;

2.对每一个key,又读出其value,即一个子hashmap;

3.然后根据平滑公式对子map里的值进行计算修改

算法框架:

Iterator it = 主hashmap.keySet().iterator();

While(it.hasNext())

{

主key = it.next();

子hashmap = (HashMap)主hashmap.get(主key);

Iterator itr = 子hashmap.keySet().iterator();

While(itr.hasNext())

{

根据平滑公式依次计算修改

}

}

注意问题:1.因为计算得出的概率值一般都比较小,为了防止出现下溢,可对其取对数,再取反。

2.每一个主key所对应的所有没有出现过的,即频率为零的2-gram,统一用一个键值对存储在相应的子hashmap里即可。

完毕,对象序列化。使用该系统时,lazy load将其载入内存,然后可让其一直存活在内存,这会大大加快速度。

到此,2-gram模型建立完毕。

<!--[if !supportLists]--> 3、 <!--[endif]-->全切分实现

切词一般有最大匹配法(MM、RMM),基于规则的方法,基于统计的方法。关于前两者就不罗嗦了。所谓全切分就是要根据字典得到所以可能的切分形式。歧义识别的方法主要有:基于规则的方法和基于统计的方法。这里当然是采用基于2-gram统计模型的方法了:)为了避免切分后再进行歧义分析的时间浪费。并且这里采用边切分边评价的方法,即在切分进行的同时进行评价的方法。

对一个句子进行全切分的结果,即所以可能的组合,可以形成一棵解空间树

于是,可用回溯法搜索最优解

若将所有的全切分组合先搜索出来,然后再根据2-gram选择最佳,显然会很浪费时间,因为过程中可能存在很多的重复搜索,而回溯搜索的时间复杂度为指数时间

所以,在搜索过程中要结合 剪枝,避免无效搜索,可很大提高效率

采用树的深度优先法则。可找到最优解

具体算法如下:

Stack.push(BOS) //树节点

while stack不为空

x=stack.pop()

pos:=x.Pos, w = x.w oldvalue:= x.value preword:=x.preword

if m>O then //m为首词串的个数

forj:=1 to m do

FWj为fwc的第j个元素l

if length(w+FWj) =length(c)且概率最大 then output w+FWjl且设置最新的句子最大概率值

else

posl:=pos+length(FWj)l

if probability(w+FWj,posl,newsate)>maxValue(pos1)

stack.push(x)

endif

endfor

endif

endwhile

end.

在算法实现过程中需要考虑一些诸如树节点保存,首词串处理等问题。

4.评估测试

环境:windows XP2, AMD Athlon 1800+, Memory 768m,JDK1.5

Delta平滑:随着delta的取值变小,准确率上升,0.5,0.01,0.0001

召回率: 0.9756 0.9826 0.9928

准确率: 0.9638 0.9710 0.9883

留存平滑

召回率: 0.9946

准确率: 0.9902

一般情况下,留存平滑应该还是比delta平滑更好

所有建模过程及平滑过程在1分钟内都可完成。

切分时间与效率:

<!--[if !supportLists]-->n <!--[endif]-->测试语料,17455字符, (中文17287),平均句长 41个字,时间 :340ms, 平均切分速度:5.1 万/S

<!--[if !supportLists]-->n <!--[endif]-->20.5万测试语料(取自笑傲江湖), 预处理后 17.46万 ,时间 110 MS,句子文本行数目 24945,平均句长 7 , 切分时间 1300MS , 平均13.46 万 / 秒

<!--[if !supportLists]-->n <!--[endif]-->20.5万测试语料(取自笑傲江湖),不预处理,平均句长 239 ,切分时间40S, 平均 5000字/秒

回溯算法是时间开销为O(N!),所以在切分过程中句子长度直接决定了切分的速度,因为句子越长词越多

经过预处理,句子短,平均句长 7, 回溯短,故速度要快很多。

到此,该系统基本完成,告一段落。感觉写的挺乱的呵呵

现在在做另一个作业,做个简单搜索引擎,准备把这个东东结合在搜索引擎里面,实现切分功能:)

这是一个强大的语义+语法+词法分析器,很难很强大
做好了,你可以试试来百度工作

去找找中文分词的资料吧

其实你的问题是个世界性的难题!中文分类虽然比英文容易但是也不是一般人能做的,这个东西太复杂,我们现在就有人做呢


JAVA中,类、对象、实体、实体类、实体对象之间存在怎样的联系??请高 ...
比如交通工具里边如果你要实现对各种交通工具进行分类这个功能的话,需要一个manager管理类来管理一下每种交 通工具,这个类的行为就是专门来分类的,复杂点的行为,也就是分类之后进行统计,并且它分类与每种交通工具密 切相关,这个你可以自己去联想一下!实体对象java应用开发中很少提到吧```一般都是...

中文分词的常见项目
引入隐喻,采用完全的面向对象设计,构思先进。高效率:在PIII 1G内存个人机器上,1秒可准确分词 100万汉字。采用基于 不限制个数的词典文件对文章进行有效切分,使能够将对词汇分类定义。能够对未知的词汇进行合理解析。仅支持Java语言。 MMSEG4J基于Java的开源中文分词组件,提供lucene和solr 接口:1....

java程序员大学生必看的7本书
本书为你剖析Java中各个内容的设计理念。需要有一定编程基础的人才可阅读,即使很多内容还无法理解,但每次读完一定会有所收获。这是一本伴随我们技术成长的好书,买一本放在旁边,摸着就有底气。 Effective Java中文版 本书针对如何编写高效、设计优良的程序提出了最实用、最权威的指导方针,通过90条简短、独立的经验法则...

java web怎样实现商品分类显示
首先要在数据库中分好类,比如 1代表食品类 2代表家用电器类 ,然后页面点击的时候 点击食品类 传参数1,然后用sql查询的时候加上where条件就行了

java 判断数据类型和方法的参数类型相同
1、如果你得到是一个Object对象,可以用if(obj instanceof String)来判断是否是String对象,int是基本类型不可以这么判断,只能用它的包装类Integer,同样用instanceof 。2、如果set方法只能接受一个参数,而且必须有int的话,可以写多个set方法,如set(String),set(int),编写不同的处理逻辑。3、...

java如何实现mysql数据库有中文字段中文排序
如果字段是gbk字符集的直接order by 如果是UTF-8字符集,查询的时候,通过convert函数,把查询出来的数据使用的字符集gb2312编码就可以了,然后使用convert之后的中文排序。如:select name from test1 order by convert(name using gb2312) asc;

这几个Java网站大学生福音!
这是一个非常不错的学习 Java 的在线网站,纯免费。这是一个个人项目,旨在通过简单有效的在浏览器中进行练习让你快速掌握 Java 编程语言。通过直接从网络浏览器运行实际代码,你无需在本地安装和执行代码就可以尝试编码,这无疑提高了编程效率和上手效率。你可以根据目录进行练习,有基础部分和高级部分首先有例子代码,告...

java中。我写了一个类A,该类中有一个静态的类方法和定义了一个实例方法...
最直观的区别就是两种方法的调用不同,静态方法的调用是:类名.方法,不用获取对象,而实例方法需要先获取对象,然后:对象名.方法 希望能帮到你

Java语言主要特点有哪些?
Java使用Unicode作为它的标准字符,这项特性使得Java的程序能在不同语言的平台上都能撰写和执行。简单的说,你可以把程序中的变量、类别名称使用中文来表示<注>,当你的程序移植到其它语言平台时,还是可以正常的执行。Java也是目前所有计算机语言当中,唯一天生使用Unicode的语言。 已赞过 已踩过< 你对这个回答的评价...

JavaSE是什么
Java se是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台的总称。用Java实现的HotJava浏览器(支持Java applet)显示了Java的魅力:跨平台、动态的Web、Internet计算,从此Java被广泛接受并推动了Web的迅速发展,常用的浏览器现在均支持Java applet。Java语言恐怕是稳居网路应用程序语言的...

吴旗县15340286349: 求java中文分类实现过程代码 -
孟该雷帕: 前几天读到google研究员吴军的数学之美系列篇,颇有感触.而恰好自己前段时间做了个基于统计语言模型的中文切分系统的课程项目,于是乎,帖出来与大家共同学习.分词技术在搜索引擎,信息提取,机器翻译等领域的重要地位与应用就不...

吴旗县15340286349: Java中如何实现中文排序 -
孟该雷帕: public class SortByChinese {//测试 public static void main(String[] args) { String[] a1 = {"保定","何子安","于小云","刘帝","刘何保定子安","刘","刘娜","家强","刘博"};getSortOfChinese(a1); for (int i = 0; i ...

吴旗县15340286349: Java编程中怎样实现中文排序 -
孟该雷帕: 简单的实现排序,可以参考如下的代码 import java.text.Collator; import java.util.Arrays; import java.util.Comparator; import java.util.Locale; public class PYDemo { public static void main(String[] args) { String[] names= {"赵z子z龙l","刘l备b",...

吴旗县15340286349: 寻求Java类库中各类及方法具体实现过程. -
孟该雷帕: 把所有你想知道的类和方法写到MyEclipse中,然后把鼠标放在上面,按下ctrl+鼠标左键,sun公司开源的代码就会出现了.研究一个两个也就算了,要是都研究的话,估计研究完了你...

吴旗县15340286349: java编个中文分词的程序 -
孟该雷帕: import java.io.Reader; import java.io.StringReader; import org.apache.lucene.analysis.*; import org.apache.lucene.analysis.cjk.CJKAnalyzer; import org.apache.lucene.analysis.cn.ChineseAnalyzer; import org.apache.lucene.analysis.standard....

吴旗县15340286349: java中文分词进行网页分类 -
孟该雷帕: 分词算法没做过 可以去参考下Lucene(一个开源搜索引擎)的中文分词器的用法 至于分类可以去参考下谷歌黑板报上的介绍的一个方法 大概是文本中所有词的余弦值 然后进行分类

吴旗县15340286349: 汉语句子拆分算法 java实现 高手请指教 -
孟该雷帕: 这个分词是一个很大很难的东西,中科院做了五年才做出ICTCLAS,如果你自己写的话估计可以晕了,建议你用现成的分词工具,用java调用,比较好的有上面的ICTCLAS,如果你是做搜索引擎,那么用lucene支持的一些分词工具会很不错

吴旗县15340286349: 求一个JAVA的汉字排序程序...
孟该雷帕: 对汉字是按拼音排序的,示例: import java.util.*; import java.text.*; public class Test{ public static void main(String args[]) { //Comparator cmp = (RuleBasedCollator)java.text.Collator.getInstance(java.util.Locale.CHINA);//try testing various locales ...

吴旗县15340286349: 编写一个java类People.java 如下属性name(String类型),age(int类型),addr(String类型),phone(int) 求代码 -
孟该雷帕: public class People {private String name;private int age;private String addr;private int phone; public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void ...

吴旗县15340286349: 求KNN文本分类算法java实现源代码【散分了!!!!】 -
孟该雷帕: #include #include using namespace std;#define NATTRS 5 //number of attributes#define MAXSZ 1700 //max size of training set#define MAXVALUE 10000.0 //the biggest attribute's value is below 10000(int)#define K 5 struct vector { double ...

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网