星期二, 四月 28, 2009

如何使用基于Suffix Array的String Kernel

String Kernel是这样一种Kernel方法,它根据两个字符串的所有公共子串计算它们的相似度,最简单的方法是用Dynamic Programming的办法,但复杂度较高,是N的平方。通过使用Suffix Tree或Suffix Array可以成功地把复杂度降为线性的,参见论文:eprints.pascal-network.org/archive/00002056/01/VisSmo04.pdf
我对String Kernel很感兴趣的原因是它有广泛的用处,比如可以利用它仅通过链接的URL和Anchor Text对它的主题进行分类(Focused Crawling的关键技术)。自己先是从网上下到了libSVM网站上提供的一个C语言的String Kernel源码(http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/string/libsvm-2.84-string.zip),利用它对以前下过的数据集进行了尝试,结果很令人兴奋。自己昨天晚上利用BestFirst方法共下载了近万个网页,其中有74%是与主题“Linux" 相关的。自己把这些下载的URL中的三分之二交给String Kernel SVM进行学习,然后对剩下的三分之一个URL进行分类,结果如下:
Precision = 84%, Recall = 92%
自己花了一天的时间又找到了两个提供String Kernel的SVM包:一个是Weka的最新版中提供了一个基于Dynamic Programming的平方复杂度的Java类包(http://www.cs.waikato.ac.nz/ml/weka/里的Developer Verstion),自己花了一个下午的时间终于让它在自己的数据集上运行了起来,但已经过去两个小时了,程序还是没有结束,自己为了备查它的使用方法,把自己的Java程序开列如下:
import java.io.File;

import weka.classifiers.functions.SMO;
import weka.classifiers.functions.supportVector.StringKernel;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.converters.ArffLoader;


public class Test {
public static void main(String[] args) throws Exception {
ArffLoader loader = new ArffLoader();
loader.setFile(new File("train"));
Instances instances = loader.getDataSet();
instances.setClassIndex(0);

SMO svm = new SMO();
StringKernel kernel = new StringKernel();
kernel.setOptions(new String[] { "-D", "-P", "1" });
svm.setKernel(kernel);

System.out.println("Starting classifying...");
svm.buildClassifier(instances);
System.out.println("Done");

loader.setFile(new File("test"));
instances = loader.getDataSet();
instances.setClassIndex(0);

int n = instances.numInstances();
int TP = 0, FP = 0, TN = 0, FN = 0;
for (int index = 0; index <>
Instance instance = instances.instance(index);
double value = svm.classifyInstance(instance);
if (value <>
if (instance.stringValue(0).equals("yes")) {
TP++;
} else {
FP++;
}
} else {
if (instance.stringValue(0).equals("no")) {
TN++;
} else {
FN++;
}
}
}
double precision = 1.0 * TP / (TP + FP);
double recall = 1.0 * TP / (TP + FN);
double F1 = 2 * precision * recall * 1.0 / (precision + recall);

System.out.printf("TP = %d, FP = %d, TN = %d, FN = %d\n", TP, FP, TN, FN);
System.out.printf("precision = %%%.2f, recall = %%%.2f, F1 = %%%.2f\n", precision, recall, F1);
}
}

另一个是SVMSequel软件包(http://www.cs.utah.edu/~hal/SVMsequel/),它最大的优势之一是它提供了一种基于SuffixTree的线性复杂度的String Kernel和Tree Kernel,可惜它的下载网址打不开,另外它的全部代码由Caml语言编写。后来自己在Google Code Search里通过查找间接下载了它的源码,自己打算以后有时间学学Caml语言再把它的源码改写成Java。
String Kernel目前最快的算法是基于Suffix Tree或Suffix Array的方法。目前网上能够找到的源码实现除了SVMSequel(现在源码好象无法下载得到,而且是基于OCaml语言)外,能够找到的并且可用的非常少。SASK(http://users.rsise.anu.edu.au/~chteo/SASK.html)是最新的基于Suffix Array的实现,它基于Linux下的C++实现,但仅提供String Kernel的计算功能,如何与SVM结合起来直接使用并没有给出说明。自己在和它的作者进行了第14次通信后终于弄懂了利用它进行SVM分类的详尽过程,现在写在这里留给将来备忘:
首先下载http://users.rsise.anu.edu.au/~chteo/SASK.html上的两个压缩包sask-1.1(http://users.rsise.anu.edu.au/~chteo/src/sask-1.1.tgz)和SASK experiments(http://users.rsise.anu.edu.au/~chteo/src/sask_icml06_expt.tgz)。然后分别将它们解压缩并且执行make命令。假设解压缩后的根目录分别为sask-1.1和sask_icml06_expt。
再到libsvm网站上下载最新的libsvm,要求是2.84版本之后的,这样它具有利用Precomputed Kernel Matrix的输入数据格式的功能。
运行sask-1.1/src目录下面生成的line-libsvmkm可执行文件,将提供的文本训练集转化成libsvm可以接受的Kernel Matrix格式。
将生成的基于Kernel Matrix格式的libsvm训练文件交给libsvm里的svm-train可执行文件,得到对应的svm-model文件。这个文件里有rho值和各个Support Vector的序号和它们的alpha值。
利用这些Support Vector及对应的alpha值构建一个与训练集对应的StringKernel对象,具体代码参见sask_icml06_expt/Code里面的 ltp-sa-sl.cpp文件,大致过程如下:
将各个Support Vector每个后面加一个'\n'的SENTINAL字符后串接一起,形成一个Master String,假设这个字符串保存在data这个std::string里,然后:

//swf和swfParam是调节weight的参数
StringKernel sk(data.size(), (SYMBOL*)data.c_str(), swf, swfParam);

//alphas保存各个Support Vector的alpha值的数组,data_len保存各个Support Vector的长度, n是Support Vector的数目
sk.Set_Lvs(&alphas[0], &data_len[0], n);

sk.PrecomputeVal();

至此,一个分类器已经创建成功,如果对一个字符串pattern进行分类,通过如下语句计算它对应的svm值(保存在kval这个变量里),减去rho后的符号即为它的label:
sk.Compute_K((SYMBOL*)pattern.c_str(), pattern.length(), kval);

使用起来其实真的很简单。如果训练数目巨大,还可以考虑用SVM-light取代libsvm以得到Support Vector及它们的alpha值。

Tips

针对不同的Boss:
学校的老师:Boss就是权威,容不得你一点挑战(对Boss说话永远要毕恭毕敬,注意语气,能少说尽量少说)

星期一, 四月 20, 2009

高调做事,低调做人

遇到尊重自己的人时,只要他愿意,一定要与之结婚,不要找任何的借口,没钱,可以不办婚礼,一个百年不变的承诺,一张结婚证,一张结婚照既可。钱可以随时挣,感情却是可遇不可求;有时候一时的错过 ,就是一生的错过,或者,一生的遗憾。
爱一个人要付出很大代价,但不爱任何人,代价会更大;所以,不管你受过多少的伤,承受了多少的痛,都不能用冷漠来对待人生。道理很简单,你给人以热情,对方未毕还你热情,但你给人以冷漠,对方肯定会还你冷漠,甚至是加倍。
纵情的结束便是后悔的开始,因此,无论多沮丧多绝望都不要去体味放纵。
遇到曾背叛你的人时,要跟他好好聊聊,因为是他教你读懂了这世界;遇到曾爱过你的人时,记得感激他,因为他让你明白了爱;遇到你曾误会过的朋友时,要及时说声对不起;因为你亵渎过他对你的信任。我爱你三个字不要轻意说出口,这三个字只能对三个人说,一是那个给你生命的人,二是第一个你爱的人,三是与你结婚的那个人。
不要轻意相信诺言,更不能相信明知无法兑现的诺言。
学会忍耐,更要明白,忍耐不是懦弱,它不过是暂时把带剌的东西攥在手里,准备将来当做武器抛出。
做事要先有冷静的头脑,再有清析的思路;遇到无法控制的事时,尽量学会控制自己的情绪,以免造成无法收拾的结果。
为人子者,最大的不幸莫过于:子欲孝而亲不在,切记,及时行孝。
不要总是为过去犯过的错而后悔愧疚,想明白为什么会犯错,学会如何不再犯同样的错以及怎么样去弥补犯下的错才是你该深思的。
不要常在人前提起自己过去的辉煌,总盯着了不起的过去,就不会有了不起的将来。
人生是一份没有满分的的试卷,因为有些题根本就没有答案;再者,九十九分和一百分在绝大多数情况下是没什么区别的,所以,不要过份地追求完美。
往高处爬之前,先衡量一下自己的力气;而在跳入一个深坑之前,更要先弄清它有多深;做任何事都要量力而行。
快乐是一天,悲伤也是一天;轻松是一天,沉重也是一天;抱怨是一天,感恩也是一天,有什么理由选择后者?
生命的长度你可能无法把握,但你能把握生命的质量,不要虚度生命中的每一天,尽量充实自己。
当你伤心时,有人比你更伤心,更沮丧,更绝望,其实生活是没有极端的,关键在于你的心态。
在人之上,视人为人,在人之下,视已为人;任何时候,自尊都不能丢,别人的自尊更不能夺。
遇到困难时,不要指望奇迹会出现在你身上,自救才是摆脱厄运唯一的出路。
现实中的你也许要经历许多挫折,但千万不要灰心,因为最因难的时候你往往受益最深。
做错事时要敢于承担责任,对便是对,错就是错,不能自欺欺人,圣人孔子都有犯错的时候,更何况你?要学会道歉,学会反省自己,学会为自己的言行负责。
能用钱解决的问题,都不是什么问题,但不能偏激的认为金钱万能,至少有:金钱治不好艾滋病;金钱买不到朋友的真心;金钱买不到安安稳稳的睡眠,金钱买不到快乐。
不要为自己的相貌或者身高过分担心和自卑。人的心灵远胜于相貌,请相信这点。人就像一本书,相貌和身高就像书皮,而一本书光书皮做得漂亮是没有用的,真正耐人寻味的还是书的内容。
任何时刻都要保持自信,一个连自己都信不过的人,是没人会信任,没人敢信任的。
受到再大的打击,只要生命还在,就有希望,因为每一天的太阳都是新的。
不要因为寂寞而去恋爱,要将寂寞暂时关押,要学会品味寂寞。
女人一定要珍爱自己,只有把自己保护好了,才有机会去爱别人或别人来爱你。
人生中有很多无奈,要学会善待自己;接受自己不能改变的一切,改变自己能改变的一切。逃不掉的,改变不了就选择接受,去习惯,当伤与痛,成为一种习惯时,犹如生活中的一日三餐,那便不叫伤,不叫痛了,也无所谓伤,无所谓痛了。慢慢将伤痛与无奈一点一点地化解于生活当中,省去不必要的挣扎和煎熬,才能换取遇事不惊,坦然处世之心境;就算世界再灰暗,时间也不会抛弃你,它可以让你从容地成长和遗忘…
还是那句话:世上无难事,只怕有心人!这是我永远坚信的

24个日常习惯

成功与失败的最大分野,来自不同的习惯。好习惯是开启成功的钥匙,坏习惯则是一扇向失败敞开的门。因此,首先要做的便是养成良好的习惯,全心全意去实行。

我们养成习惯,习惯支配我们。—-John Dryden

清晨

1.早起:我很喜欢在凌晨5点起床,并花一些时间在上班前自己该做的工作上。
1. Wake Early:I am a big fan of waking at 5am and spending time working on myself before going to work.

2.锻炼:当我有了1周4次锻炼的目标后,我发现,告诉自己“我要锻炼而非明天”是很容易的。设置日常锻炼的期望值,远离那些潜在的借口,我已受益于这些日常习惯。
2. Exercise:when I had the goal of exercising 4 times a week I found it was very easy to tell myselfI will exercise tomorrow instead.Setting the expectation of daily exercise removed this as a potential excuse and I have since reaped the benefits of this daily habit.


3.回顾或(甚至更好)调整您的目标:每一天我设法接近实现我的短期,中期和长期目标。开始一天的回顾或调整我的目标意味着我能更好的认识一整天。正如罗宾·夏尔马所说:有了更好的认识你可以做出更好的选择,当你做出更好的选择,你会看到更好的结果。
3. Review or (even better) Rewrite Your Goals:each day I try to get closer to achieving my short, medium and long term goals. Starting the day by reviewing or rewriting my goals means that I have better awareness of them throughout the day. As Robin Sharma says:
With better awareness you can make better choices and when you make better choices, you will see better results.


4.阅读和(或)听励志材料:在早上一整天的没完没了可能的摆在面前。我激励自己好好去读和听励志书籍或有声读物。
4. Read and/ or Listen to Motivational Material:in the morning a whole day of endless possibilities lies ahead. I motivate myself to play my best game by reading and listening to inspirational books/ audiobooks.


5.预先设想一天:我想闭上几分钟眼睛,然后花些时间想象未来的一天将要发生什么。令人感到惊讶是,当我做到这一点时,我的愿望常常变成现实。
5. Visualise the Day Ahead:I like to take a few minutes to shut my eyes and visualise what I want happen in the coming day. It’s amazing how often my desires become reality when I do this.


6. 写一个“To Do” 清单:我喜欢在我的记事簿里列出一天需要去做的重要任务。每完成一件事就划掉它,这种方法简单高效。
6. Write a “To Do”list:I like to write out a list in my diary of the important tasks I need to do that day. As they are completed I put a line through them. So simple, yet so effective.


7.了解新闻提要:我认为了解那些正在发生在我们的社区和社交圈里的事情很重要。然而,如果了解不到主要详情,我发现很容易遗漏一天的交往。
7. Check the News Headlines:I think it’s important to have an idea of what is happening in our community and the world. Also if don’t at least check the main stories, I find it is easy to feel left out of conversations throughout the day.


8. 摄入多种维生素:我尽量吃得均衡些,但每日摄入多种维生素保证我获得适量人体所需的维生素和矿物质。
8. Take a Multivitamin:I try to eat a well balanced diet, but taking a multivitamin daily reassures me that I obtaining the proper amount of vitamins and minerals that I need.


9. 收拾整理:一间杂乱不堪的房子能导致思想混乱和想法模糊。我认为最好坚持的头件事就是每天收拾整理。
9. Tidy Up:a cluttered house can lead to a cluttered mind and fuzzy thinking. I find it’s best to stay on top of things by tidying up each day.


10. 花些时间在仪表上:现实生活中人们常会以貌取人。每天早晨我是否花几分钟在仪表上,以确保我自己以最好的形象融入社会交往。
10. Take Time to Look Good:it’s a reality of life that people judge us by our appearance. I take a few minutes each morning to ensure I go out into the world looking the best I can.


白天
11. 重要的事情先做:许多人的日常被紧迫但不一定是重要的任务控制控制着。例如:打岔的事,一些电子邮件和电话。“重要的事情先做”的习惯就是组织和执行你的生活方式围绕你的最优先考虑的事。
11. Put First Things First:Many people have their day controlled by tasks that are urgent , but not necessarily important. Examples include interruptions, some email and some phone calls. The habit of putting first things first is about organising and executing your life around your deepest priorities.


12.亲近自然:我觉得花时间在户外可以给我带来不寻常的幸福感。
12. Connect with Nature:I find spending time outdoors in nature is great for my sense of wellbeing.



13.写博客:写博客使我思考和写—这是我每天不能获得满足的两件事。
13. Blog:blogging makes me think and write - two things that I can’t get enough of each day.



14.健康快餐好:我用水果、蔬菜(胡萝卜和芹菜等)和坚果替代炸马铃薯条、糖果和巧克力。
14. Snack Well:I substitute the chips, candy and chocolate with fruit, vegetables (carrots and celery are great to chomp on) and nuts.


15.积极主动:积极主动意味着显示出创造力和敢于实践。每当我想要做,我问自己:我能做些什么来做到这一点?
15. Be Proactive:being proactive means showing initiative and taking the responsibility to make things happen. Whenever I want something to happen, I ask myself:what can I do to make this happen?


16.与朋友保持联系:每天我设法发送快速电子邮件或文本给朋友。当我非常忙时,这是一个很好与朋友保持联络的方式。
16. Ping a Friend:I try to send a quick email or text to a friend each day. It’s a great way to stay in touch with friends when I am extremely busy.


17.储蓄:我至少将每次薪水的10 %用于储蓄。.发现一个很好储蓄的方式就是逐项列出日常金额数,例如10-15美元。
17. Save:I save at least 10% of each paycheck. A great way to find the money to save is to break it down to a daily amount, for example $10-15.


晚上
18.家庭时间:在一个普通的工作日我几乎不会见我的配偶和儿子,至少我认为重要的是在那里大多数的夜晚。家庭时间意味着数量和质量 。
18. Have Family Time:on a typical workday I won’t see much of my partner and son, so I believe it’s important to, at the very least,be theremost evenings. Family time is aboutquantityandquality.


19.用牙线清洁牙缝:这是一种必不可少的可以减少龋齿和牙床疾病的方式。您为什么不想拥有最好的微笑吗?
19. Floss:This is essential to reduce tooth decay and gum disease. Why wouldn’t you want to have the best smile possible?


20.放松:我设法在就寝前约30至60分钟关掉电脑和电视,经过漫长的一天,让我的大脑有一些休息时间。当我做到这一点我睡更安静。
20. Wind Down:I try to switch off the computer and the TV about 30 to 60 minutes before bedtime and let my brain have some down time after a long day. I sleep far more peacefully when I do this.


21.回顾一天:我认为坚持对自己全天所做的事进行反思是一种很好的方式。我一步步接近实现我的目标了吗?我完成了我清单上所要做的事情吗?我每天按计划进行了吗?如果不是这样,为什么没有实现呢?
21. Review My Day:I find this is a great way to hold myself to account for taking action throughout the day. Did I get closer to achieving my goals? Did I complete my to do list? Did my day go as planned? If not, why not?


22.阅读:我喜欢阅读并且整天连续这样做。我觉得睡觉前尤其适合阅读。当然阅读地应该是休闲方面的书,而非有关核物理等专业书籍。
22. Read:I love to read and do so continuously throughout the day. I find it is especially good to read just before to going to bed. Just makes sure it’s a relaxing book, and not one about nuclear physics.


23.对家人说我爱你:不只是假设您的家庭成员知道你爱他们。我每天至少对我的配偶和儿子说一次“我爱你”。
23. SayI Love Youto My Family Members:don’t just assume that your family members know you love them. I say these words to my partner and sonat leastonce per day.


24.在一个合适的时间上床睡觉:这个清单第一个习惯(早起)的前提是:在一个合适的时间睡觉和晚上获得良好睡眠。
24. Go to Bed At A Reasonable Time:the first habit of this list (waking early) begins by going to bed at a reasonable time and getting a good nights sleep.

星期三, 四月 15, 2009

web/text mining Data structure

网页在render的时候都生成DOM树的,所以树形的数据结构用的会比较多,常见的结构:
Trie,
Patricia tree/Radix tree一种trie的压缩形式,它把只有一个孩子的结点与他的孩子合并,这样边上
就会有多个Character
suffix tree
这几个结构对发现网页中的Repeat pattern以及结点相似度提供了一个线性的算法。
常用的算法有:String Edit Distance以及Tree Edit distance来比较结点子树的相似度,这种算法常常在raw DOM tree上进行的,这两个算法都是用了动态规划算法,复杂度都在n的平方级别。
已经有大量的论文基于这些结构和算法来实现网页block分析和结构化数据的挖掘。

星期二, 四月 14, 2009

JVM内存模型以及垃圾回收

JAVA堆的描述如下:

内存由 Perm 和 Heap 组成. 其中

Heap = {Old + NEW = { Eden , from, to } }

JVM内存模型中分两大块,一块是 NEW Generation, 另一块是Old Generation. 在New Generation中,有一个叫Eden的空间,主要是用来存放新生的对象,还有两个Survivor Spaces(from,to), 它们用来存放每次垃圾回收后存活下来的对象。在Old Generation中,主要存放应用程序中生命周期长的内存对象,还有个Permanent Generation,主要用来放JVM自己的反射对象,比如类对象和方法对象等。

垃圾回收描述:

在New Generation块中,垃圾回收一般用Copying的算法,速度快。每次GC的时候,存活下来的对象首先由Eden拷贝到某个Survivor Space, 当Survivor Space空间满了后, 剩下的live对象就被直接拷贝到Old Generation中去。因此,每次GC后,Eden内存块会被清空。在Old Generation块中,垃圾回收一般用mark-compact的算法,速度慢些,但减少内存要求.
垃圾回收分多级,0级为全部(Full)的垃圾回收,会回收OLD段中的垃圾;1级或以上为部分垃圾回收,只会回收NEW中的垃圾,内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。

当一个URL被访问时,内存申请过程如下:
A. JVM会试图为相关Java对象在Eden中初始化一块内存区域
B. 当Eden空间足够时,内存申请结束。否则到下一步
C. JVM试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收), 释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区
D. Survivor区被用来作为Eden及OLD的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区
E. 当OLD区空间不够时,JVM会在OLD区进行完全的垃圾收集(0级)
F. 完全垃圾收集后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现”out of memory错误”

JVM调优建议:

ms/mx:定义YOUNG+OLD段的总尺寸,ms为JVM启动时YOUNG+OLD的内存大小;mx为最大可占用的YOUNG+OLD内存大小。在用户生产环境上一般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。
NewSize/MaxNewSize:定义YOUNG段的尺寸,NewSize为JVM启动时YOUNG的内存大小;MaxNewSize为最大可占用的YOUNG内存大小。在用户生产环境上一般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。
PermSize/MaxPermSize:定义Perm段的尺寸,PermSize为JVM启动时Perm的内存大小;MaxPermSize为最大可占用的Perm内存大小。在用户生产环境上一般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。
SurvivorRatio:设置Survivor空间和Eden空间的比例

内存溢出的可能性

1. OLD段溢出
这种内存溢出是最常见的情况之一,产生的原因可能是:
1) 设置的内存参数过小(ms/mx, NewSize/MaxNewSize)
2) 程序问题
单个程序持续进行消耗内存的处理,如循环几千次的字符串处理,对字符串处理应建议使用StringBuffer。此时不会报内存溢出错,却会使系统持续垃圾收集,无法处理其它请求,相关问题程序可通过Thread Dump获取(见系统问题诊断一章)单个程序所申请内存过大,有的程序会申请几十乃至几百兆内存,此时JVM也会因无法申请到资源而出现内存溢出,对此首先要找到相关功能,然后交予程序员修改,要找到相关程序,必须在Apache日志中寻找。
当Java对象使用完毕后,其所引用的对象却没有销毁,使得JVM认为他还是活跃的对象而不进行回收,这样累计占用了大量内存而无法释放。由于目前市面上还没有对系统影响小的内存分析工具,故此时只能和程序员一起定位。

