声明:作者是初级学习者如果算法实现错误,或者编程不规范请各位指正,在这谢谢大家了。
一、TF :定义为词频,一篇文章中某个词出现的次数,这个次数一般会进行归一化(分子小于分母)(因为如果单纯的运用这个次数,篇幅长的文章会比篇幅短的次数多)。
二、IDF : 逆向文件频率。词语普遍重要性的度量。用语料库或数据集中的文件的总数除以某个词在语料库或数据集中在多少文件出现的次数,再将得到的商取对数。在总的文件数一定的时候如果在文件中某词出现的次数越少就可以得到大的IDF。
三、IDF 优点:可以去除常见的词。
缺点:实际上在同一类文章中某个词条正好出现的多但是IDF会小,这就是IDF的缺点。
四、TF-IDF 结合的目的:这样可以找到重要的词(可以代表这个文章的词),而不是常见的词(比较在各个文章中用的词)。
五、具体的思想:TF-IDF 最终的计算是 tf*idf代表某个词条在文章中的权重。
Python去停止词保存到test_temp.txt中
主函数:
# -*- coding: utf-8 -*-
from function import *
#print_t()
data = [] #use to save file data
stop_dict = [] #to save stopwords
data = get_data('test.txt')
stop_dict_temp = get_data('stp.txt') #读入停止词
#对停止词进行去尾操作
stop_dict = []
for line1 in stop_dict_temp:
stop_dict.append(line1.strip())
data_num = len(data) #data save the number
data_final = []
for data_t in data:
if(len(data_t) == 1):
continue
else:
data_final.append(divide_words(data_t))
data_final2 = []
data_temp = []
#文章进行标准化
for artcle in data_final:
for sentence in artcle:
for word in sentence:
if word == '>' or word == ',' or word == '.' or word =='[' or word == ']':
continue
else:
data_temp.append(word.lower())
data_final2.append(data_temp)
data_temp = []
#对文章进行去停止词
data_final3 = []#存放处理后的文件,去除了停止词
print(len(data_final2[0]))
data_final4 = []
for file1 in data_final2:
data_final3.append(del_stp(file1, stop_dict))
for file2 in data_final3:
data_final4.append(del_stp(file2, stop_dict))
print(len(data_final3[0]))
#将去了停止词的文档存储在一个文件中(test_temp.txt)
file_set = open("test_temp.txt", 'w')
for file3 in data_final3:
for word2 in file3:
word2 +=" "
file_set.write(word2)
file_set.write('\n')
#print(data_final3[1])
function.py
# -*- coding: utf-8 -*-
import nltk
#输入文章标准化
def get_data(textname):
data = open(textname).readlines()
return data
#分词
def divide_words(essay):
sens = nltk.sent_tokenize(essay)
words = []
for sent in sens:
words.append(nltk.word_tokenize(sent))
return words
#去停止词
def del_stp(text, stp):
text_temp = text
for word in text_temp:
if word in stp:
text.remove(word)
return text
TF-IDF C++实现代码:
test_temp.txt 是用Python去停止词以后的文件
main.cpp
#include<iostream>
#include <string>
#include<vector>
#include<fstream>
#include"function.h"
using namespacestd;
int main()
{
vector<string> buffer;//buffer存放的是文件里面的每篇文章
string buffer_t;
ifstream file("E:\\1研究生\\研一\\NLP\\code\\stopword\\test_temp.txt");
if (!file.is_open())
{
cout << "没能打开文档";
}
while (!file.eof())
{
getline(file, buffer_t);
buffer.push_back(buffer_t);
}
file.close();
/*
下面的过程是吧文档按照单词存放到vector<vector<string>>data; 中data没一个元素是一篇文章
*/
vector<string> data_temp;
vector<vector<string>>data;
int file_num = buffer.size();//多少篇文章
string word_temp ;
for (int i = 0; i < file_num; i++)
{
int file_size =buffer[i].size();//文章字符数
for (int j = 0; j <file_size; j++)
{
if (buffer[i][j] !=' ')
{
word_temp+= buffer[i][j];
}
else
{
data_temp.push_back(word_temp);
word_temp.clear();
}
}
data.push_back(data_temp);
vector<string>().swap(data_temp);
}
vector<map<string, double>>data_ifidf;
data_ifidf = count_ifidf(data);
int size = 0;
int lenlen = data[5].size();
for (map<string,double>::iterator iter = data_ifidf[5].begin(); iter != data_ifidf[5].end();iter++)
{
size++;
cout << iter->first<< " "<< iter->second << endl;
}
cout << "单词个数"<<size << " "<<lenlen << endl;
system("pause");
return 0;
}
function.c
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<cmath>
using namespacestd;
/*
文档的读入及存放
*/
/*
计算IF-IDF
*/
vector<map<string,double>> count_ifidf(vector<vector<string>> data)
{
//统计每篇文章中单词在文档中出现的次数和在文章中出现的次数然后求其IF-IDF的值
vector<map<string, double>>data_if;
map<string, double> word_file;
double word_data = 0;
double word_file_pro;//在文章中出现的概率
int data_size = data.size();
for (int i = 0; i < data_size; i++)
{
int file_size =data[i].size();
for (int j = 0; j <file_size; j++)
{
//cout <<"——》\n";
double temp =double((count(data[i].begin(), data[i].end(), data[i][j])))/double(data[i].size());//出现错误的地方这个地方是计算精度问题
//cout << temp<< endl;
word_file.insert({data[i][j], temp});//计算某篇文章中某个单词的IF
}
data_if.push_back(word_file);
word_file.clear();
}
//接下来计算IDF
int data_if_size = data_if.size();//文章数
vector<map<string, double>>data_if_temp;
data_if_temp = data_if;
double data_if_temp_size =data_if_temp.size();
for(int m = 0; m < data_if_size;m++)
{
for (map<string,double>::iterator iter = data_if[m].begin(); iter != data_if[m].end();iter++)
{
for (int nn = 0; nn <data_if_temp_size; nn++)
{
if(data_if_temp[nn].find(iter->first) != data_if_temp[nn].end())
{
word_data= word_data + 1.0;
}
}
word_data =log10(data_if_temp_size / word_data);
iter->second *=word_data;
word_data = 0;//这些点出现了好多错误
}
}
return data_if;
}
总结代码:
今天才写完这个代码,整体的布局不是很好,有点乱的结构,本来想整理一下来着不过最近太忙了没整,应该吧这些实现的功能模块化放入函数中。还有打算有了时间再用面向对象去写一下这个算法。
先写一下学到的新函数或新的用法吧。
(1) map 容器的遍历
用到了
Map<T1, T2> exm;
for(map<T1, T2> ::iterator iter = exm.begin(); iter != exm.end ; iter++)
{
函数体;
}
(2) 在map容器中查找某个函数是否存在。Find函数
(二)一些错误
(1)容器中clear() 函数的误用。没有注意到这个函数只是把容器中的内容清除了。但是还是没用释放这部分内存,我在这段程序中调用这个函数的目的主要是进行容器在循环中的重复使用,所以要释放内存。
更改方法:
|
vector <
j= vecInt.capacity();
i = vecInt.size(); |
注释:具体原因学习看链接
(
来自
<
http://www.cppblog.com/lanshengsheng/archive/2013/03/04/198198.html
>
)
(2) 主要是在计算除法的时候没有注意类型的转换和精度,导致了计算成为零。就是这句
Double temp = double((count(data[i].begin(),data[i].end(), data[i][j])))/double( data[i].size());//
出现错误的地方这个地方是计算精度问题