上两篇文章分别用朴素贝叶斯算法和KNN算法对newgroup文本进行了分类測试。本文使用Kmeans算法对文本进行聚类。

1、文本预处理

文本预处理在前面两本文章中已经介绍,此处(略)。

2、文本向量化

  1. package com.datamine.kmeans;
  2.  
  3. import java.io.*;
  4. import java.util.*;
  5. import java.util.Map.Entry;
  6.  
  7. /**
  8. * 计算文档的属性向量,将全部文档向量化
  9. * @author Administrator
  10. */
  11. public class ComputeWordsVector {
  12.  
  13. /**
  14. * 计算文档的TF-IDF属性向量。返回Map<文件名称,<特征词,TF-IDF值>>
  15. * @param testSampleDir 处理好的聚类样本測试例子集
  16. * @return 全部測试例子的属性向量构成的map
  17. * @throws IOException
  18. */
  19. public Map<String,Map<String,Double>> computeTFMultiIDF(String testSampleDir) throws IOException{
  20.  
  21. String word;
  22. Map<String,Map<String,Double>> allTestSampleMap = new TreeMap<String, Map<String,Double>>();
  23. Map<String,Double> idfPerWordMap = computeIDF(testSampleDir);
  24. Map<String,Double> tfPerDocMap = new TreeMap<String, Double>();
  25.  
  26. File[] samples = new File(testSampleDir).listFiles();
  27. System.out.println("the total number of test files is " + samples.length);
  28. for(int i = 0;i<samples.length;i++){
  29.  
  30. tfPerDocMap.clear();
  31. FileReader samReader = new FileReader(samples[i]);
  32. BufferedReader samBR = new BufferedReader(samReader);
  33. Double wordSumPerDoc = 0.0; //计算每篇文档的总词数
  34. while((word = samBR.readLine()) != null){
  35. if(!word.isEmpty()){
  36. wordSumPerDoc++;
  37. if(tfPerDocMap.containsKey(word))
  38. tfPerDocMap.put(word, tfPerDocMap.get(word)+1.0);
  39. else
  40. tfPerDocMap.put(word, 1.0);
  41. }
  42. }
  43.  
  44. Double maxCount = 0.0,wordWeight; //记录出现次数最多的词的次数,用作归一化 ???
  45. Set<Map.Entry<String, Double>> tempTF = tfPerDocMap.entrySet();
  46. for(Iterator<Map.Entry<String, Double>> mt = tempTF.iterator();mt.hasNext();){
  47. Map.Entry<String, Double> me = mt.next();
  48. if(me.getValue() > maxCount)
  49. maxCount = me.getValue();
  50. }
  51.  
  52. for(Iterator<Map.Entry<String, Double>> mt = tempTF.iterator();mt.hasNext();){
  53. Map.Entry<String, Double> me = mt.next();
  54. Double IDF = Math.log(samples.length / idfPerWordMap.get(me.getKey()));
  55. wordWeight = (me.getValue() / wordSumPerDoc) * IDF;
  56. tfPerDocMap.put(me.getKey(), wordWeight);
  57. }
  58. TreeMap<String,Double> tempMap = new TreeMap<String, Double>();
  59. tempMap.putAll(tfPerDocMap);
  60. allTestSampleMap.put(samples[i].getName(), tempMap);
  61. }
  62. printTestSampleMap(allTestSampleMap);
  63. return allTestSampleMap;
  64. }
  65.  
  66. /**
  67. * 输出測试例子map内容,用于測试
  68. * @param allTestSampleMap
  69. * @throws IOException
  70. */
  71. private void printTestSampleMap(
  72. Map<String, Map<String, Double>> allTestSampleMap) throws IOException {
  73. // TODO Auto-generated method stub
  74. File outPutFile = new File("E:/DataMiningSample/KmeansClusterResult/allTestSampleMap.txt");
  75. FileWriter outPutFileWriter = new FileWriter(outPutFile);
  76. Set<Map.Entry<String, Map<String,Double>>> allWords = allTestSampleMap.entrySet();
  77.  
  78. for(Iterator<Entry<String, Map<String, Double>>> it = allWords.iterator();it.hasNext();){
  79.  
  80. Map.Entry<String, Map<String,Double>> me = it.next();
  81. outPutFileWriter.append(me.getKey()+" ");
  82.  
  83. Set<Map.Entry<String, Double>> vectorSet = me.getValue().entrySet();
  84. for(Iterator<Map.Entry<String, Double>> vt = vectorSet.iterator();vt.hasNext();){
  85. Map.Entry<String, Double> vme = vt.next();
  86. outPutFileWriter.append(vme.getKey()+" "+vme.getValue()+" ");
  87. }
  88. outPutFileWriter.append("\n");
  89. outPutFileWriter.flush();
  90. }
  91. outPutFileWriter.close();
  92.  
  93. }
  94.  
  95. /**
  96. * 统计每一个词的总出现次数,返回出现次数大于n次的词汇构成终于的属性词典
  97. * @param strDir 处理好的newsgroup文件文件夹的绝对路径
  98. * @param wordMap 记录出现的每一个词构成的属性词典
  99. * @return newWordMap 返回出现次数大于n次的词汇构成终于的属性词典
  100. * @throws IOException
  101. */
  102. public SortedMap<String, Double> countWords(String strDir,
  103. Map<String, Double> wordMap) throws IOException {
  104.  
  105. File sampleFile = new File(strDir);
  106. File[] sample = sampleFile.listFiles();
  107. String word;
  108.  
  109. for(int i =0 ;i < sample.length;i++){
  110.  
  111. if(!sample[i].isDirectory()){
  112. FileReader samReader = new FileReader(sample[i]);
  113. BufferedReader samBR = new BufferedReader(samReader);
  114. while((word = samBR.readLine()) != null){
  115. if(!word.isEmpty() && wordMap.containsKey(word))
  116. wordMap.put(word, wordMap.get(word)+1);
  117. else
  118. wordMap.put(word, 1.0);
  119. }
  120. samBR.close();
  121. }else{
  122. countWords(sample[i].getCanonicalPath(),wordMap);
  123. }
  124. }
  125.  
  126. /*
  127. * 去除停顿词后。先用DF算法选取特征词,后面再增加特征词的选取算法
  128. */
  129. SortedMap<String,Double> newWordMap = new TreeMap<String, Double>();
  130. Set<Map.Entry<String, Double>> allWords = wordMap.entrySet();
  131. for(Iterator<Map.Entry<String, Double>> it = allWords.iterator();it.hasNext();){
  132. Map.Entry<String, Double> me = it.next();
  133. if(me.getValue() > 100) //DF算法降维
  134. newWordMap.put(me.getKey(), me.getValue());
  135. }
  136.  
  137. return newWordMap;
  138. }
  139.  
  140. /**
  141. * 计算IDF,即属性词典中每一个词在多少个文档中出现过
  142. * @param testSampleDir 聚类算法測试样本所在的文件夹
  143. * @return 单词IDFmap <单词,包括该单词的文档数>
  144. * @throws IOException
  145. */
  146. public Map<String,Double> computeIDF(String testSampleDir) throws IOException{
  147.  
  148. Map<String,Double> IDFPerWordMap = new TreeMap<String, Double>();
  149. //记下当前已经遇到过的该文档中的词
  150. Set<String> alreadyCountWord = new HashSet<String>();
  151. String word;
  152. File[] samples = new File(testSampleDir).listFiles();
  153. for(int i = 0;i<samples.length;i++){
  154.  
  155. alreadyCountWord.clear();
  156. FileReader tsReader = new FileReader(samples[i]);
  157. BufferedReader tsBR = new BufferedReader(tsReader);
  158. while((word = tsBR.readLine()) != null){
  159.  
  160. if(!alreadyCountWord.contains(word)){
  161. if(IDFPerWordMap.containsKey(word))
  162. IDFPerWordMap.put(word, IDFPerWordMap.get(word)+1.0);
  163. else
  164. IDFPerWordMap.put(word, 1.0);
  165. alreadyCountWord.add(word);
  166. }
  167. }
  168. }
  169. return IDFPerWordMap;
  170. }
  171.  
  172. /**
  173. * 创建聚类算法的測试例子集。主要是过滤出仅仅含有特征词的文档写到一个文件夹下
  174. * @param srcDir 源文件夹,已经预处理可是还没有过滤非特征词的文档文件夹
  175. * @param desDir 目的文件夹,聚类算法的測试例子文件夹
  176. * @return 创建測试例子集中特征词数组
  177. * @throws IOException
  178. */
  179. public String[] createTestSamples(String srcDir, String desDir) throws IOException {
  180.  
  181. SortedMap<String,Double> wordMap = new TreeMap<String, Double>();
  182. wordMap = countWords(srcDir,wordMap);
  183. System.out.println("special words map sizes:" + wordMap.size());
  184. String word,testSampleFile;
  185.  
  186. File[] sampleDir = new File(srcDir).listFiles();
  187. for(int i =0;i<sampleDir.length;i++){
  188.  
  189. File[] sample = sampleDir[i].listFiles();
  190. for(int j =0;j<sample.length;j++){
  191.  
  192. testSampleFile = desDir + sampleDir[i].getName()+"_"+sample[j].getName();
  193. FileReader samReader = new FileReader(sample[j]);
  194. BufferedReader samBR = new BufferedReader(samReader);
  195. FileWriter tsWriter = new FileWriter(new File(testSampleFile));
  196. while((word = samBR.readLine()) != null){
  197. if(wordMap.containsKey(word))
  198. tsWriter.append(word + "\n");
  199. }
  200. tsWriter.flush();
  201. tsWriter.close();
  202. }
  203. }
  204.  
  205. //返回属性词典
  206. String[] terms = new String[wordMap.size()];
  207. int i = 0;
  208. Set<Map.Entry<String, Double>> allWords = wordMap.entrySet();
  209. for(Iterator<Map.Entry<String, Double>> it = allWords.iterator();it.hasNext();){
  210. Map.Entry<String, Double> me = it.next();
  211. terms[i] = me.getKey();
  212. i++;
  213. }
  214.  
  215. return terms;
  216.  
  217. }
  218.  
  219. }

