建立文本数据数学描写叙述的过程分为三个步骤:文本预处理、建立向量空间模型和优化文本向量。

文本预处理主要採用分词、停用词过滤等技术将原始的文本字符串转化为词条串或者特点的符号串。文本预处理之后,每个文本的词条串被进一步转换为一个文本向量,向量的每一维相应一个词条,其值反映的是这个词条与这个文本之间的类似度。类似度有非常多不同的计算方法。所以优化文本向量就是採用最为合适的计算方法来规范化文本向量,使其能更好地应用于文本分类和文本聚类等方面。

TFIDF算法

TF-IDF使得一个单词能尽量与文本在语义上相关。TF-IDF算法的实现步骤:



经过试验发现,用TFIDF/max(TFIDF)的方法效果是最好的。详细代码例如以下:

  1. import java.io.File;
  2. import java.util.HashMap;
  3. import java.util.Iterator;
  4. import java.util.Map;
  5. import java.util.Set;
  6. /**
  7. * 经过试验发现,用TFIDF/max(TFIDF)的方法效果是最好的
  8. * @author Angela
  9. */
  10. public class TFIDF {
  11. private Map<String,Integer> TF;//文本词频集
  12. private Map<String,Double> IDF;//特征-逆文档频率集
  13. /**
  14. * 构造方法,初始化TF和IDF
  15. */
  16. public TFIDF(Map<String,Integer> TF,Map<String,Double> IDF){
  17. this.TF=TF;
  18. this.IDF=IDF;
  19. }
  20. /**
  21. * 计算文本特征集的tf-idf权值
  22. * @return filePath文件的特征-TFIDF集
  23. */
  24. public Map<String,Double> getTFIDF(){
  25. Map<String,Double> tfidf=new HashMap<String,Double>();
  26. for(Map.Entry<String,Integer> me: TF.entrySet()){
  27. String f=me.getKey();
  28. double weight=me.getValue()*IDF.get(f);
  29. tfidf.put(f, weight);
  30. }
  31. return tfidf;
  32. }
  33. /**
  34. * 计算文本特征集的对数tf-idf权值
  35. * @return filePath文件的特征-TFIDF集
  36. */
  37. public Map<String,Double> getLogTFIDF(){
  38. Map<String,Double> tfidf=new HashMap<String,Double>();
  39. for(Map.Entry<String,Integer> me: TF.entrySet()){
  40. String f=me.getKey();
  41. double tf=1+Math.log(me.getValue());
  42. double weight=tf*IDF.get(f);
  43. tfidf.put(f, weight);
  44. }
  45. return tfidf;
  46. }
  47. /**
  48. * 进行规一化,每个特征除以这篇文本TFIDF值之和,构成新的TFIDF集
  49. * @return filePath文件的特征-标准化TFIDF集
  50. */
  51. public Map<String,Double> getNormalTFIDF(){
  52. Map<String,Double> tfidf=new HashMap<String,Double>();
  53. Map<String,Double> weight=getTFIDF();
  54. double sum=MathUtil.calSum(weight);//计算TFIDF总和
  55. for(Map.Entry<String, Double> me: weight.entrySet()){
  56. String f=me.getKey();
  57. double w=me.getValue()/sum;
  58. tfidf.put(f, w);
  59. }
  60. return MapUtil.descend(tfidf);
  61. }
  62. /**
  63. * 进行标准化,每个特征除以这篇文本中最大的TFIDF值,构成新的TFIDF集
  64. * @return filePath文件的特征-标准化TFIDF集
  65. */
  66. public Map<String,Double> getStandardTFIDF(){
  67. Map<String,Double> tfidf=new HashMap<String,Double>();
  68. Map<String,Double> weight=getTFIDF();
  69. Map<String,Double> temp=MapUtil.descend(weight);
  70. Set<Map.Entry<String, Double>> set = temp.entrySet();
  71. Iterator<Map.Entry<String,Double>> it = set.iterator();
  72. double max=0;
  73. if(it.hasNext()){
  74. max=it.next().getValue();
  75. }
  76. for(Map.Entry<String, Double> me: weight.entrySet()){
  77. String f=me.getKey();
  78. double w=me.getValue()/max;
  79. tfidf.put(f, w);
  80. }
  81. return MapUtil.descend(tfidf);
  82. }
  83. /**
  84. * 保存文本的TFIDF结果
  85. * @param tf 文本的TF集
  86. * @param idf IDF集
  87. * @param savePath 保存路径
  88. */
  89. public static void saveTFIDF(Map<String,Integer> tf,
  90. Map<String,Double> idf,String savePath){
  91. TFIDF tfidf=new TFIDF(tf,idf);
  92. Map<String,Double> weight=tfidf.getStandardTFIDF();
  93. Writer.saveMap(weight, savePath);
  94. }
  95. /**
  96. * 保存TFIDF结果
  97. * @param filePath 文本集的TF集路径
  98. * @param idfPath IDF路径
  99. * @param tarPath 保存路径
  100. */
  101. public static void saveTFIDF(String TFPath,String IDFPath,String tarPath){
  102. File tar=new File(tarPath);
  103. if(!tar.exists()) tar.mkdir();
  104. Map<String,Double> idf=Reader.toDoubleMap(IDFPath);//IDF
  105. File file=new File(TFPath);
  106. File[] labels=file.listFiles();//类别
  107. for(File label: labels){
  108. String labelpath=tarPath+File.separator+label.getName();
  109. File labelPath=new File(labelpath);
  110. if(!labelPath.exists()) labelPath.mkdir();
  111. File[] texts=label.listFiles();//文本
  112. for(File text: texts){
  113. String savePath=labelpath+File.separator+text.getName();
  114. Map<String,Integer> tf=Reader.toIntMap(text.getAbsolutePath());
  115. saveTFIDF(tf,idf,savePath);
  116. System.out.println("Saved "+savePath);
  117. }
  118. }
  119. }
  120. public static void main(String args[]){
  121. String TFPath="data\\r8trainTF";
  122. String IDFPath="data\\r8trainIDF.txt";
  123. String tarPath="data\\r8trainTFIDF3";
  124. saveTFIDF(TFPath,IDFPath,tarPath);
  125. }
  126. }