2. Perm段溢出
通常由于Perm段装载了大量的Servlet类而导致溢出,目前的解决办法:
1) 将PermSize扩大,一般256M能够满足要求
2) 若别无选择,则只能将servlet的路径加到CLASSPATH中,但一般不建议这么处理

3. C Heap溢出
系统对C Heap没有限制,故C Heap发生问题时,Java进程所占内存会持续增长,直到占用所有可用系统内存

其他:

JVM有2个GC线程。第一个线程负责回收Heap的Young区。第二个线程在Heap不足时,遍历Heap,将Young 区升级为Older区。Older区的大小等于-Xmx减去-Xmn,不能将-Xms的值设的过大,因为第二个线程被迫运行会降低JVM的性能。
为什么一些程序频繁发生GC?有如下原因:
l 程序内调用了System.gc()或Runtime.gc()。
l 一些中间件软件调用自己的GC方法,此时需要设置参数禁止这些GC。
l Java的Heap太小,一般默认的Heap值都很小。
l 频繁实例化对象,Release对象。此时尽量保存并重用对象,例如使用StringBuffer()和String()。
如果你发现每次GC后,Heap的剩余空间会是总空间的50%,这表示你的Heap处于健康状态。许多Server端的Java程序每次GC后最好能有65%的剩余空间。