3、Kmeans算法

Kmeans算法是很经典的聚类算法,算法主要过程例如以下:先选K个(或者随机选择)初始聚类点作为初始中心点,然后就算其它全部点到K个聚类中心点的距离,将点分到近期的聚类中。聚类完后。再次计算各个类中的中心点,中心点发生变化,于是更新中心点,然后再计算其它点到中心点的距离又一次聚类。中心点又发生变化,如此迭代下去。

初始点选取策略:随机选。均匀抽样,最大最小法等....

距离的度量方法:1-余弦相似度,2-向量内积

算法停止条件:计算准则函数及设置最大迭代次数

空聚类的处理:注意空聚类导致的程序bug

  1. package com.datamine.kmeans;
  2.  
  3. import java.io.BufferedReader;
  4. import java.io.FileNotFoundException;
  5. import java.io.FileReader;
  6. import java.io.FileWriter;
  7. import java.io.IOException;
  8. import java.util.*;
  9.  
  10. /**
  11. * kmeans聚类算法的实现类,将newsgroup文档集聚成10类、20类、30类
  12. * 算法结束条件:当每一个点近期的聚类中心点就是它所属的聚类中心点时。算法结束
  13. * @author Administrator
  14. *
  15. */
  16. public class KmeansCluster {
  17.  
  18. /**
  19. * kmeans算法主过程
  20. * @param allTestSampleMap 聚类算法測试样本map(已经向量化) <文件名称,<特征词,TF-IDF值>>
  21. * @param k 聚类的数量
  22. * @return 聚类结果 <文件名称,聚类完毕后所属的类别号>
  23. */
  24. private Map<String, Integer> doProcess(
  25. Map<String, Map<String, Double>> allTestSampleMap, int k) {
  26.  
  27. //0、首先获取allTestSampleMap全部文件名称顺序组成的数组
  28. String[] testSampleNames = new String[allTestSampleMap.size()];
  29. int count =0,tsLength = allTestSampleMap.size();
  30. Set<Map.Entry<String, Map<String,Double>>> allTestSampleMapSet = allTestSampleMap.entrySet();
  31. for(Iterator<Map.Entry<String, Map<String,Double>>> it = allTestSampleMapSet.iterator();it.hasNext();){
  32. Map.Entry<String, Map<String,Double>> me = it.next();
  33. testSampleNames[count++] = me.getKey();
  34. }
  35.  
  36. //1、初始点的选择算法是随机选择或者是均匀分开选择。这里採用后者
  37. Map<Integer,Map<String,Double>> meansMap = getInitPoint(allTestSampleMap,k);
  38. double [][] distance = new double[tsLength][k]; //distance[i][k]记录点i到聚类中心k的距离
  39.  
  40. //2、初始化k个聚类
  41. int[] assignMeans = new int[tsLength]; //记录全部点属于的聚类序号,初始化全部为0
  42. Map<Integer,Vector<Integer>> clusterMember = new TreeMap<Integer, Vector<Integer>>();//记录每一个聚类的成员点序号
  43. Vector<Integer> mem = new Vector<Integer>();
  44. int iterNum = 0; //迭代次数
  45.  
  46. while(true){
  47. System.out.println("Iteration No." + (iterNum++) + "-------------------------");
  48. //3、计算每一个点和每一个聚类中心的距离
  49. for(int i = 0;i < tsLength;i++){
  50. for(int j = 0;j<k;j++)
  51. distance[i][j] = getDistance(allTestSampleMap.get(testSampleNames[i]),meansMap.get(j));
  52. }
  53.  
  54. //4、找出每一个点近期的聚类中心
  55. int [] nearestMeans = new int[tsLength];
  56. for(int i = 0;i < tsLength;i++){
  57. nearestMeans[i] = findNearestMeans(distance,i);
  58. }
  59.  
  60. //5、推断当前全部点属于的聚类序号是否已经全部是其离的近期的聚类,假设是或者达到最大的迭代次数。那么结束算法
  61. int okCount = 0;
  62. for(int i= 0;i<tsLength;i++){
  63. if(nearestMeans[i] == assignMeans[i])
  64. okCount ++;
  65. }
  66. System.out.println("okCount = " + okCount);
  67. if(okCount == tsLength || iterNum >= 10)
  68. break;
  69.  
  70. //6、假设前面条件不满足,那么须要又一次聚类再次进行一次迭代,须要改动每一个聚类的成员和每一个点属于的聚类信息
  71. clusterMember.clear();
  72. for(int i = 0;i < tsLength;i++){
  73. assignMeans[i] = nearestMeans[i];
  74. if(clusterMember.containsKey(nearestMeans[i])){
  75. clusterMember.get(nearestMeans[i]).add(i);
  76. }
  77. else{
  78. mem.clear();
  79. mem.add(i);
  80. Vector<Integer> tempMem = new Vector<Integer>();
  81. tempMem.addAll(mem);
  82. clusterMember.put(nearestMeans[i], tempMem);
  83. }
  84. }
  85.  
  86. //7、又一次计算每一个聚类的中心点
  87. for(int i = 0;i<k;i++){
  88.  
  89. if(!clusterMember.containsKey(i)) //注意kmeans可能产生空聚类
  90. continue;
  91.  
  92. Map<String,Double> newMean = computeNewMean(clusterMember.get(i),allTestSampleMap,testSampleNames);
  93. Map<String,Double> tempMean = new TreeMap<String,Double>();
  94. tempMean.putAll(newMean);
  95. meansMap.put(i, tempMean);
  96. }
  97.  
  98. }
  99.  
  100. //8、形成聚类结果而且返回
  101. Map<String,Integer> resMap = new TreeMap<String,Integer>();
  102. for(int i = 0;i<tsLength;i++){
  103. resMap.put(testSampleNames[i], assignMeans[i]);
  104. }
  105.  
  106. return resMap;
  107. }
  108.  
  109. /**
  110. * 计算当前聚类的新中心,採用向量平均
  111. * @param clusterM 该点到全部聚类中心的距离
  112. * @param allTestSampleMap 全部測试例子 <文件名称,向量>
  113. * @param testSampleNames 全部測试例子名构成的数组
  114. * @return 新的聚类中心向量
  115. */
  116. private Map<String, Double> computeNewMean(Vector<Integer> clusterM,
  117. Map<String, Map<String, Double>> allTestSampleMap,
  118. String[] testSampleNames) {
  119.  
  120. double memberNum = (double)clusterM.size();
  121. Map<String,Double> newMeanMap = new TreeMap<String,Double>();
  122. Map<String,Double> currentMemMap = new TreeMap<String, Double>();
  123.  
  124. for(Iterator<Integer> it = clusterM.iterator();it.hasNext();){
  125. int me = it.next();
  126. currentMemMap = allTestSampleMap.get(testSampleNames[me]);
  127. Set<Map.Entry<String, Double>> currentMemMapSet = currentMemMap.entrySet();
  128. for(Iterator<Map.Entry<String, Double>> jt = currentMemMapSet.iterator();jt.hasNext();){
  129. Map.Entry<String, Double> ne = jt.next();
  130. if(newMeanMap.containsKey(ne.getKey()))
  131. newMeanMap.put(ne.getKey(), newMeanMap.get(ne.getKey())+ne.getValue());
  132. else
  133. newMeanMap.put(ne.getKey(), ne.getValue());
  134. }
  135. }
  136.  
  137. Set<Map.Entry<String, Double>> newMeanMapSet = newMeanMap.entrySet();
  138. for(Iterator<Map.Entry<String, Double>> it = newMeanMapSet.iterator();it.hasNext();){
  139. Map.Entry<String, Double> me = it.next();
  140. newMeanMap.put(me.getKey(), newMeanMap.get(me.getKey()) / memberNum);
  141. }
  142.  
  143. return newMeanMap;
  144. }
  145.  
  146. /**
  147. * 找出距离当前点近期的聚类中心
  148. * @param distance 点到全部聚类中心的距离
  149. * @param m 点(文本号)
  150. * @return 近期聚类中心的序号j
  151. */
  152. private int findNearestMeans(double[][] distance, int m) {
  153.  
  154. double minDist = 10;
  155. int j = 0;
  156. for(int i = 0;i<distance[m].length;i++){
  157. if(distance[m][i] < minDist){
  158. minDist = distance[m][i];
  159. j = i;
  160. }
  161. }
  162. return j;
  163. }
  164.  
  165. /**
  166. * 计算两个点的距离
  167. * @param map1 点1的向量map
  168. * @param map2 点2的向量map
  169. * @return 两个点的欧式距离
  170. */
  171. private double getDistance(Map<String, Double> map1, Map<String, Double> map2) {
  172.  
  173. return 1 - computeSim(map1,map2);
  174. }
  175.  
  176. /**计算两个文本的类似度
  177. * @param testWordTFMap 文本1的<单词,词频>向量
  178. * @param trainWordTFMap 文本2<单词,词频>向量
  179. * @return Double 向量之间的类似度 以向量夹角余弦计算(加上凝视部分代码就可以)或者向量内积计算(不加凝视部分,效果相当而速度更快)
  180. * @throws IOException
  181. */
  182. private double computeSim(Map<String, Double> testWordTFMap,
  183. Map<String, Double> trainWordTFMap) {
  184. // TODO Auto-generated method stub
  185. double mul = 0;//, testAbs = 0, trainAbs = 0;
  186. Set<Map.Entry<String, Double>> testWordTFMapSet = testWordTFMap.entrySet();
  187. for(Iterator<Map.Entry<String, Double>> it = testWordTFMapSet.iterator(); it.hasNext();){
  188. Map.Entry<String, Double> me = it.next();
  189. if(trainWordTFMap.containsKey(me.getKey())){
  190. mul += me.getValue()*trainWordTFMap.get(me.getKey());
  191. }
  192. //testAbs += me.getValue() * me.getValue();
  193. }
  194. //testAbs = Math.sqrt(testAbs);
  195.  
  196. /*Set<Map.Entry<String, Double>> trainWordTFMapSet = trainWordTFMap.entrySet();
  197. for(Iterator<Map.Entry<String, Double>> it = trainWordTFMapSet.iterator(); it.hasNext();){
  198. Map.Entry<String, Double> me = it.next();
  199. trainAbs += me.getValue()*me.getValue();
  200. }
  201. trainAbs = Math.sqrt(trainAbs);*/
  202. return mul ;/// (testAbs * trainAbs);
  203. }
  204.  
  205. /**
  206. * 获取kmeans算法迭代的初始点
  207. * @param allTestSampleMap <文件名称,<特征词。TF-IDF值>>
  208. * @param k 聚类的数量
  209. * @return meansMap k个聚类的中心点向量
  210. */
  211. private Map<Integer, Map<String, Double>> getInitPoint(
  212. Map<String, Map<String, Double>> allTestSampleMap, int k) {
  213.  
  214. int count = 0, i = 0;
  215. //保存k个聚类的中心向量
  216. Map<Integer,Map<String,Double>> meansMap = new TreeMap<Integer, Map<String,Double>>();
  217. System.out.println("本次聚类的初始点相应的文件为:");
  218. Set<Map.Entry<String, Map<String,Double>>> allTestSampleMapSet = allTestSampleMap.entrySet();
  219. for(Iterator<Map.Entry<String, Map<String,Double>>> it = allTestSampleMapSet.iterator();it.hasNext();){
  220. Map.Entry<String, Map<String,Double>> me = it.next();
  221. if(count == i*allTestSampleMapSet.size() / k){
  222. meansMap.put(i, me.getValue());
  223. System.out.println(me.getKey());
  224. i++;
  225. }
  226. count++ ;
  227. }
  228.  
  229. return meansMap;
  230. }
  231.  
  232. /**
  233. * 输出聚类结果到文件里
  234. * @param kmeansClusterResult 聚类结果
  235. * @param kmeansClusterResultFile 输出聚类结果到文件里
  236. * @throws IOException
  237. */
  238. private void printClusterResult(Map<String, Integer> kmeansClusterResult,
  239. String kmeansClusterResultFile) throws IOException {
  240.  
  241. FileWriter resultWriter = new FileWriter(kmeansClusterResultFile);
  242. Set<Map.Entry<String, Integer>> kmeansClusterResultSet = kmeansClusterResult.entrySet();
  243. for(Iterator<Map.Entry<String, Integer>> it = kmeansClusterResultSet.iterator();it.hasNext();){
  244. Map.Entry<String, Integer> me = it.next();
  245. resultWriter.append(me.getKey()+" "+me.getValue()+"\n");
  246. }
  247. resultWriter.flush();
  248. resultWriter.close();
  249. }
  250.  
  251. /**
  252. * 评估函数依据聚类结果文件统计熵 和 混淆矩阵
  253. * @param kmeansClusterResultFile 聚类结果文件
  254. * @param k 聚类数目
  255. * @return 聚类结果的熵值
  256. * @throws IOException
  257. */
  258. private double evaluateClusterResult(String kmeansClusterResultFile, int k) throws IOException {
  259.  
  260. Map<String,String> rightCate = new TreeMap<String, String>();
  261. Map<String,String> resultCate = new TreeMap<String, String>();
  262. FileReader crReader = new FileReader(kmeansClusterResultFile);
  263. BufferedReader crBR = new BufferedReader(crReader);
  264. String[] s;
  265. String line;
  266. while((line = crBR.readLine()) != null){
  267. s = line.split(" ");
  268. resultCate.put(s[0], s[1]);
  269. rightCate.put(s[0], s[0].split("_")[0]);
  270. }
  271. crBR.close();
  272. return computeEntropyAndConfuMatrix(rightCate,resultCate,k);//返回熵
  273. }
  274.  
  275. /**
  276. * 计算混淆矩阵并输出,返回熵
  277. * @param rightCate 正确的类目相应map
  278. * @param resultCate 聚类结果相应map
  279. * @param k 聚类的数目
  280. * @return 返回聚类熵
  281. */
  282. private double computeEntropyAndConfuMatrix(Map<String, String> rightCate,
  283. Map<String, String> resultCate, int k) {
  284.  
  285. //k行20列,[i,j]表示聚类i中属于类目j的文件数
  286. int[][] confusionMatrix = new int[k][20];
  287.  
  288. //首先求出类目相应的数组索引
  289. SortedSet<String> cateNames = new TreeSet<String>();
  290. Set<Map.Entry<String, String>> rightCateSet = rightCate.entrySet();
  291. for(Iterator<Map.Entry<String, String>> it = rightCateSet.iterator();it.hasNext();){
  292. Map.Entry<String, String> me = it.next();
  293. cateNames.add(me.getValue());
  294. }
  295.  
  296. String[] cateNamesArray = cateNames.toArray(new String[0]);
  297. Map<String,Integer> cateNamesToIndex = new TreeMap<String, Integer>();
  298. for(int i =0;i < cateNamesArray.length ;i++){
  299. cateNamesToIndex.put(cateNamesArray[i], i);
  300. }
  301.  
  302. for(Iterator<Map.Entry<String, String>> it = rightCateSet.iterator();it.hasNext();){
  303. Map.Entry<String, String> me = it.next();
  304. confusionMatrix[Integer.parseInt(resultCate.get(me.getKey()))][cateNamesToIndex.get(me.getValue())]++;
  305. }
  306.  
  307. //输出混淆矩阵
  308. double [] clusterSum = new double[k]; //记录每一个聚类的文件数
  309. double [] everyClusterEntropy = new double[k]; //记录每一个聚类的熵
  310. double clusterEntropy = 0;
  311.  
  312. System.out.print(" ");
  313.  
  314. for(int i=0;i<20;i++){
  315. System.out.printf("%-6d",i);
  316. }
  317.  
  318. System.out.println();
  319.  
  320. for(int i =0;i<k;i++){
  321. System.out.printf("%-6d",i);
  322. for(int j = 0;j<20;j++){
  323. clusterSum[i] += confusionMatrix[i][j];
  324. System.out.printf("%-6d",confusionMatrix[i][j]);
  325. }
  326. System.out.println();
  327. }
  328. System.out.println();
  329.  
  330. //计算熵值
  331. for(int i = 0;i<k;i++){
  332. if(clusterSum[i] != 0){
  333. for(int j = 0;j< 20 ;j++){
  334. double p = (double)confusionMatrix[i][j]/clusterSum[i];
  335. if(p!=0)
  336. everyClusterEntropy[i] += -p * Math.log(p);
  337. }
  338. clusterEntropy += clusterSum[i]/(double)rightCate.size() * everyClusterEntropy[i];
  339. }
  340. }
  341. return clusterEntropy;
  342. }
  343.  
  344. public void KmeansClusterMain(String testSampleDir) throws IOException {
  345.  
  346. //首先计算文档TF-IDF向量,保存为Map<String,Map<String,Double>> 即为Map<文件名称,Map<特征词,TF-IDF值>>
  347. ComputeWordsVector computV = new ComputeWordsVector();
  348.  
  349. //int k[] = {10,20,30}; 三组分类
  350. int k[] = {20};
  351.  
  352. Map<String,Map<String,Double>> allTestSampleMap = computV.computeTFMultiIDF(testSampleDir);
  353.  
  354. for(int i =0;i<k.length;i++){
  355. System.out.println("開始聚类。聚成"+k[i]+"类");
  356. String KmeansClusterResultFile = "E:\\DataMiningSample\\KmeansClusterResult\\";
  357. Map<String,Integer> KmeansClusterResult = new TreeMap<String, Integer>();
  358. KmeansClusterResult = doProcess(allTestSampleMap,k[i]);
  359. KmeansClusterResultFile += k[i];
  360. printClusterResult(KmeansClusterResult,KmeansClusterResultFile);
  361. System.out.println("The Entropy for this Cluster is " + evaluateClusterResult(KmeansClusterResultFile,k[i]));
  362. }
  363.  
  364. }
  365.  
  366. public static void main(String[] args) throws IOException {
  367.  
  368. KmeansCluster test = new KmeansCluster();
  369.  
  370. String KmeansClusterResultFile = "E:\\DataMiningSample\\KmeansClusterResult\\20";
  371. System.out.println("The Entropy for this Cluster is " + test.evaluateClusterResult(KmeansClusterResultFile,20));
  372. }
  373.  
  374. }

