前几天因为好久没发blog了,就拿我毕设中的一段算法凑数,没想到引起很多人的兴趣。因此就把我的分词算法单独拎出来做了一个项目叫作DartSplitter。暂时把分词算法的名称叫做树状词库分词法。
刚刚统计了一下源代码,一共也就950多行代码,加上测试用例共1200行代码。看来确实还是想法比实现重要。说明如下:
1、由于不能用原来的专业词库,因此我特地去网上找了个Access的词库,一共有一万条记录左右,还有很多单字,因此分词的效果不会太理想。不过我这里只是为了演示一下功能,幸好从数据库转成我现的词库并不复杂,我的演示程序里提供了例子,后面还会有说明。而且,真正好的词库可能还要加入机器学习等功能,真正全面的分词可能还需要将基于词库的分词与无意义的分词结合,不过这些功能都不是那么简单的啦。
2、由于测试对词库的依赖性太强了,因此我的测试用例里没有用太多的assert,只是简单地log一下结果。而且考虑到大家用TestNG的还比较少,因此我把测试用例都改成JUnit了。测试用例与外部资源的依赖一直是困扰着我的问题,不知大家有何良策?
3、由于我现在写程序已经对Spring产生依赖症了,因此虽然我希望我程序依赖的包越少越好,但还是用了Spring,这样的好处是所有接口与关联都是可配置的。因此如果要替换掉某一部分实现也会比较简单,例如从关系数据库的词库取词的接口肯定是要重写,只要配置文件里修改一行就可以了,这个在后面说明。
4、为了方便大家使用我特意写了示例splitterTest,里面提供了两个main,一个是建词库(DictSerializationMain),另一个是对一篇文章的analysis(AnalysisTest),用了SimpleAnalyzer,StandardAnalyzer和我的TreeDictAnalyzer进行对比。
下面讲一下使用说明:
1、如果不需要修改源代码的话,只要下载dartsplitter-0.3.jar就可以了。
2、需要在新建项目的source的etc下放入以下配置文件(示例项目里都有,只要copy就行了):dartSplitter.properties, dictJdbc.properties, dartSplitterContext.xml。
dartSplitter.properties的大概内容如下:
splitter.dictDir=f:/WebDict (指定了词典的路径,主要用于lazy load,目前还没用到)
splitter.dictFile=f:/WebDict/common.dict (词典的文件名,只要将词典文件与配置对就行了)
splitter.maxWordLength=20 (放入词库的最大词长,load之后相当于树的高度)
演示的字典文件名位于dict文件夹下:common.dict。 commonDict.mdb则是当时找来的access文件。
dictJdbc.properties的内容如下:
dict.jdbc.driverClassName=sun.jdbc.odbc.JdbcOdbcDriver
dict.jdbc.url=jdbc:odbc:commonDict
dict.jdbc.username=
dict.jdbc.password=
其实就是词库文件对应的Jdbc链接啦。
dartSplitterContext.xml是Spring的配置文件,除了建词库时访问关系数据库的DAO配置要改动外,其它都不要去动。
3、建自己的词库
A、自己implements一下DictDAO接口,提供自己的实现,DictDAO的接口定义很简单,只要实现两个方法就行了,可参考CommonDictDAO的实现:
public interface DictDAO {
/**
* @param strPrefix 词的首个字
* @return 以这个字为首字的词对象(@see cn.edu.zju.dartsplitter.data.DictValue)的列表
*/
public List<DictValue> getDictValues(String strPrefix);
/**
* @return 词库中所有词的首字列表
*/
public List<String> getAllPrefixes();
}
B、修改dartSplitterContext.xml的配置:
<bean id="dictTree" class="cn.edu.zju.dartsplitter.impl.DictTreeImpl">
<property name="rebuild"><value>false</value></property>
<property name="maxWordLength"><value>${splitter.maxWordLength}</value></property>
<property name="fileName"><value>${splitter.dictFile}</value></property>
<property name="dictDAOList">
<list>
<ref local="commonDictDAO "/>
</list>
</property>
</bean>
只要在以下这段里将替换commonDictDAO为自己的DAO就行了,也可以加入新的DAO,因为我们考虑到有多个数据来源的情况,因此可以把多个DAO实现一起放入List里。
C、执行一下包里或者示例程序里的DictSerializationMain就OK了
最后感谢要一下blueGuitar,如果没有当时与他讨论时的灵感,就不会有现在的算法。
以下是项目的地址: http://ccnt.zju.edu.cn/projects/DartSplitter
我的blog地址: http://blog.itpub.net/xiecc
刘润在首富的宴请 vs. 雨中的犹豫里写到关于Chris的故事:
南京暴雨的下午。一个男孩在雨中骑自行车。非常的犹豫,不知道应该骑的快一点还是慢一点。他边骑边计算怎样淋的雨会少。他非常苦恼,不知道怎样才好。所有听到的人都在大笑。
看到这里我突然想起来我高中的时候也思考这个问题,可是那个时候没有得到结果,直到我进了大学后通过建模的方法才彻底解决了这个问题。
建模的方法是我在粒子的里学到的,常常一个非常复杂的数学问题,或者一个难以下手的实际问题,都是可以通过建模来实现的。
下面我介绍一下我对这里淋雨问题的建模和求解,当然,简化的的求解方法,不见得全面。
1.我们先对雨进行建模,我们先进行最少参数的简化建模。假设雨点是一个均匀分布和垂直往下降落的物体,就会有以下参数:
v 下降速度
r 雨点的大小
n 单位面积雨点的个数
l 两个雨点上下相距的长度
2.下面我们对在雨中行走,奔跑的人进行建模。我们的模型是简化人为一个圆柱体,分两个参数,高度和直径:
h 身高
w 就是人的宽度
s 就是人跑或者走的速度
L 两建筑物(点)之间的距离
3.初步的计算
我们对人进行了简化后实际上人能够接收到雨点的地方只有两个:
横截面 和 纵向
我们先计算横截面接受到的雨滴数目
3.1 横截面(头顶接收到的雨量)
这个雨量就应该是人头顶单位时间内接收到的雨量乘以时间
人跑完L 需要的时间: L/s
这个时间共接收到雨量的体积是:(L/s)*v*(pai/4)*w*w
那么全部的雨滴数目:
((L/s)v)*(pai/4)w*w*n/l
全部的水的体积是:
((L/s)v)*(pai/4)w*w*n/l*(4/3)*(pai)*r*r*r
3.2 纵向面(迎面接受到的雨量)
这个雨量就是人身子扫过的横断面乘以长度,这个体积是:
w*h*L
全部的雨滴的个数是:
w*h*L*n/l
全部的水的体积是:
w*h*L*n/l*(4/3)*(pai)*r*r*r
4.总的水量:
((L/s)v)*(pai/4)w*w*n/l*(4/3)*(pai)*r*r*r+w*h*L*n/l*(4/3)*(pai)*r*r*r
=n/l*(4/3)*(pai)*r*r*r*(L*v*w*w*pai/s/4+w*h*L*)
因此可以看出来,速度s是总的水量的一个函数,而且随着s的提高,总的水量在下降。因此从这个简单的模型里说,要最少的被雨淋湿,就要跑的快,越快头上的水越少。
5.当雨的方向不是垂直向下
这点我没有进行特别的计算,有兴趣的可以继续求解。
a relational visualization chart showing the branches & connections of 100 years of music using the London Underground map. train lines denote different music styles (e.g. pop.soul, reggae) & are directional according to time, branch lines represent sub-genres (e.g. rock divides into grunge & psychedelia). stations represent music artists, so that key stations naturally are linked to the most eclectic artists. see also music similarity map & artist similarity visualization & music plasma.
[guardian.co.uk (pdf) & guardian.co.uk|thnkx Rajio]
Saw this in Shanghai at a bread store. It's the most brilliant copy I've seen in the bread industry for ages - and as you know many of the great copy writers of the bread industry were killed in 1994 in that huge baking tragedy.
a live news feed aggregator featuring auto-tagged & filtered news stories from NPR (National Public Radio), augmented with different forms of data visualization. the homepage features an animated map-based feed with circles denoting the popularity of the different news story tags. in addition, the individual tag pages contain interactive timeline graphs. see also what's up news map. [reverbiage.com]