经验之谈:
1.Server端JVM最好将-Xms和-Xmx设为相同值。为了优化GC,最好让-Xmn值约等于-Xmx的1/3[2]。
2.一个GUI程序最好是每10到20秒间运行一次GC,每次在半秒之内完成[2]。

注意:
1.增加Heap的大小虽然会降低GC的频率,但也增加了每次GC的时间。并且GC运行时,所有的用户线程将暂停,也就是GC期间,Java应用程序不做任何工作。
2.Heap大小并不决定进程的内存使用量。进程的内存使用量要大于-Xmx定义的值,因为Java为其他任务分配内存,例如每个线程的Stack等。
2.Stack的设定
每个线程都有他自己的Stack。

-Xss

每个线程的Stack大小
Stack的大小限制着线程的数量。如果Stack过大就好导致内存溢漏。-Xss参数决定Stack大小,例如-Xss1024K。如果Stack太小,也会导致Stack溢漏。
3.硬件环境
硬件环境也影响GC的效率,例如机器的种类,内存,swap空间,和CPU的数量。
如果你的程序需要频繁创建很多transient对象,会导致JVM频繁GC。这种情况你可以增加机器的内存,来减少Swap空间的使用[2]。
4.4种GC
第一种为单线程GC,也是默认的GC。,该GC适用于单CPU机器。
第二种为Throughput GC,是多线程的GC,适用于多CPU,使用大量线程的程序。第二种GC与第一种GC相似,不同在于GC在收集Young区是多线程的,但在Old区和第一种一样,仍然采用单线程。-XX:+UseParallelGC参数启动该GC。
第三种为Concurrent Low Pause GC,类似于第一种,适用于多CPU,并要求缩短因GC造成程序停滞的时间。这种GC可以在Old区的回收同时,运行应用程序。-XX:+UseConcMarkSweepGC参数启动该GC。
第四种为Incremental Low Pause GC,适用于要求缩短因GC造成程序停滞的时间。这种GC可以在Young区回收的同时,回收一部分Old区对象。-Xincgc参数启动该GC。