4、程序入口

  1. package com.datamine.kmeans;
  2.  
  3. import java.io.IOException;
  4. import java.text.SimpleDateFormat;
  5. import java.util.Date;
  6.  
  7. public class ClusterMain {
  8.  
  9. /**
  10. * Kmeans 聚类主程序入口
  11. * @param args
  12. * @throws IOException
  13. */
  14. public static void main(String[] args) throws IOException {
  15.  
  16. //数据预处理 在分类算法中已经实现 这里(略)
  17.  
  18. ComputeWordsVector computeV = new ComputeWordsVector();
  19.  
  20. KmeansCluster kmeansCluster = new KmeansCluster();
  21.  
  22. String srcDir = "E:\\DataMiningSample\\processedSample\\";
  23. String desDir = "E:\\DataMiningSample\\clusterTestSample\\";
  24.  
  25. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  26. String beginTime = sdf.format(new Date());
  27. System.out.println("程序開始运行时间:"+beginTime);
  28.  
  29. String[] terms = computeV.createTestSamples(srcDir,desDir);
  30. kmeansCluster.KmeansClusterMain(desDir);
  31.  
  32. String endTime = sdf.format(new Date());
  33. System.out.println("程序结束运行时间:"+endTime);
  34.  
  35. }
  36.  
  37. }

