当前位置:  开发笔记 > 编程语言 > 正文

快速文本预处理

如何解决《快速文本预处理》经验,为你挑选了1个好方法。

在我的项目中,我一般都使用文本.我发现预处理可能非常慢.所以我想问你是否知道如何优化我的代码.流程是这样的:

获取HTML页面 - >(以纯文本 - >词干 - >删除停用词) - >进一步文本处理

括号中有预处理步骤.该应用程序运行在大约10.265秒,但预处理需要9.18秒!这是预处理50个HTML页面的时间(不包括下载).

我使用HtmlAgilityPack库将HTML转换为纯文本.这很快.转换1个文档需要2.5ms,所以它相对比较好.

问题出现了.阻止一个文档需要120毫秒.不幸的是,那些HTML页面是波兰语.用C#编写的波兰语不存在词干.我知道只有2个免费使用Java编写:stempel和morfologic.我借助IKVM软件将stempel.jar预编译为stempel.dll.所以没有更多的事要做.

消除停用词也需要很多时间(1个文档约70毫秒).它是这样完成的:

result = Regex.Replace(text.ToLower(), @"(([-]|[.]|[-.]|[0-9])?[0-9]*([.]|[,])*[0-9]+)|(\b\w{1,2}\b)|([^\w])", " ");
while (stopwords.MoveNext())
{
   string stopword = stopwords.Current.ToString();                
   result = Regex.Replace(result, "(\\b"+stopword+"\\b)", " ");                               
}
return result;

首先,我删除所有数字,特殊字符,单词和双字母单词.然后在循环中删除停用词.大概有270个停用词.

有可能让它更快吗?

编辑:

我想要做的是删除所有不超过2个字母的单词.所以我想把所有特殊的字符(包括'.',',','?','!'等)数字,停止字样.我只需要用于数据挖掘的纯语言.



1> LBushkin..:

迭代替换单词将成为您实现中的最大瓶颈.在每次迭代时,您必须扫描整个字符串以获取禁用词,然后替换操作必须分配一个新字符串并使用替换后的文本填充它.那不会很快.

一种更有效的方法是对字符串进行标记化并以流式方式执行替换.将输入划分为由适当的空格或分隔符分隔的单个单词.您可以逐步执行此操作,因此您无需分配任何额外的内存来执行此操作.对于每个单词(标记),您现在可以在停用词的哈希集中执行查找 - 如果找到匹配项,则在将最终文本流式化为单独文本时将替换它StringBuilder.如果令牌不是停用词,只需将其流出StringBuilder未经修改的.此方法应具有O(n)性能,因为它只扫描字符串一次并使用a HashSet来执行禁用字查找.

以下是我期望表现更好的一种方法.虽然它不是完全流式传输(它使用String.Split()分配了一系列附加字符串的数据),但它在一次传递中完成所有处理.优化代码以避免分配额外的字符串可能不会提供太多改进,因为您仍需要提取子字符串以执行与停用词的比较.

下面的代码返回一个排除所有停用词和单词的单词列表,结果是两个字母或更短的字母.它还对停用词使用不区分大小写的比较.

public IEnumerable SplitIntoWords( string input,
                                           IEnumerable stopwords )
{
    // use case-insensitive comparison when matching stopwords
    var comparer = StringComparer.InvariantCultureIgnoreCase;
    var stopwordsSet = new HashSet( stopwords, comparer );
    var splitOn = new char[] { ' ', '\t', '\r' ,'\n' };

    // if your splitting is more complicated, you could use RegEx instead...
    // if this becomes a bottleneck, you could use loop over the string using
    // string.IndexOf() - but you would still need to allocate an extra string
    // to perform comparison, so it's unclear if that would be better or not
    var words = input.Split( splitOn, StringSplitOptions.RemoveEmptyEntries );

    // return all words longer than 2 letters that are not stopwords...
    return words.Where( w => !stopwordsSet.Contains( w ) && w.Length > 2 );
}

推荐阅读
依然-狠幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有