今日提示

1.把一件事做到极致,不可当做任务。
2.对老板永远要敬畏,轻易不要表达出自己的想法,沟通的时候要在关键的时刻凸显自己的智慧。答辩的时候低调,针对任何羞辱和刁难均谦虚表示接受,表明自己没有考虑周全。
3.做事要专注,戒网络,戒浮躁,耐心,在任何时候都要想坚持,自己做的还不够,记住要想比别人卓越的就是要前进一步。
4.虽然ppt是最赚钱的工具,vs、eclipse等还是属于自己应该掌握的工具,PPT做到最好,在工作之余补充人文等知识,注意自己的思考方式和表达方式。
5.结果导向,老板关注的是结果,要预先想到老板所没有想到的,态度和方法永远是最重要的,还有自己的执行力,自己的提高与否则是自己的事情了,再合适的时候做出合适的选择。

星期日, 四月 12, 2009

机器学习领域重要链接

C/C++ Programming
C++ TutoralThe cplusplus.com TutorialC++ StringIntroduction to Object-Oriented Programming Using C++DJGPPStandard Templale LibraryMakefile Tutorial
Machine Learning Softwares
SVM Light - Support Vector Machine in C Source CodeLIBSVM - A C++ Library for SMO Support Vector Machines (Recommend)CVM Toolbox - A C++ Implementation of Core Vector Machines (Recommend for Massive Data-sets)UniverSVM - Transductive and sparse SVMs in C++SVM in the Primal - Direct Primal SVM SolverSVM-QP - Active Set QP solver for Large Scale SVM in Fortran 77Torch3 - Machine Learning Package in C++LASVM - Online SVM ImplementationMATLAB Support Vector Machine Toolbox SimpleSVM Toolbox - Invariant SVM ImplementationStatlearn Toolbox Weka 3 - Machine Learning Software in Java (Including SVM package)Bow - A Toolkit for Text Retrieval, Classification and ClusteringSeDuMi - A MATLAB Package for Semi-Definite Programming SDPT3 - A MATLAB Package for Semi-Definite-Quadratic-Linear programmingOther Geometric Programming SoftwaresMosek - An Optimization Software Statistical Pattern Recognition Toolbox for MatlabNetlab - A Matlab Neural Network SoftwareDecision Tree - C4.5/C5.0Cover Tree - Fast Nearest Neighbor Search GSL - GNU Scientific Library Numerical Recipes in C Other Software Packages for Kernel Machines
Machine Learning Journals
Journal of Machine Learning ResearchMachine LearningIEEE Transactions on Neural Networks Neural ComputationNeural NetworksNeurocomputingJournal of the American Statistical AssociationAnnals of Statistics Data Mining and Knowledge Discovery IEEE Transactions on Knowledge and Data Engineering IEEE Transactions on Pattern Analysis and Machine Intelligence Pattern Recognition
Machine Learning Benchmark Datasets
UCI Machine Learning Repository UCI Knowledge Discovery in Databases ArchiveText DatasetsDatasets for SMODatasets for BoostingReuters-21578 DELVE Lufs Torgo - Regression Data SetsEachMovie collaborative filtering data set Resources for Face Database The USC-SIPI Image DatabaseThe NORB Dataset, V1.0
Useful Courses and Links in Machine Learning
Machine Learning Summer School 2005 at ANU Machinel Learning Theory ForumInternational Machinel Learning SocietyMachinel Learning Conference InformationStatistical Learning Theory and Applications at MITFoundations of Machine Learning at PrincetonConvex Optimization with Engineering Applications at StanfordConic and Robust Optimization at Columbia Templates for the Solution of Algebraic Eigenvalue Problems: a Practical GuideTemplates for the Solution of Linear Systems: Building Blocks for Iterative MethodsRandomized AlgorithmsMatrix Reference Manual Mathematical Programming at CornellDistribution Theory and Statistical Inference at UNEVirtual Laboratories in Probability and Statistics Machine Learning, Tom Mitchell, McGraw Hill Message Board on Kernel Machines Learning with Kernels Support Vector Machines, Regularization, Optimization and Beyond

星期六, 四月 11, 2009

程序员每天该做的事

今天学习JS的时候,偶然看到一篇文章,"程序员每天该做的事", 感到自己做的很少很少,希望自己以后的生活会有所改变,有计划、有生机。
程序员每天该做的事


1、总结自己一天任务的完成情况
最好的方式是写工作日志,把自己今天完成了什么事情,遇见了什么问题都记录下来,日后翻看好处多多

2、考虑自己明天应该做的主要工作
把明天要做的事情列出来,并按照优先级排列,第二天应该把自己效率最高的时间分配给最重要的工作

3、考虑自己一天工作中失误的地方,并想出避免下一次再犯的方法
出错不要紧,最重要的是不要重复犯相同的错误,那是愚蠢

4、考虑自己一天工作完成的质量和效率能否还能提高
一天只提高1%,365天你的效率就能提高多少倍你知道吗? (1+0.01)^365 = 37 倍

5、看一个有用的新闻网站或读一张有用的报纸,了解业界动态
闭门造车是不行的,了解一下别人都在做什么,对自己能带来很多启示

6、记住一位同事的名字及其特点
你认识公司的所有同事吗?你了解他们吗?

7、清理自己的代码
今天完成的代码,把中间的调试信息,测试代码清理掉,按照编码风格整理好,注释都写好了吗?

8、清理自己的桌面
当日事当日毕,保持清洁干劲的桌面才能让你工作时不分心,程序员特别要把电脑的桌面清理干净

程序员每周该做的事

1、向你的老板汇报一次工作
让你的老板知道你在做什么,这很重要。可以口头、书面、邮件,看你老板的工作方式而定

2、进行一次自我总结(非正式)
这周之内自己表现得怎么样?该加分还是扣分?

3、制定下周计划
把下周要做的事情列出来,一样要分清楚优先级

4、整理自己的文件夹、书柜和电脑文件
把桌面以外的地方也要清理干净,电脑的文件夹,收到的邮件,把过时的垃圾全部清理掉

5、与一个非公司的朋友沟通
它山之石,可以攻玉

6、看一本杂志
找一本适合自己的专业杂志

7、纠正自己或同事一个细节上的不正确做法
《细节决定成败》看过了吗?没看过强烈建议先看看

程序员每月该做的事

1、至少和一个同事一起吃饭或喝茶
不光了解自己工作伙伴的工作,还要了解他们的生活

2、自我考核一次
相对正式地考核自己一下,你对得起这个月的工资吗?

3、对你的同事考核一次
你的同事表现怎么样?哪些人值得学习,哪些人需要帮助?

3、制定下月的计划,确定下月的工作重点

4、总结自己工作质量改进状况
自己的质量提高了多少?

5、有针对性地对一项工作指标做深入地分析并得出改进的方案
可以是对自己的,也可以是对公司的,一定要深入地分析后拿出自己的观点来。要想在老板面前说得上话,做的成事,工作上功夫要做足。