向量空间模型VSM

余弦类似度

文本与文本之间的类似度不能简单地用欧式距离来计算。更合理的计算方式是余弦类似度。

以下就是涉及这两个知识点的工具类。

MathUtil存放通用的计算公式方法

  1. import java.util.Map;
  2. /**
  3. *
  4. * @author Angela
  5. */
  6. public class MathUtil {
  7. /**
  8. * 计算Map的键值之和
  9. * @param map
  10. * @return
  11. */
  12. public static double calSum(Map<String,Double> map){
  13. double sum=0;
  14. for(Map.Entry<String,Double> me: map.entrySet()){
  15. sum+=me.getValue();
  16. }
  17. return sum;
  18. }
  19. /**
  20. * 计算两篇文本的类似度
  21. * @param text1 文本1
  22. * @param text2 文本2
  23. * @return text1和text2的余弦类似度。值越大越类似
  24. */
  25. public static double calSim(Map<String,Double> text1,
  26. Map<String,Double> text2){
  27. double sim=0;//类似度
  28. double sum=0;//同样特征的权重相乘之和
  29. double len1=0;//文本1的长度
  30. double len2=0;//文本2的长度
  31. for(Map.Entry<String,Double> me: text1.entrySet()){
  32. String f=me.getKey();
  33. double value=me.getValue();
  34. if(text2.containsKey(f)){
  35. sum+=value*text2.get(f);
  36. }
  37. len1+=value*value;
  38. }
  39. for(Map.Entry<String,Double> me: text2.entrySet()){
  40. double value=me.getValue();
  41. len2+=value*value;
  42. }
  43. sim=sum/(Math.sqrt(len1)*Math.sqrt(len2));
  44. return sim;
  45. }
  46. }