5、聚类结果

  1. 程序開始运行时间:2016-03-14 17:02:38
  2. special words map sizes:3832
  3. the total number of test files is 18828
  4. 開始聚类,聚成20
  5. 本次聚类的初始点相应的文件为:
  6. alt.atheism_49960
  7. comp.graphics_38307
  8. comp.os.ms-windows.misc_10112
  9. comp.sys.ibm.pc.hardware_58990
  10. comp.sys.mac.hardware_50449
  11. comp.windows.x_66402
  12. comp.windows.x_68299
  13. misc.forsale_76828
  14. rec.autos_103685
  15. rec.motorcycles_105046
  16. rec.sport.baseball_104941
  17. rec.sport.hockey_54126
  18. sci.crypt_15819
  19. sci.electronics_54016
  20. sci.med_59222
  21. sci.space_61185
  22. soc.religion.christian_20966
  23. talk.politics.guns_54517
  24. talk.politics.mideast_76331
  25. talk.politics.misc_178699
  26. Iteration No.0-------------------------
  27. okCount = 512
  28. Iteration No.1-------------------------
  29. okCount = 10372
  30. Iteration No.2-------------------------
  31. okCount = 15295
  32. Iteration No.3-------------------------
  33. okCount = 17033
  34. Iteration No.4-------------------------
  35. okCount = 17643
  36. Iteration No.5-------------------------
  37. okCount = 18052
  38. Iteration No.6-------------------------
  39. okCount = 18282
  40. Iteration No.7-------------------------
  41. okCount = 18404
  42. Iteration No.8-------------------------
  43. okCount = 18500
  44. Iteration No.9-------------------------
  45. okCount = 18627
  46. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
  47. 0 482 0 3 3 1 1 0 5 2 1 0 0 2 27 11 53 4 6 15 176
  48. 1 4 601 69 8 14 127 7 5 5 8 0 14 31 16 34 2 2 2 1 5
  49. 2 1 64 661 96 18 257 26 9 3 0 0 13 25 13 6 2 3 2 6 2
  50. 3 0 56 78 575 213 15 119 15 6 2 1 4 131 2 4 2 6 0 2 1
  51. 4 1 25 13 151 563 11 50 3 3 1 2 14 125 4 8 1 0 3 0 0
  52. 5 2 28 78 25 37 348 13 2 0 0 2 5 38 5 6 2 1 1 2 8
  53. 6 20 80 24 21 23 166 38 45 45 26 10 37 87 34 27 22 15 8 35 12
  54. 7 4 20 6 24 45 6 629 28 20 14 0 3 87 10 4 1 8 0 13 0
  55. 8 0 2 1 10 8 4 25 781 40 1 1 0 70 5 10 2 8 4 2 3
  56. 9 4 2 11 0 1 1 11 34 831 1 0 1 7 7 0 1 1 1 8 0
  57. 10 10 7 6 2 4 1 7 7 4 633 4 5 11 18 9 5 13 8 10 3
  58. 11 1 0 1 9 4 1 20 1 3 286 961 0 17 8 4 2 2 0 5 3
  59. 12 3 14 0 6 1 2 2 0 1 1 0 858 51 1 1 2 16 8 69 4
  60. 13 3 15 4 7 7 17 5 12 8 5 2 5 46 13 793 6 5 2 30 5
  61. 14 2 4 0 1 0 2 4 6 3 4 4 2 14 746 3 1 2 3 55 11
  62. 15 30 43 29 39 15 18 12 13 7 3 4 13 195 38 36 5 6 18 5 11
  63. 16 195 1 0 2 0 1 1 0 4 1 4 1 4 16 6 846 3 6 16 274
  64. 17 8 2 0 2 4 2 1 5 7 0 0 10 30 12 5 28 363 9 289 23
  65. 18 19 1 0 0 2 0 0 6 0 1 1 3 1 3 2 9 8 843 48 18
  66. 19 10 8 1 1 1 0 2 13 2 6 3 3 9 12 18 5 444 16 164 69
  67.  
  68. The Entropy for this Cluster is 1.2444339205006887
  69. 程序结束运行时间:2016-03-14 17:08:24