6、与老板沟通一次
最好是面对面地沟通,好好表现一下自己,虚心听取老板的意见,更重要的是要了解老板当前关心的重点

程序员每年该做的事

1、年终总结
每个公司都会做的事情,但你真正认真地总结过自己吗?

2、兑现给自己、给家人的承诺
给老婆、儿子的新年礼物买了没有?给自己的呢?

3、下年度工作规划
好好想想自己明年的发展目标,争取升职/加薪、跳槽还是自己出来干?

4、掌握一项新技术
至少是一项,作为程序员一年要是一项新技术都学不到手,那就一定会被淘汰。掌握可不是看本书就行的,要真正懂得应用,最好你能够写一篇教程发表到你的blog

5、推出一种新产品
可以是一个真正的产品,也可以只是一个类库,只要是你创造的东西就行,让别人使用它,也为世界作点贡献。当然如果真的很有价值,收点注册费也是应该的

6、与父母团聚一次
常回家看看,常回家看看。

Concept

Classification & Clustering
supervised learning vs unsupervised learning

分类是数据挖掘中的最重要的技术之一。目前实现分类的方法有统计方法、机器学习方法和人工智能方法等,常用的技术有决策树分类、贝叶斯分类、神经网络分类等.通过对当前具有代表性的分类算法原理进行分析、比较,总结出每种算法的性能特征,既便于使用者了解掌握各种分类算法、更好地选择合适的算法,又便于研究者对算法进行研究改进,提出性能更好的分类算法。
聚类方法可以分为:
1) 划分的方法:构造不同的划分,然后用某些方法评估划分情况。
2) 层次的方法:基于某些标准对给定数据对象集合进行层次分解。
3) 基于密度的方法:基于临近区域的密度进行聚类。
4) 基于网格的方法:把对象空间量化为有限数目的单元,形成网格结构进行聚类操作。
5) 基于模型的方法:为每个簇假定一个模型,寻找数据对给定模型的最佳拟合。

classification vs prediction

预测的常用方法是时间序列,回归也可以用来预测。

时间序列常用的方法有:ARMA,指数平滑和趋势外推等。时间序列的最大特点就是充分挖掘事物本身随时间的规律。因为,任何事物,比如企业销售额,在没有特别的外在因素影响下,总是有规可循的。

数据仓库就是面向主题的、集成的、不可更新的(稳定性)、随时间不断变化(不同时间)的数据集合,用以支持经营管理中的决策制定过程。
数据库与数据仓库的主要区别是:
1、数据存储量不同,一般来说数据库相对数据仓库而言数据存储量要小;
2、建模方式与建模方法不同,一般来说传统数据库建模使用实体关系即E_R而数据仓库则一般采用维度与指标即DF方法;
3、应用方式不同,一般来说数据库一般面向联机业务处理即OLTP(online transaction processing),而数据仓库则主要面向联机分析处理即OLAP(Online Analytical Processing)

常用数据中心趋势以及数据离散的度量有哪些?
平均值(mean):是最常用最有效的中心数值度量。包括平均值和加权平均值。

中位数(median):一个整体度量,不是分布度量,也不是代数度量。

模(mode):是集合中出现最多的值。

中列数(midrange):是数列集合的最大值和最小值的平均值。

四分位数(quantile):Q1 (25th percentile), Q3 (75th percentile)

孤立点(outlier): 落在至少高于Q3或者低于Q1的1.5×IQR处的值

五数概括(five-number summary): min,Q1, M, Q3, max ——M为中位数/中值

盒图(variance):端点在四分位数上;盒的长度是IQR;中位数标记为盒内的线;盒外的两条线延伸到最小和最大的观测值

星期三, 四月 08, 2009

AOL Seach query database

500k User Session Collection
----------------------------------------------
This collection is distributed for NON-COMMERCIAL RESEARCH USE ONLY.
Any application of this collection for commercial purposes is STRICTLY PROHIBITED.

Brief description:

This collection consists of ~20M web queries collected from ~650k users over three months.
The data is sorted by anonymous user ID and sequentially arranged.

The goal of this collection is to provide real query log data that is based on real users. It could be used for personalization, query reformulation or other types of search research.

The data set includes {AnonID, Query, QueryTime, ItemRank, ClickURL}.
AnonID - an anonymous user ID number.
Query - the query issued by the user, case shifted with
most punctuation removed.
QueryTime - the time at which the query was submitted for search.
ItemRank - if the user clicked on a search result, the rank of the
item on which they clicked is listed.
ClickURL - if the user clicked on a search result, the domain portion of
the URL in the clicked result is listed.

Each line in the data represents one of two types of events:
1. A query that was NOT followed by the user clicking on a result item.
2. A click through on an item in the result list returned from a query.
In the first case (query only) there is data in only the first three columns/fields -- namely AnonID, Query, and QueryTime (see above).
In the second case (click through), there is data in all five columns. For click through events, the query that preceded the click through is included. Note that if a user clicked on more than one result in the list returned from a single query, there will be TWO lines in the data to represent the two events. Also note that if the user requested the next "page" or results for some query, this appears as a subsequent identical query with a later time stamp.

CAVEAT EMPTOR -- SEXUALLY EXPLICIT DATA! Please be aware that these queries are not filtered to remove any content. Pornography is prevalent on the Web and unfiltered search engine logs contain queries by users who are looking for pornographic material. There are queries in this collection that use SEXUALLY EXPLICIT LANGUAGE. This collection of data is intended for use by mature adults who are not easily offended by the use of pornographic search terms. If you are offended by sexually explicit language you should not read through this data. Also be aware that in some states it may be illegal to expose a minor to this data. Please understand that the data represents REAL WORLD USERS, un-edited and randomly sampled, and that AOL is not the author of this data.

Basic Collection Statistics
Dates:
01 March, 2006 - 31 May, 2006

Normalized queries:
36,389,567 lines of data
21,011,340 instances of new queries (w/ or w/o click-through)
7,887,022 requests for "next page" of results
19,442,629 user click-through events
16,946,938 queries w/o user click-through
10,154,742 unique (normalized) queries
657,426 unique user ID's


Please reference the following publication when using this collection:

G. Pass, A. Chowdhury, C. Torgeson, "A Picture of Search" The First
International Conference on Scalable Information Systems, Hong Kong, June,
2006.



You can download it from here:AOL-data.tgz.



According to Adam D’Angelo, the reason AOL published the data was for recognition in the search-engine research arena:

This was not a leak - it was intentional. In their desperation to gain recognition from the research community, AOL decided they would compromise their integrity to provide a data set that might become often-cited in research papers: “Please reference the following publication when using this collection: G. Pass, A. Chowdhury, C. Torgeson, ‘A Picture of Search’ The First International Conference on Scalable Information Systems, Hong Kong, June, 2006.” is the message before the download.

Here’s a breakdown of the core facts:

* 20,000,000 queries from 650,000 users in 2GB uncompressed tab-delimited files
* Uncensored queries for three months of AOL search service, spring 2006
* Essentially public domain
* Contains dangerous private information

Update

The data is rife with all kinds of personally identifiable data. For example, a quick grep for credit-card patterns produces the following:

grep -i -e “[0-9]\{4\}-[0-9]\{4\}-[0-9]\{4\}-[0-9]\{4\}” *.txt

* 9006-0512-xxxx-xxx
* 1550-0905-xxxx-xxxx

Looking for Social Security Numbers (SSN) turns up this HUGE amount of data:

grep -i -e “\b[0-9]\{3\}-[0-9]\{2\}-[0-9]\{4\}\b” *.txt

* kristy nicole vega hammond la. social secruity number 437-67-xxxx birth date 03 08 xx drivers license number la. 00765xxxx address 41178 rene dr. hammond la.
* pamela button 079-60-xxxx
* thomas j finney socsec 370-40-xxxx
* 419-94-xxxx thomas black
* 458-87-xxxx seguro social
* social security number 545-29-xxxx
* ssn 436-47-xxxx

I’ve censored the personal information, but there are about 200 entries of social security numbers in the test data. Searching for things that look email addresses ([a-zA-Z0-9_\-]*@[a-zA-Z0-9_\-]*\.) turns up another 60 or so.

Update 2:

If you want to get this data into a more usable form, say MySQL, try this (note that we’re not going to bother storing duplicate queries, but you might want to):