GetData获取DF、TFIDF即VSM、类别成员clusterMember、类别列表LabelList及由TFIDF构造的其他数据

  1. import java.io.File;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.HashSet;
  5. import java.util.List;
  6. import java.util.Map;
  7. import java.util.Set;
  8. /**
  9. *
  10. * @author Angela
  11. */
  12. public class GetData {
  13. /**
  14. * 依据TFIDF得到相应的DF集合
  15. * 假设你的TFIDF集仅仅是原始的一部分,就用这种方法来获取相应的DF集
  16. * @param tfidf TFIDF集合
  17. * @return
  18. */
  19. public static Map<String,Integer> getDF(Map<String,Map<String,Double>> tfidf){
  20. Map<String,Integer> map=new HashMap<String,Integer>();
  21. for(Map.Entry<String,Map<String,Double>> me: tfidf.entrySet()){
  22. Map<String,Double> text=me.getValue();
  23. for(Map.Entry<String,Double> t: text.entrySet()){
  24. String feature=t.getKey();
  25. if(map.containsKey(feature)){
  26. map.put(feature,map.get(feature)+1);
  27. }else{
  28. map.put(feature, 1);
  29. }
  30. }
  31. }
  32. return map;
  33. }
  34. /**
  35. * 读取文本集,返回Map<类别+文件名称,Map<特征,权重>>
  36. * 当你进行特征选择后,得到特征子集,能够用这种方法
  37. * 从文本集中构建新的VSM
  38. * @param filePath TFIDF存放路径
  39. * @param featureSet 特征集
  40. * @return
  41. */
  42. public static Map<String,Map<String,Double>> getTFIDF(String filePath,
  43. Set<String> featureSet){
  44. Map<String,Map<String,Double>> map=new HashMap<String,Map<String,Double>>();
  45. File path=new File(filePath);
  46. File[] files=path.listFiles();//类别
  47. for(File file: files){
  48. String label=file.getName();
  49. File[] texts=file.listFiles();//文本
  50. for(File text: texts){
  51. Map<String,Double> tfidf=Reader.toDoubleMap(text.getAbsolutePath());
  52. Map<String,Double> temp=new HashMap<String,Double>();
  53. for(Map.Entry<String,Double> me: tfidf.entrySet()){
  54. String feature=me.getKey();
  55. if(featureSet.contains(feature)){
  56. temp.put(feature,me.getValue());
  57. }
  58. }
  59. map.put(label+File.separator+text.getName(), temp);
  60. }
  61. }
  62. return map;
  63. }
  64. /**
  65. * 依据特征集构建新的VSM,返回Map<类别+文件名称,Map<特征,权重>>
  66. * 当你进行特征选择后,得到特征子集,能够用这种方法
  67. * 从原始的VSM中构建新的VSM
  68. * @param tfidf 原始的VSM
  69. * @param featureSet 特征集
  70. * @return
  71. */
  72. public static Map<String,Map<String,Double>> getTFIDF(
  73. Map<String,Map<String,Double>> tfidf,Set<String> featureSet){
  74. Map<String,Map<String,Double>> map=new HashMap<String,Map<String,Double>>();
  75. for(Map.Entry<String,Map<String,Double>> me: tfidf.entrySet()){
  76. Map<String,Double> text=me.getValue();
  77. Map<String,Double> temp=new HashMap<String,Double>();
  78. for(Map.Entry<String,Double> t: text.entrySet()){
  79. String feature=t.getKey();
  80. if(featureSet.contains(feature)){
  81. temp.put(feature,t.getValue());
  82. }
  83. }
  84. map.put(me.getKey(), temp);
  85. }
  86. return map;
  87. }
  88. /**
  89. * 依据TFIDF文本集和特征集构建
  90. * Map<特征,Map<文本路径名,特征在该文本中的TFIDF值>>
  91. * @param tfidf TFIDF文本集
  92. * @param featureSet 特征集
  93. * @return
  94. */
  95. public static Map<String,Map<String,Double>> getTermIndex(
  96. Map<String,Map<String,Double>> tfidf,Set<String> featureSet){
  97. Map<String,Map<String,Double>> termIndex=
  98. new HashMap<String,Map<String,Double>>();
  99. for(String f: featureSet){//特征
  100. //包括有特征f的全部文本及特征f在该文本中的权重
  101. Map<String,Double> feature=new HashMap<String,Double>();
  102. for(Map.Entry<String,Map<String,Double>> me: tfidf.entrySet()){
  103. Map<String,Double> text=me.getValue();//文本
  104. if(text.containsKey(f)){//假设文本包括特征f
  105. //将文本的路径和特征f的值赋给feature
  106. feature.put(me.getKey(), text.get(f));
  107. }
  108. }
  109. //将特征及feature赋给termIndex
  110. termIndex.put(f,feature);
  111. }
  112. return termIndex;
  113. }
  114. /**
  115. * 依据文本特征集和特征集构建Map<特征,Set<文本路径名>>
  116. * @param dataSet Map<文本,Set<特征>>
  117. * @param featureSet 特征集
  118. * @return
  119. */
  120. public static Map<String,Set<String>> getFeatureIndex(
  121. Map<String,Set<String>> dataSet,Set<String> featureSet){
  122. Map<String,Set<String>> featureIndex=
  123. new HashMap<String,Set<String>>();
  124. for(String f: featureSet){//特征
  125. Set<String> textSet=new HashSet<String>();
  126. for(Map.Entry<String,Set<String>> me: dataSet.entrySet()){
  127. String textPath=me.getKey();//文本路径
  128. Set<String> feature=me.getValue();//文本的特征集
  129. //假设文本包括特征f
  130. if(feature.contains(f)){
  131. textSet.add(textPath);
  132. }
  133. }
  134. //将特征及文本集赋给termText
  135. featureIndex.put(f,textSet);
  136. }
  137. return featureIndex;
  138. }
  139. /**
  140. * 文本集的类别成员
  141. * @param filePath
  142. * @return
  143. */
  144. public static Map<Integer,List<String>> getClusterMember(String filePath){
  145. Map<Integer,List<String>> clusterMember=new HashMap<Integer,List<String>>();
  146. File file=new File(filePath);
  147. File[] labels=file.listFiles();
  148. int labelNum=labels.length;
  149. for(int i=0;i<labelNum;i++){
  150. File[] texts=labels[i].listFiles();
  151. String label=labels[i].getName();
  152. List<String> member=new ArrayList<String>();
  153. for(File text: texts){
  154. member.add(label+File.separator+text.getName());
  155. }
  156. clusterMember.put(i, member);
  157. }
  158. return clusterMember;
  159. }
  160. /**
  161. * 类别集
  162. * @param filePath
  163. * @return
  164. */
  165. public static List<String> getLabelList(String filePath){
  166. List<String> labelList=new ArrayList<String>();
  167. File files=new File(filePath);
  168. File[] file=files.listFiles();
  169. for(File f: file){
  170. labelList.add(f.getName());
  171. }
  172. return labelList;
  173. }
  174. /**
  175. * 依据TFIDF集构造类别集
  176. * @param TFIDF
  177. * @return
  178. */
  179. public static List<String> getLabelList(Map<String,Map<String,Double>> TFIDF){
  180. Set<String> labels=new HashSet<String>();
  181. for(Map.Entry<String,Map<String,Double>> me: TFIDF.entrySet()){
  182. String path=me.getKey();
  183. String label=path.substring(0,path.lastIndexOf(File.separator));
  184. labels.add(label);
  185. }
  186. List<String> labelList=new ArrayList<String>(labels);
  187. return labelList;
  188. }
  189. }

