2012-05-22 115 views
-2

我搜索了Google无济于事。这里的任何人都可以告诉我如何在Prolog中对术语频率进行编码?越“逻辑”越好。 给定一个文本文件,忽略非字母数字字符,检测单词,删除停用词(可能在外部文件中给出),计算文件中每个单词的出现次数并输出按照降低频率排序的“word:freq”。在Prolog中计算字词频率

谢谢!

(这不是功课,顺便说一句,这是我做的一个项目)

+0

这是一个SO问题过于宽泛。你试过什么了?你面临什么问题? – mgibsonbr

+0

Prolog不是我选择的语言风格。我正在寻找一位“专家prologer”来向我展示如何用逻辑编程风格来思考这个问题。 –

+0

这个问题是不适合逻辑编程恕我直言。即使在Prolog中实现,它的结构也将与命令式程序非常相似。我建议尝试以最佳方式实现它,然后在[codereview.SE](http://codereview.stackexchange.com/)中提交它以供同行评审,以便人们可以提出更多“逻辑”方法来改进它。 – mgibsonbr

回答

2

这里的东西,让你开始:

它假设的话是每个输入的单独的行文件

无法处理 “停止词”

没有实现那种

; Print the term frequency for words in file Path 
print_freq_from_file(Path) :- 
    open(Path, read, Stream), 
    read_file(Stream, Words), 
    calc_freq(Words, Freq), 
    sort_freq(Freq, SortedFreq), 
    print_freq(SortedFreq). 

; calc_freq(Words,Freq) Freq is the term frequency of the words in list Words 
calc_freq([], []). 
calc_freq([Word|Words], Freq) :- 
    calc_freq(Words, FreqRest), 
    add_word(Word, FreqRest, Freq). 

; add_word(Word, Freq1, Freq2) Freq2 is Freq1 with Word added 
add_word(Word, [], [(Word,1)]). 
add_word(Word, [(Word,N)|Rest], [(Word,N1)|Rest]) :- 
    N1 is N+1. 
add_word(Word, [Term|Rest], [Term|NewRest]) :- 
    add_word(Word, Rest, NewRest). 

; Print the given term frequency 
print_freq([]). 
print_freq([(W,N)|Rest]) :- 
    write(W), write(' : '), write(N), nl, 
    print_freq(Rest). 
+0

谢谢!我假设read_file和read是一样的,是的?在任何情况下,我想看到的这个问题的一个部分就是表示将一行分割为单词的逻辑;也就是表示非字母表过滤的逻辑;以及用于过滤停用词的逻辑,我希望很多内容可以表达为基本事实,例如stop_word(th E)。你是这么做的吗? –

1

对于过滤停止的话,一个好的办法是通过assert

read_sw(Path) :- 
    open(Path, read, Stream), 
    read_words_file(Stream, Words), 
    add_sw(Words). 

add_sw([]). 
add_sw([Word|Rest]) :- 
    assertz(stop_word(Word)), 
    add_sw(Rest). 

一旦做到这一点,你可以用stop_word/1检查一个词是停用词,并忽略它。举例来说,如果你正在实施斯科特·亨特的回答,您可以在calc_freq/2增加一个附加条款,以筛选出那些话:

calc_freq([], []). 
calc_freq([Word|Words], Freq) :- 
    stop_word(Word), !, 
    calc_freq(Words, Freq). 
calc_freq([Word|Words], Freq) :- 
    calc_freq(Words, FreqRest), 
    add_word(Word, FreqRest, Freq). 
2

我用这个答案SWI-Prolog的丰富库支持,因此可能是不合适的案件。

当然,你是如何解决任何编程任务强力地什么在你选择的语言,从你使用它的能力可用的影响。

这里我使用library(assoc),如果你的系统错过了它,那么你可以使用列表模拟,或者使用assert/retract。

这个片段只是显示了一个(惯用)的方式计数单词,计算频率可以很容易地与库(聚合)或一些算术,可能你想尝试记下自己在锻炼语言...

/* File: frequency_of_words.pl 
    Author: Carlo,,, 
    Created: May 23 2012 
    Purpose: http://stackoverflow.com/questions/10711483/calculating-term-frequency-in-prolog 
*/ 

:- module(frequency_of_words, [count_words/2, count_words/1]). 
:- [library(assoc)]. 

count_words(File, Assoc) :- 
    empty_assoc(Empty), 
    open(File, read, Stream), 
    frequency_of_words(Stream, Empty, Assoc, ""), 
    close(Stream). 
count_words(File) :- 
    count_words(File, Assoc), 
    assoc_to_list(Assoc, List), 
    maplist(writeln, List). 

frequency_of_words(Stream, SoFar, Words, CurrWord) :- 
    get_code(Stream, Code), 
    ( Code == -1 
    -> update_dictionary(SoFar, Words, CurrWord) 
    ; use_character(Code, SoFar, Updated, CurrWord, NextWord), 
     frequency_of_words(Stream, Updated, Words, NextWord) 
    ). 

update_dictionary(SoFar, SoFar, Word) :- 
    skip_word(Word). 
update_dictionary(SoFar, Updated, Codes) :- 
    atom_codes(Word, Codes), 
    (get_assoc(Word, SoFar, CountSoFar) ; CountSoFar = 0), 
    WordCount is CountSoFar + 1, 
    put_assoc(Word, SoFar, WordCount, Updated). 

use_character(Code, SoFar, Updated, CurrWord, NextWord) :- 
    ( word_character(Code) 
    -> Updated = SoFar, 
     NextWord = [Code|CurrWord] 
    ; reverse(CurrWord, Forward), 
     update_dictionary(SoFar, Updated, Forward), 
     NextWord = "" 
    ). 

word_character(Code) :- 
    [Code] @>= "A", [Code] @=< "Z" ; 
    [Code] @>= "a", [Code] @=< "z" ; 
    [Code] @>= "0", [Code] @=< "9" ; 
    [Code] == "_". 

skip_word(""). % a trick on EOF or consecutive blanks: not really a skipword 
skip_word("is"). 

测试:

?- count_words('frequency_of_words.pl'). 
0-2 
1-3 
2012-1 
23-1 
9-1 
A-1 
Author-1 
Carlo-1 
Code-14 
Codes-2 
CountSoFar-3 
Created-1 
CurrWord-6 
EOF-1 
Empty-2 
File-3 
Forward-2 
Full-2 
List-2 
May-1 
NextWord-5 
Purpose-1 
SoFar-11 
StackOverflow-1 
Stream-6 
Updated-7 
Word-5 
WordCount-2 
Words-3 
Z-1 
_-1 
a-3 
answer-1 
assoc-1 
assoc_to_list-1 
atom_codes-1 
blanks-1 
close-1 
consecutive-1 
count_words-2 
empty_assoc-1 
frequency_of_words-5 
get_assoc-1 
get_code-1 
library-1 
maplist-1 
module-1 
not-1 
on-1 
open-1 
or-1 
pl-1 
put_assoc-1 
read-1 
really-1 
reverse-1 
skip_word-3 
skipword-1 
trick-1 
update_dictionary-4 
use_character-2 
word_character-2 
writeln-1 
z-1 
+0

谢谢!这涵盖了我正在寻找的许多东西。 –

+0

看了这个更长的时间...这个解决方案使用内联处理方法,即一次读取文件中的一个字符。这是prolog专家如何自然地解决这个问题? (另一种方法是管道和过滤器,首先读取整个文件,然后从整个数据中过滤非字母数字并生成另一条数据,然后检测单词并传递它们,等等。规则的逻辑在序言中更简单或更复杂?) –

+1

我认为这样代码会更复杂,需要更多的步骤。如果你阅读整个文件,那么可以使用DCG,但在这里没有什么可以从中获益的。我使用的技术与用于(非常)简单扫描仪的技术类似。 – CapelliC