mysql> CREATE TABLE aoldata (anonid int unsigned not null, query varchar(255), querytime datetime, itemrank int unsigned, clickurl varchar(255), PRIMARY KEY(anonid, query))

Then you just need to import it, as appropriate:

LOAD DATA LOCAL INFILE ‘user-ct-test-collection-01.txt’
INTO TABLE aoldata
FIELDS TERMINATED BY ‘\t’
LINES TERMINATED BY ‘\n’
(anonid, query, querytime, itemrank, clickurl);

Other Blogs

Paul notes that the AOL data is really Google data, since AOL search is rebranded Google. Zoli has the post that started it all.

星期四, 四月 02, 2009

Database Index

http://en.wikipedia.org/wiki/Index_(database)

用分治法实现元素选择

要求复杂度在O(n)

kua方法:
使用分治策略,类似与快速排序的方法,先对数组分组,然后判断第k小的元素应该在哪个分组
然后递归该分组,最后求的第k小的元素

/*
使用分段的思想求第k小的数(减治法)
如:第1小的数是最小的数

思想:对于一个数组a[0...n-1],分段成a[0...s-1],a[s],a[s+1...n-1]
分组后,a[0...s-1]里面的元素都小于等于a[s];
a[s+1...n-1]里面的元素都大于等于a[s];
所以,如果 s==k-1,那么a[s]就是要求的数;
如果 s > k-1,那么要求的数在a[0...s-1]里;
如果 s < k-1,那么要求的数在a[s+1...n-1]里;
因此,我们把范围缩小到 a[0...s-1]或者a[s+1...n-1]里;
对缩小后的数组也做同样的操作;

通常情况下,这个比快速排序要高效:
因为快速排序要同时处理被分割的2段,
而此方法只需要处理一段;
*/

实现:


//求数组中最小的第K的元素,要求时间复杂度O(n)
//原理类似与quicksort,都是分治
//不同在与,minK只需要对其中一个分组进行递归

//该方法最坏复杂度为O(n^2),但是平均复杂度有O(n)
//复杂度取决于基准值的选择,可以使用随机选择基准值
public static int minK(int[] array, int low, int high, int k)
{
if( low == high )
return array[low];
int pivotPos = partition(array, low, high);
int j = pivotPos - low + 1;
if( k == j )
return array[pivotPos];
if( k < j )
return minK(array, low, pivotPos - 1, k);
else
return minK(array, pivotPos + 1, high, k - j);
}

Algorithm Index

算法篇

目录
一、搜索算法
1、 深度优先搜索(DFS)
2、 广度优先搜索(BFS)
3、 记忆化搜索——一种类似DP的搜索方法
4、 A*A*启发式搜索及其相应变种
5、 博弈问题
6、 搜索的优化——剪枝
二、基础算法
1、 枚举
2、 几种常见常用的排序算法
3、 贪心(Greedy)
4、 贪心的贪心——动态规划(DP)
(1) 线性规划
(2) 树型动态规划
(3) 状态压缩的动态规划
(4) 动态规划的优化
5、 分而治之——分治法
6、 随机化及其应用
三、图论算法
1、 最小生成树的两种算法(Prim、Kruscal)
2、 求最短路径的算法(Dijkstra、Floyed、Bellman-Ford、SPFA)
3、 求图的强连通分量——洪水灌溉法(FloodFill)
4、 图中环的相关问题
(1) 拓扑排序(TopoSort)
(2) 块及块的收缩
5、 图的割点与桥
6、 凸包(扫描线、Graham-Scan)
7、 利用Bellman-Ford的差分约束系统
四、网络流
1、 Ford-FulkersonFord-Fulkerson及Edmonds-Karp
2、 基于分层思想的算法——Dinic
3、 预流推进及相关算法
4、 特殊的图——二分图
(3) 二分图的最大匹配——超级源点、汇点法及匈牙利法
(4) 二分图的最优匹配——最小费用最大流
(5) 二分图的独立集和支配集
5、最小切割最大流定理
6、最大流的增广路算法——KM算法
五、其他
1、 区间最大最小值问题——RMQ
2、 树的最近公共祖先问题——LCA

分治法的基本思想

任何一个可以用计算机求解的问题所需的计算时间都与其规模有关。问题的规模越小,越容易直接求解,解题所需的计算时间也越少。例如,对于n个元素的排序问题,当n=1时,不需任何计算。n=2时,只要作一次比较即可排好序。n=3时只要作3次比较即可,…。而当n较大时,问题就不那么容易处理了。要想直接解决一个规模较大的问题,有时是相当困难的。
分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。
如果原问题可分割成k个子问题,1<k≤n,且这些子问题都可解,并可利用这些子问题的解求出原问题的解,那么这种分治法就是可行的。由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。分治法的适用条件
分治法所能解决的问题一般具有以下几个特征:
*该问题的规模缩小到一定的程度就可以容易地解决;
*该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
*利用该问题分解出的子问题的解可以合并为该问题的解;
*该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。
上述的第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;第二条特征是应用分治法的前提,它也是大多数问题可以满足的,此特征反映了递归思想的应用;第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑贪心法或动态规划法。第四条特征涉及到分治法的效率,如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。

分治法的基本步骤
分治法在每一层递归上都有三个步骤:
*分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
*解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题;
*合并:将各个子问题的解合并为原问题的解。
它的一般的算法设计模式如下:
Divide-and-Conquer(P)
1. if |P|≤n0
2. return(ADHOC(P))
3. 将P分解为较小的子问题 P[1] ,P[2] ,...,P[k]
4. for (i=1;i<=k;i++)
5. y[i]=Divide-and-Conquer(P[i]) △ 递归解决P[i]
6. T=MERGE(y[1],y[2],...,y[k]) △ 合并子问题
7. return(T)
其中|P|表示问题P的规模;n0为一阈值,表示当问题P的规模不超过n0时,问题已容易直接解出,不必再继续分解。ADHOC(P)是该分治法中的基本子算法,用于直接解小规模的问题P。因此,当P的规模不超过n0时,直接用算法ADHOC(P)求解。算法 MERGE(y[1],y[2],...,y[k])是该分治法中的合并子算法,用于将P的子问题P[1] ,P[2] ,...,P[k]的相应的解y[1],y[2],...,y[k]合并为P的解。
根据分治法的分割原则,原问题应该分为多少个子问题才较适宜?各个子问题的规模应该怎样才为适当?这些问题很难予以肯定的回答。但人们从大量实践中发现,在用分治法设计算法时,最好使子问题的规模大致相同。换句话说,将一个问题分成大小相等的k个子问题的处理方法是行之有效的。许多问题可以取k=2。这种使子问题规模大致相等的做法是出自一种平衡 (balancing)子问题的思想,它几乎总是比子问题规模不等的做法要好。
分治法的合并步骤是算法的关键所在。有些问题的合并方法比较明显;有些问题合并方法比较复杂,或者是有多种合并方案;或者是合并方案不明显。究竟应该怎样合并,没有统一的模式,需要具体问题具体分析。

分治法的复杂性分析
从分治法的一般设计模式可以看出,用它设计出的程序一般是一个递归过程。因此,分治法的计算效率通常可以用递归方程来进行分析。为方便起见,设分解阈值 n0=1,且算法ADHOC解规模为1的问题耗费1个单位时间。又设分治法将规模为n的问题分成k个规模为n/m的子问题去解,而且,将原问题分解为k个子问题以及用算法MERGE将k个子问题的解合并为原问题的解需用f(n)个单位时间。用T(n)表示该分治法Divide-and- Conquer(P)解规模为|P|=n的问题P所需的计算时间。则:
(1)注意,递归方程及其解只能给出n等于m的方幂时T(n)的值,但是如果认为T(n)足够平滑,那么由等于m的方幂时T(n)的值可以估计T(n)的增长速度。通常,我们可以假定T(n)是单调上升的,从而当mi≤n〈 mi+1时,T(mi)≤T(n)〈 T(mi+1)。另一个需要注意的问题是,在分析分治法的计算效率时,通常得到的是递归不等式:
(2)由于我们关心的一般是最坏情况下的计算时间复杂度的上界,所以用等于号(=)还是小于或等于号(≤)是没有本质区别的。