由于文本数据量一般非常大,并且VSM具有高维稀疏的特点。所以一般须要进行特征选择。来降低特征的数量。

下一节,我将介绍几种特征选择方法。

(6)文本挖掘(三)——文本特征TFIDF权重计算及文本向量空间VSM表示的更多相关文章

  1. 文本情感分析(一):基于词袋模型(VSM、LSA、n-gram)的文本表示

    现在自然语言处理用深度学习做的比较多,我还没试过用传统的监督学习方法做分类器,比如SVM.Xgboost.随机森林,来训练模型.因此,用Kaggle上经典的电影评论情感分析题,来学习如何用传统机器学习 ...

  2. 文本分类学习(三) 特征权重(TF/IDF)和特征提取

    上一篇中,主要说的就是词袋模型.回顾一下,在进行文本分类之前,我们需要把待分类文本先用词袋模型进行文本表示.首先是将训练集中的所有单词经过去停用词之后组合成一个词袋,或者叫做字典,实际上一个维度很大的 ...

  3. 经典文本特征表示方法: TF-IDF

    引言 在信息检索, 文本挖掘和自然语言处理领域, IF-IDF 这个名字, 从它在 20 世纪 70 年代初被发明, 已名震江湖近半个世纪而不曾衰歇. 它表示的简单性, 应用的有效性, 使得它成为不同 ...

  4. tf-idf 词条权重计算

    在文本分类问题中,某些高频词一直出现,这样的词对区分文档的作用不大,例如: D1:  'Job was the chairman of Apple Inc.' D2:  'I like to use ...

  5. 关键词权重计算算法:TF-IDF

    TF-IDF(Term Frequency–Inverse Document Frequency)是一种用于资讯检索与文本挖掘的常用加权技术.TF-IDF是一种统计方法,用以评估一字词对于一个文件集或 ...

  6. sklearn之特征提取(文本特征)

    1.引言 关于文本的提取有很多方法,本文主要探索下sklearn官方的文本特征提取功能. 2.文本特征提取 文本分析是机器学习算法的主要应用领域. 然而,原始数据,符号文字序列不能直接传递给算法,因为 ...

  7. 机器学习入门-文本特征-使用LDA主题模型构造标签 1.LatentDirichletAllocation(LDA用于构建主题模型) 2.LDA.components(输出各个词向量的权重值)

    函数说明 1.LDA(n_topics, max_iters, random_state)  用于构建LDA主题模型,将文本分成不同的主题 参数说明:n_topics 表示分为多少个主题, max_i ...

  8. 前端极易被误导的css选择器权重计算及css内联样式的妙用技巧

    记得大学时候,专业课的网页设计书籍里面讲过css选择器权重的计算:id是100,class是10,html标签是5等等,然后全部加起来的和进行比较... 我只想说:真是误人子弟,害人不浅! 最近,在前 ...

  9. CSS 选择器权重计算规则

    其实,CSS有自己的优先级计算公式,而不仅仅是行间>内部>外部样式:ID>class>元素. 一.样式类型 1.行间 <h1 style="font-size: ...

