qinwf / jiebaR

Chinese text segmentation with R. R语言中文分词 (文档已更新 🎉 :https://qinwenfeng.com/jiebaR/ )

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

關於TF-IDF的演算法

sulaxd opened this issue · comments

請教一下,
tokenEngine <- worker("keywords", idf = "idf.test.txt")
vector_keywords(c("蘋果","蘋果","蘋果","柳丁","柳丁"), tokenEngine)

在我自定義的idf中:
蘋果 0.7595766
柳丁 4.2784980

這邊的詞頻應該要是:
蘋果 0.6
柳丁 0.4

故蘋果與柳丁的 TF-IDF 應該要分別是 0.455746與1.711399,
但程式碼算出的結果看似毫無關聯:
算出的結果卻是:
蘋果 30.4548
柳丁 20.3032

不求精確的演算法,但希望能大概懂您的邏輯或算法,請您賜教。

commented

参考 https://en.wikipedia.org/wiki/Tf%E2%80%93idf

我这里写一下过程吧,具体代码在这里 https://github.com/qinwf/jiebaR/blob/master/inst/include/lib/KeywordExtractor.hpp。

首先,储存 IDF 的数据结构是 unordered_map<string, double> ,是一个类似 R 里面 List 的键值对,string 对应词条,double 对应 IDF 值的值。

void LoadIdfDict(const string& idfPath) 读取 IDF 文件。同时对于计算 idfAverage_ ,在之后的计算中,对于出现的在 IDF 表没有对应的文本,取 idfAverage_。

提取时,读入一组词,使用 map<string, double>, 统计Term frequency,这里选的是 raw frequency, the number of times that term t occurs in document d.

这里在计算词频的时候,对于单字,比如,“我”,“了”,不纳入统计,也就是关键词提取的时候不会提取出单字的关键词。

统计完词频以后,根据停词表,删除停词表里的词。

之后,查询剩余词在 IDF 表中的对应具体数值,对于 IDF 表中没有的词,取 idfAverage_。

TF-IDF

commented

tokenEngine <- worker("keywords", idf = "IDF.txt")
vector_keywords(c("蘋果","蘋果","蘋果","柳丁","柳丁"), tokenEngine)
8.557 2.27873
"柳丁" "蘋果"

commented

我电脑上的运行结果。

可以看看IDF.txt中的柳丁和蘋果的idf嗎?感謝。

commented

看一下你输入的 "idf.test.txt" 文件是不是 UTF-8 编码的。如果不是,读取的时候,可能读的是乱码。

commented

蘋果 0.7595766
柳丁 4.2784980

commented

词频除不除以总词数不影响提取结果,因为对于一次提取,除的是同一个数,如果需要比较不同提取结果,可以自行除以总词数。这个总词数的值,用户是知道的。

okay, 我找到原因了。

剛剛我的IDF.txt長這樣:
"蘋果" 0.7595766
"柳丁" 4.2784980

調整後的get_idf正確用法,如下:
tokenEngineNormal <- worker()
斷詞後文本向量 <- lapply(未斷詞文本向量, function(u)segment(u, tokenEngineNormal))
idf <- get_idf(斷詞後文本向量)
write.table(idf, file="IDF.txt", row.names = F, col.names = F, quote = F)

以上若有更好的方法再請不吝賜教
感謝 @qinwf 耐心解答 :)

commented

get_idf(path = "ss") 设置了以后 path 参数就会写对应文件了。里面写文件用的是

    write.table(df, file = path, sep = " ", row.names = FALSE, 
        col.names = FALSE, quote = FALSE)
  1. IDF= log( 总文件数 / 包含该词的文件数) 这样表述你看看有什么问题吗?

  2. get_idf(a_big_list,stop="停止词列表",path="输出IDF目录")

    输入一个包含多个文本向量的 list,每一个文本向量代表一个文档,可自定义停止词列表。

可以理解为:这里的 list[i] 为第i个文档,list[[i]] 为该文档的所有内容吗?如果我有100个txt文件,就必须先导入然后转为合并为big_list,才能使用get_idf这个函数?

新版能不能加上这样的特性:list可以为文件名列表,像这样的: list.files("./",pattern = "*.txt"),或许能让自定义idf变的简单?

其实转为list也是容易的事情,@qinwf 有时间再回复吧~

commented

可以的,输入一个文件的可以为以行为单位,每行一个词。每个文件读取为一个文本向量,也就是 list[[i]] 的内容。多个文件被读取为一个大 list 。考虑这周添加这一个功能。