初涉自然语言处理(五):平滑处理

这个项目前前后后拖了得有三个月时间吧,中间放寒假完全没管。前一阵开学了,在寝室闲得天昏地暗,索性花几天时间把它弄完。

先上一下效果图:

Powered by Vkki's Spell Checker

话说这个长时间不看代码造成的后果就是自己也不知道自己当初写的是些什么鬼,基本上第一天我都在回忆当初为什么要写成这种鸟样 —— 看不顺眼顺手一改 —— 出错了 —— 看来必须得这么写……

意外的发现 —— Log 时间成本

上篇文章无意中发现了如果把 logger 单独拉一个线程会极大提高运行速度。这篇文章就来测试一下究竟能提速多快。

就简单看从 0 加到 100,000 的时间。

主线程打印
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static Stopwatch watcher;
static int i = 0;
static void Main(string[] args)
{
watcher = new Stopwatch();
watcher.Start();
for (; i < 100000; i++) {
Console.Clear();
Console.WriteLine(i);
}
watcher.Stop();
Console.WriteLine("共花费 {0} 毫秒", watcher.ElapsedMilliseconds);
}

结果:

99999
共花费 13318 毫秒

初涉自然语言处理(四):统计 Bigram

这篇文章之所以拖了这么久是因为我没法解决内存问题,因为随着统计的进行内存占用肯定会越来越高,我在本地测试 300 个文件内存占用已经达到了 500M,而我服务器只有 1G 的空余内存。好在我发现了个逆天的方法能够大幅加快文本处理速度(> 5,000,000 words/s)。

放张内存受虐图:

首先要计算 bigram,肯定得设计一种数据结构来存储它。这里介绍一个叫 Trie 树的结构,其原理就是利用相同字符串的公共部分来节省空间。严格来 Trie 树的一个节点应该只存一个字母,但对于此任务直接存字符串显然是更好的选择。看了网上的实现还是用的 class,而有了上次的教训我还是选择用 KeyValuePair 来实现,这个没什么说的,代码放最后了

这部分的难点主要是逻辑比较复杂,比如遇到了不在字典里的词,指针跳几个,遇到了需要 Fuzzy 的词怎么处理,连续遇到两个又怎么处理,上一个词是大小写敏感还是不敏感……错综缠绕地很不直观,但是细心一点理顺了也没什么难的。我得承认这段我写得太渣。。。

初涉自然语言处理(三):分句

进度有点慢,先放个分句的算法上来吧,光是写这一大堆正则就让我头疼。

先说一下分句的目标,就是把文本分割成最小的句子。这任务听起来简单实际上很麻烦,因为网络上的文本格式参差不齐,有的有标点有的没标点,例如下图:

可以看到第一行的 Preface 是单独一句,但 11 ~ 12 行的 TO MY BEST FRIEND 应该也是一句,他们之间都没有标点,只有换行符。

这里主要用大小写来判断,英语单词的大小写分为3种:Upper CaseLower CaseInitial Caps.