分治法的几种变形
(1)二分法 dichotomy
一种每次将原问题分解为两个子问题的分治法,是一分为二的哲学思想的应用。这种方法很常用,由此法产生了许多经典的算法和数据结构。
(2)分解并在解决之前合并法(典型:快速分类)
一种分治法的变形,其特点是将分解出的子问题在解决之前合并。
(3)管道传输分治法 pipelined divide and conquer
一种分治法的变形,它利用某种称为“管道”的数据结构在递归调用结束前将其中的某些结果返回。此方法经常用来减少算法的深度。
注: divide and marriage before conquest和pipelined divide and conquer 方法并不太了解,只在某些参考文献上看过其名称。其原文定义如下:
Divide And Marriage Before Conquest: A variant of divide and conquer in which subproblems created in the "divide" step are merged before the "conquer" step.
Pipelined Divide And Conquer: A divide and conquer paradigm in which partial results from recursive calls can be used before the calls complete. The technique is often useful for reducing the depth of an algorithm.

动态规划的理论模型[转载]

【摘要】

本文介绍了动态规划的基本思想和基本步骤,通过实例研究了利用动态规划设计算
法的具体途径,讨论了动态规划的一些实现技巧,并将动态规划和其他一些算法作
了比较,最后还简单介绍了动态规划的数学理论基础和当前最新的研究成果。

(说明:这是我中学时候写的一篇小论文,因为公式和图比较多,
为了能在bbs上贴出来做了不少删节)


【目录】
一.引言
二.动态规划的基本思想
三.动态规划算法的基本步骤
四.动态规划的适用条件
五.动态规划的实例分析
六.动态规划的技巧——阶段的划分和状态的表示
七.动态规划实现中的问题
八.动态规划与其他算法的比较
九.动态规划的理论模型


一。引言

动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision
process)最优化的数学方法。20世纪50年代初美国数学家R.E.Bellman等人在研究
多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优
化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,逐
个求解,创立了解决这类过程优化问题的新方法——动态规划。1957年出版了他的
名著Dynamic Programming,这是该领域的第一本著作。

动态规划问世以来,在经济管理、生产调度、工程技术和最优控制等方面得到了广
泛的应用。例如最短路线、库存管理、资源分配、设备更新、排序、装载等问题,
用动态规划方法比用其它方法求解更为方便。

虽然动态规划主要用于求解以时间划分阶段的动态过程的优化问题,但是一些与时
间无关的静态规划(如线性规划、非线性规划),只要人为地引进时间因素,把它视
为多阶段决策过程,也可以用动态规划方法方便地求解。

二。动态规划的基本思想

一般来说,只要问题可以划分成规模更小的子问题,并且原问题的最优解中包含了
子问题的最优解(即满足最优子化原理),则可以考虑用动态规划解决。

动态规划的实质是分治思想和解决冗余,因此,动态规划是一种将问题实例分解为
更小的、相似的子问题,并存储子问题的解而避免计算重复的子问题,以解决最优
化问题的算法策略。

由此可知,动态规划法与分治法和贪心法类似,它们都是将问题实例归纳为更小的
、相似的子问题,并通过求解子问题产生一个全局最优解。其中贪心法的当前选择
可能要依赖已经作出的所有选择,但不依赖于有待于做出的选择和子问题。因此贪
心法自顶向下,一步一步地作出贪心选择;而分治法中的各个子问题是独立的 (即
不包含公共的子子问题),因此一旦递归地求出各子问题的解后,便可自下而上地
将子问题的解合并成问题的解。但不足的是,如果当前选择可能要依赖子问题的解
时,则难以通过局部的贪心策略达到全局最优解;如果各子问题是不独立的,则分
治法要做许多不必要的工作,重复地解公共的子问题。

解决上述问题的办法是利用动态规划。该方法主要应用于最优化问题,这类问题会
有多种可能的解,每个解都有一个值,而动态规划找出其中最优(最大或最小)值的
解。若存在若干个取最优值的解的话,它只取其中的一个。在求解过程中,该方法
也是通过求解局部子问题的解达到全局最优解,但与分治法和贪心法不同的是,动
态规划允许这些子问题不独立,(亦即各子问题可包含公共的子子问题)也允许其通
过自身子问题的解作出选择,该方法对每一个子问题只解一次,并将结果保存起来
,避免每次碰到时都要重复计算。

因此,动态规划法所针对的问题有一个显著的特征,即它所对应的子问题树中的子
问题呈现大量的重复。动态规划法的关键就在于,对于重复出现的子问题,只在第
一次遇到时加以求解,并把答案保存起来,让以后再遇到时直接引用,不必重新求
解。

三。动态规划算法的基本步骤

设计一个标准的动态规划算法,通常可按以下几个步骤进行:

1。划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。注意这若干
个阶段一定要是有序的或者是可排序的(即无后向性),否则问题就无法用动态规
划求解。
2。选择状态:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示
出来。当然,状态的选择要满足无后效性。
确定决策并写出状态转移方程:之所以把这两步放在一起,是因为决策和状态转移
有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。
所以,如果我们确定了决策,状态转移方程也就写出来了。但事实上,我们常常是
反过来做,根据相邻两段的各状态之间的关系来确定决策。
3。写出规划方程(包括边界条件):动态规划的基本方程是规划方程的通用形式
化表达式。一般说来,只要阶段、状态、决策和状态转移确定了,这一步还是比较
简单的。

动态规划的主要难点在于理论上的设计,一旦设计完成,实现部分就会非常简单。
根据动态规划的基本方程可以直接递归计算最优值,但是一般将其改为递推计算,
实现的大体上的框架如下:

标准动态规划的基本框架

对fn+1(xn+1)初始化; △ 处理边界条件
for k ← n downto 1 do
for 每一个xk∈Xk do
for 每一个uk∈Uk(xk)
do fk(xk) ← 一个极值 △ ∞或-∞
xk+1 ← Tk(xk,uk) △ 状态转移方程
t ← φ(fk+1(xk+1), vk(xk,uk)) △ 基本方程(9)式
if t比fk(xk)更优
then fk(xk) ← t △ 计算fk(xk)的最优值

t ← 一个极值 △ ∞或-∞
for 每一个x1∈X1
do if f1(x1)比t更优
then t ← f1(x1) △ 按照10式求出最优指标


输出t;


但是,实际应用当中经常不显式地按照上面步骤设计动态规划,而是按以下几个步
骤进行:

1。分析最优解的性质,并刻划其结构特征。
2。递归地定义最优值。
3。以自底向上的方式或自顶向下的记忆化方法(备忘录法)计算出最优值。
4。根据计算最优值时得到的信息,构造一个最优解。

步骤(1)--(3)是动态规划算法的基本步骤。在只需要求出最优值的情形,步骤(4)
可以省略,若需要求出问题的一个最优解,则必须执行步骤(4)。此时,在步骤
(3)中计算最优值时,通常需记录更多的信息,以便在步骤(4)中,根据所记录的信
息,快速地构造出一个最优解。

四。动态规划的适用条件

任何思想方法都有一定的局限性,超出了特定条件,它就失去了作用。同样,动态
规划也并不是万能的。适用动态规划的问题必须满足最优化原理和无后效性。

1.最优化原理(最优子结构性质)
最优化原理可这样阐述:一个最优化策略具有这样的性质,不论过去状态和决策如
何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略。简而言之
,一个最优化策略的子策略总是最优的。一个问题满足最优化原理又称其具有最优
子结构性质。

例如图2中,若路线I和J是A到C的最优路径,则根据最优化原理,路线J必是从B到
C的最优路线。这可用反证法证明:假设有另一路径J'是B到C的最优路径,则A到C
的路线取I和J'比I和J更优,矛盾。从而证明J'必是B到C的最优路径。

最优化原理是动态规划的基础,任何问题,如果失去了最优化原理的支持,就不可
能用动态规划方法计算。动态规划的最优化理在其指标函数的可分离性和单调性中
得到体现。根据最优化原理导出的动态规划基本方程是解决一切动态规划问题的基
本方法。

2.无后向性

将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的
状态无法直接影响它未来的决策,而只能通过当前的这个状态。换句话说,每个状
态都是过去历史的一个完整总结。这就是无后向性,又称为无后效性。

有些问题乍一看好像有后向性,但如果按照某种合理的方式重新划分阶段,就可以
发现其本质上是无后向性的,所以关键是阶段的合理划分,这一点将在动态规划的
技巧中详细阐述。

3.子问题的重叠性