文本聚类——Kmeans的更多相关文章

  1. K-means算法及文本聚类实践

    K-Means是常用的聚类算法,与其他聚类算法相比,其时间复杂度低,聚类的效果也还不错,这里简单介绍一下k-means算法,下图是一个手写体数据集聚类的结果. 基本思想 k-means算法需要事先指定 ...

  2. [转]python进行中文文本聚类(切词以及Kmeans聚类)

    简介 查看百度搜索中文文本聚类我失望的发现,网上竟然没有一个完整的关于Python实现的中文文本聚类(乃至搜索关键词python 中文文本聚类也是如此),网上大部分是关于文本聚类的Kmeans聚类的原 ...

  3. pyhanlp 文本聚类详细介绍

    文本聚类 文本聚类简单点的来说就是将文本视作一个样本,在其上面进行聚类操作.但是与我们机器学习中常用的聚类操作不同之处在于. 我们的聚类对象不是直接的文本本身,而是文本提取出来的特征.因此如何提取特征 ...

  4. 文本挖掘之文本聚类(MapReduce)

    刘 勇  Email:lyssym@sina.com 简介 针对大数量的文本数据,采用单线程处理时,一方面消耗较长处理时间,另一方面对大量数据的I/O操作也会消耗较长处理时间,同时对内存空间的消耗也是 ...

  5. 文本挖掘之文本聚类(DBSCAN)

    刘 勇   Email:lyssym@sina.com 简介 鉴于基于划分的文本聚类方法只能识别球形的聚类,因此本文对基于密度的文本聚类算法展开研究.DBSCAN(Density-Based Spat ...

  6. 10.HanLP实现k均值--文本聚类

    笔记转载于GitHub项目:https://github.com/NLP-LOVE/Introduction-NLP 10. 文本聚类 正所谓物以类聚,人以群分.人们在获取数据时需要整理,将相似的数据 ...

  7. 【转】算法杂货铺——k均值聚类(K-means)

    k均值聚类(K-means) 4.1.摘要 在前面的文章中,介绍了三种常见的分类算法.分类作为一种监督学习方法,要求必须事先明确知道各个类别的信息,并且断言所有待分类项都有一个类别与之对应.但是很多时 ...

  8. 转】Mahout分步式程序开发 聚类Kmeans

    原博文出自于: http://blog.fens.me/hadoop-mahout-kmeans/ 感谢! Mahout分步式程序开发 聚类Kmeans Hadoop家族系列文章,主要介绍Hadoop ...

  9. Mahout分步式程序开发 聚类Kmeans(转)

    Posted: Oct 14, 2013 Tags: clusterHadoopkmeansMahoutR聚类 Comments: 13 Comments Mahout分步式程序开发 聚类Kmeans ...

随机推荐

  1. Selenium WebDriver的多浏览器测试

    1. IE浏览器,需要配合下载IEDriverSever.exe的驱动程序,目前selenium支持IE9以上. (驱动程序下载链接:https://pan.baidu.com/s/1YpaUsIs1 ...

  2. hihoCoder挑战赛29

    多打打不同的比赛,找经验啊 题目4 : 不上升序列 时间限制:40000ms 单点时限:2000ms 内存限制:256MB 描述 给定一个长度为 n 的非负整数序列 a[1..n]. 你每次可以花费 ...

  3. maven无法下载依赖jar包—几种仓库的区别

    一.问题背景 最近这两天,感觉自己智商急剧退化,到了自己都捉急的地步,呃,有必要记录下来,以后智商被人甩几条街的时候,看看这篇文字,找找灵感也是好的! 这个项目呢,是用IDEA开发的,我一切都弄好了, ...

  4. How to use MJRefresh

    Installation with CocoaPods:pod 'MJRefresh' Manual import: Drag All files in the MJRefresh folder to ...

  5. NOJ——1669xor的难题(详细的树状数组扩展—异或求和)

    [1669] xor的难题 时间限制: 1000 ms 内存限制: 65535 K 问题描述 最近Alex学长有个问题被困扰了很久,就是有同学给他n个数,然后给你m个查询,然后每个查询给你l和r(左下 ...

  6. HDU-1529 Cashier Employment

    据网上说这是到差分约束四星题... 可我觉得难吗? 比推DP方程容易... 两种约束方式,当然实现到程序就变成六种了... #include <cstdio> #include <c ...

  7. bzoj1023【SHOI2008】cactus仙人掌图

    题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1023 求一棵仙人掌的直径 sol :orz YDC神犇 http://ydcydcy1.blo ...

  8. [SCOI2011]糖果 (差分约束)

    题目链接 Solution 差分约束乱搞就好了. 需要注意的地方: 对于大于等于的直接联等于,应为等于,因为对于我满足条件而言,等于总是最好的. 对于等于的,注意要建双向边. 然后要开 \(long~ ...

  9. [APIO2009]抢掠计划 ($Tarjan$,最长路)

    题目链接 Solution 裸题诶... 直接 \(Tarjan\) 缩点+ \(SPFA\) 最长路即可. 不过在洛谷上莫名被卡... RE两个点... Code #include<bits/ ...

  10. maven项目打包 编码gbk的不可映射字符

    中文系统默认gbk编码格式,你的代码是utf8格式的.所以报错 <build> <plugins> <plugin> <groupId>org.apac ...