随机推荐

  1. leetcode_919. Complete Binary Tree Inserter

    https://leetcode.com/problems/complete-binary-tree-inserter/ 设计一个CBTInserter,使用给定完全二叉树初始化.三个功能; CBTI ...

  2. CAD交互绘制直线(com接口)

    用户可以在控件视区任意位置绘制直线. 主要用到函数说明: _DMxDrawX::DrawLine 绘制一个直线.详细说明如下: 参数 说明 DOUBLE dX1 直线的开始点x坐标 DOUBLE dY ...

  3. Mysql使用导出导入数据库

    要在两台不同的电脑上进行开发,数据库需要统一,由于自己第一次完整的设计表结构,因此多次更改表结构,造成了很多不必要的麻烦, 需要将数据库导出成sql脚本: 命令行下具体用法如下: mysqldump ...

  4. 【计算机网络】3.2 无连接运输:UDP

    第三章第二节 无连接运输:UDP UDP(用户数据报协议,User Datagram Protocol),它只是做了运输层协议能够做的最少工作,除了多路复用和多路分解及一些差错检测外,它几乎没有做任何 ...

  5. gifsicle for linux ----------gif 图像处理

    1.gifsicle 在linux 中的使用下载gifsicle yum install gifsicle 若发现没有此包 ,更新epel第三方软件库 sudo yum install epel-re ...

  6. 「 Luogu P1379 」 八数码难题

    # 解题思路 这题不难,主要就是考虑如何判重,如果直接在 $9$ 个位置上都比较一遍的话.你会得到下面的好成绩 所以考虑另一种方法: 将九个位置压成一个整数,并且因为只有九个数,所以不会超出 $int ...

  7. [Python3网络爬虫开发实战] 6.3-Ajax结果提取

    这里仍然以微博为例,接下来用Python来模拟这些Ajax请求,把我发过的微博爬取下来. 1. 分析请求 打开Ajax的XHR过滤器,然后一直滑动页面以加载新的微博内容.可以看到,会不断有Ajax请求 ...

  8. Python:webshell 跳板机审计服务器

    1.修改paramiko源码包实现 https://github.com/paramiko/paramiko/tree/1.10.1 下载源码包 unzip paramiko-1.10.1.zip p ...

  9. ruby on rails使用gmail的smtp发送邮件

    参考至http://guides.rubyonrails.org/action_mailer_basics.html 在gmail账户的安全里先开启两步验证(链接:https://myaccount. ...

  10. Hadoop-2.7.1伪分布--安装配置hbase 1.1.2

    hbase-1.1.2下载地址:http://www.eu.apache.org/dist/hbase/stable/hbase-1.1.2-bin.tar.gz 下载之后解压至\usr\local目 ...