动态规划可以将原来具有指数级复杂度的搜索算法改进成具有多项式时间的算法。
其中的关键在于解决冗余,这是动态规划算法的根本目的。动态规划实质上是一种
以空间换时间的技术,它在实现的过程中,不得不存储产生过程中的各种状态,所
以它的空间复杂度要大于其它的算法。以Bitonic旅行路线问题为例,这个问题也
可以用搜索算法来解决。动态规划的时间复杂度为O(n^2),搜索算法的时间复杂度
为O(n!) ,但从空间复杂度来看,动态规划算法为O(n^2),而搜索算法为O(n),搜
索算法反而优于动态规划算法。选择动态规划算法是因为动态规划算法在空间上可
以承受,而搜索算法在时间上却无法承受,所以我们舍空间而取时间。

设原问题的规模为n,容易看出,当子问题树中的子问题总数是n的超多项式函数,
而不同的子问题数只是n的多项式函数时,动态规划法显得特别有意义,此时动态
规划法具有线性时间复杂性。所以,能够用动态规划解决的问题还有一个显著特征
:子问题的重叠性。这个性质并不是动态规划适用的必要条件,但是如果该性质无
法满足,动态规划算法同其他算法相比就不具备优势。

五。动态规划的实例分析

(因为图较多,略)

六。动态规划的技巧——阶段的划分和状态的表示

在动态规划的设计过程中,阶段的划分和状态的表示是非常重要的两步,这两步会
直接影响该问题的计算复杂性,有时候阶段划分或状态表示的不合理还会使得动态
规划法不适用。

(下面的几个例子图较多,这里从略)

有很多的多阶段决策问题都有着不止一种的阶段划分方法,因而往往就有不止一种
的规划方法。有时各种方法所产生的效果是差不多的,但更多的时候,就像我们的
例子一样,两种方法会在某个方面有些区别。所以,在用动态规划解题的时候,可
以多想一想是否有其它的解法。对于不同的解法,要注意比较,好的算法好在哪里
,差一点的算法差在哪里。从各种不同算法的比较中,我们可以更深刻地领会动态
规划的构思技巧。

七.动态规划实现中的问题

应用动态规划解决问题,在有了基本的思路之后,一般来说,算法实现是比较好考
虑的。但有时也会遇到一些问题,而使算法难以实现。动态规划思想设计的算法从
整体上来看基本都是按照得出的递推关系式进行递推,这种递推相对于计算机来说
,只要设计得当,效率往往是比较高的,这样在时间上溢出的可能性不大,而相反
地,动态规划需要很大的空间以存储中间产生的结果,这样可以使包含同一个子问
题的所有问题共用一个子问题解,从而体现动态规划的优越性,但这是以牺牲空间
为代价的,为了有效地访问已有结果,数据也不易压缩存储,因而空间矛盾是比较
突出的。另一方面,动态规划的高时效性往往要通过大的测试数据体现出来(以与
搜索作比较),因而,对于大规模的问题如何在基本不影响运行速度的条件下,解
决空间溢出的问题,是动态规划解决问题时一个普遍会遇到的问题。

对于这个问题,可以考虑从以下一些方面去尝试:

一个思考方向是尽可能少占用空间。如从结点的数据结构上考虑,仅仅存储必不可
少的内容,以及数据存储范围上精打细算(按位存储、压缩存储等)。当然这要因问
题而异,进行分析。另外,在实现动态规划时,一个我们经常采用的方法是用一个
与结点数一样多的数组来存储每一步的决策,这对于倒推求得一种实现最优解的方
法是十分方便的,而且处理速度也有一些提高。但是在内存空间紧张的情况下,我
们就应该抓住问题的主要矛盾。省去这个存储决策的数组,而改成在从最优解逐级
倒推时,再计算一次,选择某个可能达到这个值的上一阶段的状态,直到推出结果
为止。这样做,在程序编写上比上一种做法稍微多花一点时间,运行的时效也可能
会有一些(但往往很小)的下降,但却换来了很多的空间。因而这种思想在处理某些
问题时,是很有意义的。

但有时,即使采用这样的方法也会发现空间溢出的问题。这时就要分析,这些保留
下来的数据是否有必要同时存在于内存之中。因为有很多问题,动态规划递推在处
理后面的内容时,前面比较远处的内容实际上是用不着的。对于这类问题,在已经
确信不会再被使用的数据上覆盖数据,从而使空间得以重复利用,如果能有效地使
用这一手段,对于相当大规模的问题,空间也不至于溢出(为了求出最优方案,保
留每一步的决策仍是必要的,这同样需要空间)。

一般地说,这种方法可以通过两种思路来实现:一种是递推结果仅使用Data1和
Data2这样两个数组,每次将Data1作为上一阶段,推得Data2数组,然后,将
Data2通过复制覆盖到Data1之上,如此反复,即可推得最终结果。这种做法有一个
局限性,就是对于递推与前面若干阶段相关的问题,这种做法就比较麻烦;而且,
每递推一级,就需要复制很多的内容,与前面多个阶段相关的问题影响更大。另外
一种实现方法是,对于一个可能与前N个阶段相关的问题,建立数组Data[0..N],
其中各项为最近N各阶段的保存数据。这样不采用这种内存节约方式时对于阶段k的
访问只要对应成对数组Data中下标为k mod (N+1)的单元的访问就可以了。这种处
理方法对于程序修改的代码很少,速度几乎不受影响,而且需要保留不同的阶段数
也都能很容易实现。

当采用以上方法仍无法解决内存问题时,也可以采用对内存的动态申请来使绝大多
数情况能有效出解。而且,使用动态内存还有一点好处,就是在重复使用内存而进
行交换时,可以只对指针进行交换,而不复制数据,这在实践中也是十分有效的。

八.动态规划与其他算法的比较

动态规划与其说是一种算法,不如说是一种算法设计的策略,他的基本思想体现于
许多其它算法之中。下面我们通过比较动态规划和其他的一些算法之间的相互联系
,来深入理解动态规划的基本思想。

1.动态规划与静态规划——某些情况下可以相互转化
2.动态规划与递推——动态规划是最优化算法
3.动态规划与搜索——动态规划是高效率、高消费算法
4.动态规划与网络流——动态规划是易设计易实现算法

九.动态规划的理论模型

在动态规划算法发展的初期,Bellman从纯粹的逻辑出发给出了最优性原理
--Principle of Optimality:

"An optimal policy has the property that whatever the initial state
and initial decision are, then remaining decisions must constitute an
optimal policy with regard to the state resulting from first decision.
"

他给出这个原理作为动态规划适用的条件,后来Morin在1982年证明了这只是一个
充分条件而非必要条件。

动态规划开始只是应用于多阶段决策性问题,后来渐渐被发展为解决离散最优化问
题的有效手段,进一步应用于一些连续性问题上。然而,动态规划更像是一种思想
而非算法,它没有固定的数学模型,没有固定的实现方法,其正确性也缺乏严格的
理论证明。因此,一直以来动态规划的数学理论模型是一个研究的热点。

目前比较流行的主要有两种理论模型:关系计算模型(relational calculus
model)和估价网络模型(valuation network model)。

关于这两种流行理论,感兴趣的朋友可以参看以下论文:

关系计算模型:
Sharon Curtis , Dynamic Programming: a different perspective

估价网络模型:
Prakash P. Shenoy, AXIOMS FOR DYNAMIC PROGRAMMING


【参考文献】

[1]Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford
Stein, Introduction to algorithms, Second Edition, The MIT Press, 2001
[2]傅清祥, 王晓东, 算法与数据结构,电子工业出版社,1998
[3]现代应用数学手册——运筹学与最优化理论卷,清华大学出版社,1998
[4]张莹, 运筹学基础,清华大学出版社,1995
[5]Paul E. Black, Dictionary of Algorithms, Data Structures, and
Problems ,http://hissa.nist.gov/dads/, 下载该网站的镜像(1,682KB)
[6]方奇, 动态规划, 中国NOI国家集训队论文集
[7]来煜坤, 把握本质,灵活运用——动态规划的深入探讨 ,中国NOI国家集训队
论文集
[8]李刚, 动态规划的深入讨论 ,中国NOI国家集训队论文集
[9]张辰, 动态规划的特点及其应用 ,中国NOI国家集训队论文集
[10]Prakash P. Shenoy ,AXIOMS FOR DYNAMIC PROGRAMMING , 1996
[11]Sharon Curtis, Dynamic Programming: a different perspective