我搜索了Google无济于事。这里的任何人都可以告诉我如何在Prolog中对术语频率进行编码?越“逻辑”越好。 给定一个文本文件,忽略非字母数字字符,检测单词,删除停用词(可能在外部文件中给出),计算文件中每个单词的出现次数并输出按照降低频率排序的“word:freq”。在Prolog中计算字词频率
谢谢!
(这不是功课,顺便说一句,这是我做的一个项目)
我搜索了Google无济于事。这里的任何人都可以告诉我如何在Prolog中对术语频率进行编码?越“逻辑”越好。 给定一个文本文件,忽略非字母数字字符,检测单词,删除停用词(可能在外部文件中给出),计算文件中每个单词的出现次数并输出按照降低频率排序的“word:freq”。在Prolog中计算字词频率
谢谢!
(这不是功课,顺便说一句,这是我做的一个项目)
这里的东西,让你开始:
它假设的话是每个输入的单独的行文件
无法处理 “停止词”
没有实现那种
; 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).
谢谢!我假设read_file和read是一样的,是的?在任何情况下,我想看到的这个问题的一个部分就是表示将一行分割为单词的逻辑;也就是表示非字母表过滤的逻辑;以及用于过滤停用词的逻辑,我希望很多内容可以表达为基本事实,例如stop_word(th E)。你是这么做的吗? –
对于过滤停止的话,一个好的办法是通过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).
我用这个答案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
谢谢!这涵盖了我正在寻找的许多东西。 –
看了这个更长的时间...这个解决方案使用内联处理方法,即一次读取文件中的一个字符。这是prolog专家如何自然地解决这个问题? (另一种方法是管道和过滤器,首先读取整个文件,然后从整个数据中过滤非字母数字并生成另一条数据,然后检测单词并传递它们,等等。规则的逻辑在序言中更简单或更复杂?) –
我认为这样代码会更复杂,需要更多的步骤。如果你阅读整个文件,那么可以使用DCG,但在这里没有什么可以从中获益的。我使用的技术与用于(非常)简单扫描仪的技术类似。 – CapelliC
这是一个SO问题过于宽泛。你试过什么了?你面临什么问题? – mgibsonbr
Prolog不是我选择的语言风格。我正在寻找一位“专家prologer”来向我展示如何用逻辑编程风格来思考这个问题。 –
这个问题是不适合逻辑编程恕我直言。即使在Prolog中实现,它的结构也将与命令式程序非常相似。我建议尝试以最佳方式实现它,然后在[codereview.SE](http://codereview.stackexchange.com/)中提交它以供同行评审,以便人们可以提出更多“逻辑”方法来改进它。 – mgibsonbr