`

生成文本聚类java实现 (3)

 
阅读更多

    很多网友看到我的聚类的研究,到后来基本上都是到carrot2的研究上去了。但由于carrot2对中文的理解很不靠谱,所以参考了网络上的一些资料,现在贡献出来所有代码。

 

 代码的思路就是找字或者词出现的频度,并进行打分,最后按照出现次数和重要性,找出重要的语汇。现在贴出来一些可用的代码。

 ClusterBuilder.java

 /**

Java代码  收藏代码
  1.  *   
  2. @author    
  3. @version 创建时间:2011-3-8 下午02:02:36  
  4. * 聚类生成器  
  5.  */  
  6. public class ClusterBuilder {  
  7.     private static final Log LOG;  
  8.     private List<DocCluster> clusters;  
  9.     private ICTHit[] docs;  
  10.     private int maxLevels;  
  11.     private ClusteringOptions[] options;  
  12.     private boolean useTagsAsTitle;  
  13.     private String wordsExcluded;  
  14.     private static short[] bit1Table;  
  15.   
  16.     static {  
  17.         LOG = LogFactory.getLog(ClusterBuilder.class.getName());  
  18.   
  19.         bit1Table = new short[65536];  
  20.   
  21.         for (int n = 0; n < bit1Table.length; n++) {  
  22.             String s = Integer.toBinaryString(n);  
  23.             short m = 0;  
  24.             for (int k = 0; k < s.length(); k++) {  
  25.                 if (s.charAt(k) == '1') {  
  26.                     m = (short) (m + 1);  
  27.                 }  
  28.             }  
  29.             bit1Table[n] = m;  
  30.         }  
  31.     }  
  32.   
  33.     private static int getValidBitCount(long n) {  
  34.         int i3 = (int) (n % 65536L);  
  35.         n /= 65536L;  
  36.         int i2 = (int) (n % 65536L);  
  37.         n /= 65536L;  
  38.         int i1 = (int) (n % 65536L);  
  39.         n /= 65536L;  
  40.         int i0 = (int) (n % 65536L);  
  41.         return bit1Table[i0] + bit1Table[i1] + bit1Table[i2] + bit1Table[i3];  
  42.     }  
  43.   
  44.     private static int getDocHitCount(long[] hits) {  
  45.         assert (hits != null);  
  46.         if (hits == null)  
  47.             return 0;  
  48.         int n0 = 0;  
  49.         for (int i = 0; i < hits.length; i++) {  
  50.             n0 += getValidBitCount(hits[i]);  
  51.         }  
  52.         return n0;  
  53.     }  
  54.   
  55.     public ClusterBuilder() {  
  56.         for (int n = 0; n < bit1Table.length; n++)  
  57.         {  
  58.             String s = Integer.toBinaryString(n);  
  59.             short m = 0;  
  60.             for (int k = 0; k < s.length(); k++)  
  61.             {  
  62.                 if (s.getBytes()[k] == '1')  
  63.                 {  
  64.                     m = (short)(m + 1);  
  65.                 }  
  66.             }  
  67.             bit1Table[n] = m;  
  68.         }  
  69.     }  
  70.     /** 
  71.      *  
  72.      * @param docsToCluster 要聚类的记录列表 
  73.      * @param exWords 不使用的主题词列表,多个词用西文逗号分隔。这些词将不会作为主题词。 
  74.      * @param maxLevels 最大聚类级数 
  75.      * @param useTagsAsTitle 是否使用主题词作为类别主题词。如果不使用,则根据文档标题自动生成类别主题词。 
  76.      */  
  77.     public ClusterBuilder(ICTHit[] docsToCluster, String exWords, int maxLevels, boolean useTagsAsTitle) {  
  78.         this.useTagsAsTitle = useTagsAsTitle;  
  79.         this.wordsExcluded = exWords;  
  80.         this.maxLevels = maxLevels;  
  81.         this.docs = docsToCluster;  
  82.         this.options = new ClusteringOptions[3];  
  83.         this.options[0] = new ClusteringOptions();  
  84.         this.options[0].setDocMaxTagCount(10);  
  85.         this.options[0].setMinTagRelevance(60);  
  86.         this.options[0].setMinSameDocPercent(80);  
  87.   
  88.         this.options[1] = new ClusteringOptions();  
  89.         this.options[1].setDocMaxTagCount(8);  
  90.         this.options[1].setMinTagRelevance(85);  
  91.         this.options[1].setMinSameDocPercent(70);  
  92.         this.options[1].setTagMinDocCount(2);  
  93.         this.options[1].setMinSameDocs(2);  
  94.   
  95.         this.options[2] = new ClusteringOptions();  
  96.         this.options[2].setDocMaxTagCount(8);  
  97.         this.options[2].setMinTagRelevance(50);  
  98.         this.options[2].setMinSameDocPercent(70);  
  99.         this.options[2].setTagMinDocCount(2);  
  100.         this.options[2].setMinSameDocs(2);  
  101.     }  
  102.     /** 
  103.      * 对Docs记录列表执行聚类,结果存放于Clusters中 
  104.      */  
  105.     public void cluster() {  
  106.         this.clusters = createLevelClusters(docs, 0, options[0]);  
  107.         List subs = null;  
  108.         if (this.maxLevels <= 1) {  
  109.             return;  
  110.         }  
  111.         for (DocCluster dc : this.clusters) {  
  112.             if ((dc.getDocList().length < options[0].getMinDocsToCluster()) || (dc.getTags() == "其他"))  
  113.                 continue;  
  114.             subs = createLevelClusters(dc.getDocList(), 1, options[1]);  
  115.             if (subs.size() > 1)  
  116.                 dc.setSubclusters(subs);  
  117.         }  
  118.     }  
  119.     /** 
  120.      * 创建一个层级的聚类 
  121.      * @param docs 文档列表 
  122.      * @param level 层级号 
  123.      * @param levelOpt 该层级的聚类选项 
  124.      * @return 
  125.      */  
  126.     private List<DocCluster> createLevelClusters(ICTHit[] docs, int level, ClusteringOptions levelOpt) {  
  127.         TagHitMatrix matrix = new TagHitMatrix(docs.length, levelOpt.getDocMaxTagCount());  
  128.         List clusters = new ArrayList();  
  129.         int i, ValidTagCount;  
  130.         int DocCount = 0;  
  131.         // 扫描文档列表,根据每个文档的主题词列表,初始化主题词文档对照表。  
  132.         for (i = 0; i < docs.length; i++) {  
  133.             ICTHit d = docs[i];  
  134.             int validTagCount = 0;  
  135.             if (d.getTagList() != null) {  
  136.                 String[] tagList = d.getTagList();  
  137.                 for (int tagIdx = 0; (tagIdx < tagList.length) && (validTagCount < levelOpt.getDocMaxTagCount()); tagIdx++) {  
  138.                     String tag = tagList[tagIdx].trim();  
  139.                      // 主题词长度大于6个字的丢弃  
  140.                     if ((tag.length() <= 0)  
  141.                             || (tag.length() > 20)  
  142.                             || ((this.wordsExcluded.length() != 0) && ((tag.contains(this.wordsExcluded)) || (this.wordsExcluded  
  143.                                     .contains(tag)))))  
  144.                         continue;  
  145.                     matrix.AddDocHit(tag, i);  
  146.                     validTagCount++;  
  147.                 }  
  148.             }  
  149.   
  150.         }  
  151.   
  152.         int maxKwDocCount = 0;  
  153.         List entryListToRemove = new ArrayList();  
  154.         String kwWithMaxDocCount = "";  
  155.         LOG.debug("有效关键词:");  
  156.         for (Map.Entry entry : matrix.entrySet()) {  
  157.             // 统计当前主题词的命中文档数,文档数小于预设值,则该主题词将被删除  
  158.             int n = getDocHitCount((long[]) entry.getValue());  
  159.             if (n < levelOpt.getTagMinDocCount()) {  
  160.                 entryListToRemove.add((String) entry.getKey());  
  161.             } else {  
  162.                 LOG.debug((String) entry.getKey() + "(" + n + "), ");  
  163.   
  164.                 DocCount += n;  
  165.             }  
  166.             if (n > maxKwDocCount) {  
  167.                 maxKwDocCount = n;  
  168.                 kwWithMaxDocCount = (String) entry.getKey();  
  169.             }  
  170.         }  
  171.         LOG.debug("");  
  172.   
  173.         LOG.debug("被忽略的关键词:");  
  174.   
  175.         for (i = 0; i < entryListToRemove.size(); i++) {  
  176.             LOG.debug((String) entryListToRemove.get(i) + ", ");  
  177.             matrix.remove(entryListToRemove.get(i));  
  178.         }  
  179.   
  180.         LOG.debug("");  
  181.   
  182.         LOG.debug(entryListToRemove.size() + "个关键词被忽略。剩余" + matrix.size() + "个关键词。");  
  183.   
  184.         LOG.debug("最大文档数的关键词:" + kwWithMaxDocCount + ",文档数:" + maxKwDocCount + "。");  
  185.   
  186.         double docCountPerTag = matrix.size() > 0 ? DocCount / matrix.size() : 0.0D;  
  187.         LOG.debug("关键词平均文档数:" + docCountPerTag);  
  188.   
  189.         levelOpt.setMinSameDocs((int) (docCountPerTag / (2.0D + level)));  
  190.         if (levelOpt.getMinSameDocs() < 1) {  
  191.             levelOpt.setMinSameDocs(1);  
  192.         }  
  193.   
  194.         while (mergeClusters(matrix, levelOpt) > 0) {  
  195.         }  
  196.         return createResult(matrix, docs, level, levelOpt);  
  197.     }  
  198.   
  199.     private int mergeClusters(TagHitMatrix matrix, ClusteringOptions opt) {  
  200.         if (matrix.size() == 0)  
  201.             return 0;  
  202.         long[] docHitsMerged = (long[]) null;  
  203.         long[] maxDocHitsMerged = (long[]) null;  
  204.         String word1 = "";  
  205.         String word2 = "";  
  206.         String word1ToMerge = "";  
  207.         String word2ToMerge = "";  
  208.         int i,j;  
  209.         int sameDocs = 0;  
  210.         // 初始化一个相关度数组,0到100分,共101项  
  211.         List rankMatrix = new ArrayList();  
  212.         for (i = 0; i < 101; i++) {  
  213.             rankMatrix.add(new ArrayList());  
  214.         }  
  215.         List matrix2List = new ArrayList();  
  216.         matrix2List.addAll(matrix.entrySet());  
  217.         // 将主题词文档映射表中的主题词两两比对  
  218.         for (int i1 = 0; i1 < matrix2List.size() - 1; i1++) {  
  219.             Map.Entry hits1 = (Map.Entry) matrix2List.get(i1);  
  220.             word1 = (String) hits1.getKey();  
  221.             for (int i2 = i1 + 1; i2 < matrix2List.size(); i2++) {  
  222.                 Map.Entry hits2 = (Map.Entry) matrix2List.get(i2);  
  223.                 word2 = (String) hits2.getKey();  
  224.                 Object[] re = getWordsRelevance(mapEntry2TagHitEntry(hits1), mapEntry2TagHitEntry(hits2),  
  225.                         docHitsMerged, sameDocs, opt, matrix.hitsItemCount);  
  226.                 // 计算两个词的相关性,获取两词的文档汇总表,以及相同文档数  
  227.                 int nRank = ((Integer) re[0]).intValue();  
  228.                 docHitsMerged = (long[]) re[1];  
  229.                 sameDocs = ((Integer) re[2]).intValue();  
  230.                 // 相关度小于预设阈值的忽略  
  231.                 if (nRank >= opt.getMinTagRelevance()) {  
  232.                     ((List) rankMatrix.get(nRank)).add(new IdPair(i1, i2));  
  233.                 }  
  234.   
  235.             }  
  236.   
  237.         }  
  238.   
  239.         List tagListToRemove = new ArrayList();  
  240.         List entryListMerged = new ArrayList();  
  241.         entryListMerged.add(new TagHitEntry(""null));  
  242.         HashSet idPairTable = new HashSet();  
  243.         TagHitEntry entryToMerge1;  
  244.         while (true) {  
  245.             // 找到最大相关性的两个主题词  
  246.             for (i = 100; (i >= opt.getMinTagRelevance()) && (((List) rankMatrix.get(i)).size() == 0); i--){};  
  247.             if (i < opt.getMinTagRelevance()) {  
  248.                 break;  
  249.             }  
  250.             IdPair ip = (IdPair) ((List) rankMatrix.get(i)).get(0);  
  251.             // 合并两个类别  
  252.             ((List) rankMatrix.get(i)).remove(0);  
  253.               
  254.             entryToMerge1 = ip.Id1 >= 0 ? mapEntry2TagHitEntry((Map.Entry) matrix2List.get(ip.Id1))  
  255.                     : (TagHitEntry) entryListMerged.get(-ip.Id1);  
  256.             TagHitEntry entryToMerge2 = ip.Id2 >= 0 ? mapEntry2TagHitEntry((Map.Entry) matrix2List.get(ip.Id2))  
  257.                     : (TagHitEntry) entryListMerged.get(-ip.Id2);  
  258.             word1ToMerge = entryToMerge1.key;  
  259.             word2ToMerge = entryToMerge2.key;  
  260.             assert ((word1ToMerge.length() > 0) && (word2ToMerge.length() > 0));  
  261.   
  262.             String wordsMerged = word1ToMerge + "," + word2ToMerge;  
  263.             long[] lDocs0 = entryToMerge1.value;  
  264.             long[] lDocs1 = entryToMerge2.value;  
  265.             maxDocHitsMerged = new long[matrix.hitsItemCount];  
  266.             for (i = 0; i < lDocs0.length; i++) {  
  267.                 lDocs0[i] |= lDocs1[i];// 获取合并的文档集  
  268.             }  
  269.             if (ip.Id1 >= 0)  
  270.                 tagListToRemove.add(word1ToMerge);  
  271.             else  
  272.                 entryListMerged.set(-ip.Id1, new TagHitEntry(""null));  
  273.             if (ip.Id2 >= 0)  
  274.                 tagListToRemove.add(word2ToMerge);  
  275.             else {  
  276.                 entryListMerged.set(-ip.Id2, new TagHitEntry(""null));  
  277.             }  
  278.             entryListMerged.add(new TagHitEntry(wordsMerged, maxDocHitsMerged));  
  279.             // 替换与合并主题词有关联的其他相关主题词对的评分  
  280.             int idMerged = -(entryListMerged.size() - 1);  
  281.             int id2 = 0;  
  282.   
  283.             boolean CanDelete = false;  
  284.   
  285.             for (i = 0; i <= 100; i++) {  
  286.                 int ListCount = ((List) rankMatrix.get(i)).size();  
  287.                 if (ListCount == 0) {  
  288.                     continue;  
  289.                 }  
  290.   
  291.                 for (j = 0; j < ListCount; j++) {  
  292.                     IdPair p = (IdPair) ((List) rankMatrix.get(i)).get(j);  
  293.                     CanDelete = false;  
  294.                     if ((ip.Id1 == p.Id1) || (ip.Id2 == p.Id1)) {  
  295.                         id2 = p.Id2;  
  296.                         CanDelete = true;  
  297.                     } else if ((ip.Id1 == p.Id2) || (ip.Id2 == p.Id2)) {  
  298.                         id2 = p.Id1;  
  299.                         CanDelete = true;  
  300.                     }  
  301.                     if (!CanDelete)  
  302.                         continue;  
  303.                     if (idMerged == id2) {  
  304.                         continue;  
  305.                     }  
  306.   
  307.                     ((List) rankMatrix.get(i)).remove(j);  
  308.                     j--;  
  309.                     ListCount--;  
  310.   
  311.                     IdPair pairMerged = new IdPair(idMerged, id2);  
  312.                     if (idPairTable.contains(pairMerged)) {  
  313.                         continue;  
  314.                     }  
  315.   
  316.                     TagHitEntry e2 = id2 >= 0 ? mapEntry2TagHitEntry((Map.Entry) matrix2List.get(id2))  
  317.                             : (TagHitEntry) entryListMerged.get(-id2);  
  318.   
  319.                     assert ((e2.key.length() != 0) && (e2.key != wordsMerged));  
  320.   
  321.                     Object[] re = getWordsRelevance(new TagHitEntry(wordsMerged, maxDocHitsMerged), e2, docHitsMerged,  
  322.                             sameDocs, opt, matrix.hitsItemCount);  
  323.                     int rank = ((Integer) re[0]).intValue();  
  324.                     docHitsMerged = (long[]) re[1];  
  325.                     sameDocs = ((Integer) re[2]).intValue();  
  326.   
  327.                     if (rank <= opt.getMinTagRelevance())  
  328.                         continue;  
  329.                     ((List) rankMatrix.get(rank)).add(pairMerged);  
  330.                     idPairTable.add(pairMerged);  
  331.                 }  
  332.   
  333.             }  
  334.   
  335.         }  
  336.         // 删除被合并的主题词  
  337.         for (int m =0;m<tagListToRemove.size();m++){  
  338.             matrix.remove(tagListToRemove.get(m));  
  339.         }  
  340.         /** 
  341.         for (String w : tagListToRemove) 
  342.             matrix.remove(w); 
  343.         **/   
  344.         // 添加合并而成的新主题词  
  345.         for (int n=0;n<entryListMerged.size();n++){  
  346.             TagHitEntry e = (TagHitEntry) entryListMerged.get(n);  
  347.             matrix.put(e.getKey(), e.getValue());  
  348.         }  
  349.         /** 
  350.         for (TagHitEntry e : entryListMerged) { 
  351.             if (e.getKey().length() > 0) 
  352.                 matrix.put(e.getKey(), e.getValue()); 
  353.         } 
  354.         **/  
  355.         return 0;  
  356.     }  
  357.   
  358.     private int mergeClusters1(TagHitMatrix matrix, ClusteringOptions opt) {  
  359.         if (matrix.size() == 0)  
  360.             return 0;  
  361.         long[] docHitsMerged = (long[]) null;  
  362.         long[] maxDocHitsMerged = (long[]) null;  
  363.         int nMaxRank = 0;  
  364.         String word1 = "";  
  365.         String word2 = "";  
  366.         String word1ToMerge = "";  
  367.         String word2ToMerge = "";  
  368.         int sameDocs = 0;  
  369.   
  370.         List matrix2List = new ArrayList();  
  371.         matrix2List.addAll(matrix.entrySet());  
  372.   
  373.         for (int i1 = 0; i1 < matrix2List.size() - 1; i1++) {  
  374.             TagHitEntry hits1 = mapEntry2TagHitEntry((Map.Entry) matrix2List.get(i1));  
  375.             word1 = hits1.getKey();  
  376.             for (int i2 = i1 + 1; i2 < matrix2List.size(); i2++) {  
  377.                 TagHitEntry hits2 = mapEntry2TagHitEntry((Map.Entry) matrix2List.get(i2));  
  378.                 word2 = hits2.getKey();  
  379.                 Object[] re = getWordsRelevance(hits1, hits2, docHitsMerged, sameDocs, opt, matrix.hitsItemCount);  
  380.                 int nRank = ((Integer) re[0]).intValue();  
  381.                 docHitsMerged = (long[]) re[1];  
  382.                 sameDocs = ((Integer) re[2]).intValue();  
  383.   
  384.                 if ((nRank <= nMaxRank) || (nRank <= opt.getMinTagRelevance()))  
  385.                     continue;  
  386.                 nMaxRank = nRank;  
  387.                 maxDocHitsMerged = docHitsMerged;  
  388.                 word1ToMerge = word1;  
  389.                 word2ToMerge = word2;  
  390.             }  
  391.   
  392.         }  
  393.   
  394.         if ((word1ToMerge.length() == 0) || (word2ToMerge.length() == 0)) {  
  395.             return 0;  
  396.         }  
  397.   
  398.         String wordsMerged = word1ToMerge + "," + word2ToMerge;  
  399.         if ((nMaxRank > opt.getMinTagRelevance()) && (wordsMerged != "")) {  
  400.             matrix.remove(word1ToMerge);  
  401.             matrix.remove(word2ToMerge);  
  402.             matrix.put(wordsMerged, maxDocHitsMerged);  
  403.             LOG.debug("(" + word1ToMerge + ") - (" + word2ToMerge + ")");  
  404.   
  405.             return 1;  
  406.         }  
  407.   
  408.         return 0;  
  409.     }  
  410.   
  411.     private Object[] getWordsRelevance(TagHitEntry entry1, TagHitEntry entry2, long[] docHitsMerged, int sameDocCount,  
  412.             ClusteringOptions opt, int hitsItemCount) {  
  413.         Object[] re = new Object[3];  
  414.         docHitsMerged = new long[hitsItemCount];  
  415.         sameDocCount = 0;  
  416.   
  417.         String tag1 = entry1.getKey();  
  418.         String tag2 = entry2.getKey();  
  419.         assert (tag2 != tag1);  
  420.   
  421.         long[] lDocs0 = entry1.getValue();  
  422.         long[] lDocs1 = entry2.getValue();  
  423.         int n0 = 0;  
  424.         int n1 = 0;  
  425.         n0 = getDocHitCount(lDocs0);  
  426.         n1 = getDocHitCount(lDocs1);  
  427.         int docCountMin = Math.min(n0, n1);  
  428.         int docCountMax = Math.max(n0, n1);  
  429.         int docCountMerged = 0;  
  430.   
  431.         long sameDocBits = 0L;  
  432.         long diffDocBits = 0L;  
  433.         int diffDocCount = 0;  
  434.         for (int i = 0; i < lDocs0.length; i++) {  
  435.             docHitsMerged[i] = lDocs0[i] | lDocs1[i];// 获取合并的文档集  
  436.             docCountMerged += getValidBitCount(docHitsMerged[i]);  
  437.             diffDocBits = lDocs0[i] ^ lDocs1[i];// 获取不同的文档集  
  438.             diffDocCount += getValidBitCount(diffDocBits);  
  439.             sameDocBits = lDocs0[i] & lDocs1[i];// 获取相同的文档集  
  440.             sameDocCount += getValidBitCount(sameDocBits);  
  441.         }  
  442.   
  443.         boolean IsSubstring = false;  
  444.         // 一个主题词是另一个的子串,则得分较高  
  445.         if ((tag2.contains(tag1)) || (tag1.contains(tag2))) {  
  446.             IsSubstring = true;  
  447.             docCountMin += opt.getTagMinDocCount();  
  448.         }  
  449.   
  450.         if ((sameDocCount == 0) && (!IsSubstring)) {  
  451.             re[0] = Integer.valueOf(0);  
  452.             re[1] = docHitsMerged;  
  453.             re[2] = Integer.valueOf(sameDocCount);  
  454.             return re;  
  455.         }  
  456.   
  457.         if (docCountMin < opt.getTagMinDocCount()) {  
  458.             re[0] = Integer.valueOf(0);  
  459.             re[1] = docHitsMerged;  
  460.             re[2] = Integer.valueOf(sameDocCount);  
  461.             return re;  
  462.         }  
  463.   
  464.         int samePercent = (int) Math.round(sameDocCount * 100.0D / docCountMerged);  
  465.         int samePercentMin = (int) Math.round(sameDocCount * 100.0D / docCountMin);  
  466.         int diffPercent = (int) Math.round(diffDocCount * 100.0D / docCountMerged);  
  467.         LOG.debug("相关性:" + tag1 + "(" + n0 + ")-(" + n1 + ")" + tag2);  
  468.         LOG.debug(", SamePercent=" + samePercent);  
  469.         LOG.debug(", SamePercentMin=" + samePercentMin);  
  470.         LOG.debug(", DiffPercent=" + diffPercent);  
  471.         int nRank;  
  472.         if ((sameDocCount >= opt.getMinSameDocs())  
  473.                 && ((docCountMin < 10) || (samePercentMin >= opt.getMinSameDocPercent()))) {  
  474.             nRank = (int) Math.round((samePercentMin + samePercent) * 0.85D - diffPercent * 0.2D);  
  475.         } else {  
  476.             nRank = 0;  
  477.         }  
  478.         if (IsSubstring)  
  479.             nRank += 80;  
  480.         LOG.debug(", Rank=" + nRank);  
  481.   
  482.         re[0] = Integer.valueOf(Math.min(nRank, 100));  
  483.         re[1] = docHitsMerged;  
  484.         re[2] = Integer.valueOf(sameDocCount);  
  485.         return re;  
  486.     }  
  487.   
  488.     private TagHitEntry mapEntry2TagHitEntry(Map.Entry<String, long[]> e) {  
  489.         return new TagHitEntry((String) e.getKey(), (long[]) e.getValue());  
  490.     }  
  491.   
  492.     @SuppressWarnings("unchecked")  
  493.     private List<DocCluster> createResult(TagHitMatrix matrix, ICTHit[] docs, int level, ClusteringOptions opt) {  
  494.         int i,j;  
  495.         Map<String,DocValue> clsIdList = new HashMap();  
  496.         List ClassTitleList = new ArrayList();  
  497.         for (Map.Entry de : matrix.entrySet()) {  
  498.             DocValue dv = new DocValue();  
  499.             clsIdList.put((String) de.getKey(), dv);  
  500.         }  
  501.   
  502.         List<Integer> otherIdList = new ArrayList();  
  503.         TagHitEntry maxTagHitEntry = new TagHitEntry();  
  504.         int clsCount;  
  505.         String tag;  
  506.         // 确定每个文档所属的类别  
  507.         for (i = 0; i < docs.length; i++) {  
  508.             ICTHit d = docs[i];  
  509.             TagHitMatrix.ClusterDocInfo di = matrix.docs[i];  
  510.             assert (docs[i] != null);  
  511.             int maxTagHit = 0;  
  512.             clsCount = 0;  
  513.   
  514.             for (Map.Entry hits : matrix.entrySet()) {  
  515.                 int tagHitCount = 0;  
  516.                 int score = 0;  
  517.                 String clsWordListStr = "," + (String) hits.getKey() + ",";  
  518.                 // 那个类别包含当前文档的主题词最多,该文档就属于哪个类别  
  519.                 for (j = 0; j < di.TagCount; j++) {  
  520.                     tag = di.TagList[j];  
  521.                     score = j < 3 ? 2 : 1;  
  522.                     assert (tag.length() > 0);  
  523.                     if (!clsWordListStr.contains("," + tag + ","))  
  524.                         continue;  
  525.                     tagHitCount += score;  
  526.                     clsCount++;  
  527.                 }  
  528.   
  529.                 if (maxTagHit >= tagHitCount)  
  530.                     continue;  
  531.                 maxTagHit = tagHitCount;  
  532.                 maxTagHitEntry = mapEntry2TagHitEntry(hits);  
  533.             }  
  534.   
  535.             if (maxTagHit > 0) {  
  536.                 DocValue dv = (DocValue) clsIdList.get(maxTagHitEntry.getKey());  
  537.                 dv.idList.add(Integer.valueOf(i));  
  538.             } else {  
  539.                 otherIdList.add(Integer.valueOf(i));  
  540.             }  
  541.   
  542.         }  
  543.         // 生成类别列表  
  544.         List<DocCluster> clusterList = new ArrayList();  
  545.         String[] TagList;  
  546.         Object dc;  
  547.         for (Map.Entry<String,DocValue> kv : clsIdList.entrySet()) {  
  548.             DocValue dv = (DocValue) kv.getValue();  
  549.             if (dv.idList.size() <= 0)  
  550.                 continue;  
  551.             if (dv.idList.size() == 1) {  
  552.                 otherIdList.add((Integer) dv.idList.get(0));  
  553.             } else {  
  554.                 dc = new DocCluster();  
  555.                 ((DocCluster) dc).setDocIdList(new String[dv.idList.size()]);  
  556.                 ((DocCluster) dc).setDocList(new ICTHit[dv.idList.size()]);  
  557.                 for (i = 0; i < dv.idList.size(); i++) {  
  558.                     ((DocCluster) dc).getDocIdList()[i] = docs[((Integer) dv.idList.get(i)).intValue()].getDocId();  
  559.                     ((DocCluster) dc).getDocList()[i] = docs[((Integer) dv.idList.get(i)).intValue()];  
  560.                 }  
  561.                 ((DocCluster) dc).setLevel(level);  
  562.                 ((DocCluster) dc).setTags((String) kv.getKey());  
  563.   
  564.                 for (i = 0; (i < clusterList.size())  
  565.                         && (((DocCluster) dc).getDocIdList().length <= ((DocCluster) clusterList.get(i)).getDocIdList().length);) {  
  566.                     i++;  
  567.                 }  
  568.                 clusterList.add(i, (DocCluster) dc);  
  569.             }  
  570.         }  
  571.         for (i = opt.getMaxClusterCount(); i < clusterList.size();) {  
  572.             DocCluster c = (DocCluster) clusterList.get(i);  
  573.             List idList = ((DocValue) clsIdList.get(c.getTags())).idList;  
  574.             for (dc = idList.iterator(); ((Iterator) dc).hasNext();) {  
  575.                 int idx = ((Integer) ((Iterator) dc).next()).intValue();  
  576.                 otherIdList.add(Integer.valueOf(idx));  
  577.             }  
  578.             clusterList.remove(i);  
  579.         }  
  580.         int i1;  
  581.         for (i = 0; i < clusterList.size(); i++) {  
  582.             DocCluster dc1 = (DocCluster) clusterList.get(i);  
  583.             String[] tagList = dc1.getTags().split(",");  
  584.             String newTags = "";  
  585.   
  586.             for (j = 0; j < tagList.length; j++) {  
  587.                 i1 = dc1.getTags().indexOf(tagList[j]);  
  588.                 int i2 = dc1.getTags().lastIndexOf(tagList[j]);  
  589.                 if (i1 == i2)  
  590.                     newTags = newTags + tagList[j] + ",";  
  591.             }  
  592.             if ((newTags.trim().length() > 0) && (newTags.endsWith(","))) {  
  593.                 newTags = newTags.substring(0, newTags.length() - 1);  
  594.             }  
  595.             dc1.setTags(newTags);  
  596.   
  597.             dc1.setTitle("");  
  598.   
  599.             if (this.useTagsAsTitle) {  
  600.                 tagList = dc1.getTags().split(",");  
  601.                 for (j = 0; (tagList != null) && (j < tagList.length); j++) {  
  602.                     if ((dc1.getTitle() + tagList[j]).length() > 16)  
  603.                         break;  
  604.                     boolean isSubstr = false;  
  605.                     for (DocCluster c : clusterList) {  
  606.                         if ((c.getTitle().length() <= 0)  
  607.                                 || ((!c.getTitle().contains(tagList[j])) && (!tagList[j].contains(c.getTitle()))))  
  608.                             continue;  
  609.                         isSubstr = true;  
  610.                         break;  
  611.                     }  
  612.                     if (!isSubstr)  
  613.                         dc1.setTitle(dc1.getTitle() + tagList[j] + ",");  
  614.                 }  
  615.                 if ((dc1.getTitle().trim().length() > 0) && (dc1.getTitle().endsWith(","))) {  
  616.                     dc1.setTitle(dc1.getTitle().substring(0, dc1.getTitle().length() - 1));  
  617.                 }  
  618.   
  619.             }  
  620.   
  621.             if (dc1.getTitle() != "")  
  622.                 continue;  
  623.             dc1.setTitle(dc1.getTags());  
  624.             if (dc1.getTitle().length() <= 16)  
  625.                 continue;  
  626.             String s = dc1.getTitle().substring(016);  
  627.             int li = s.lastIndexOf(',');  
  628.             if (li > 0) {  
  629.                 dc1.setTitle(s.substring(0, li));  
  630.             }  
  631.   
  632.         }  
  633.   
  634.         if (otherIdList.size() > 0) {  
  635.             DocCluster clusterOther = new DocCluster();  
  636.             clusterOther.setDocIdList(new String[otherIdList.size()]);  
  637.             clusterOther.setDocList(new ICTHit[otherIdList.size()]);  
  638.             clusterOther.setLevel(level);  
  639.             clusterOther.setTitle("其他");  
  640.             clusterOther.setTags("其他");  
  641.             i = 0;  
  642.             for (int k=0;k<otherIdList.size();k++) {  
  643.                 int idx = otherIdList.get(k);  
  644.   
  645.                 clusterOther.getDocIdList()[i] = docs[idx].getDocId();  
  646.                 clusterOther.getDocList()[i] = docs[idx];  
  647.                 i++;  
  648.             }  
  649.             clusterList.add(clusterOther);  
  650.         }  
  651.   
  652.         return (List<DocCluster>) clusterList;  
  653.     }  
  654.   
  655.     public List<DocCluster> getClusters() {  
  656.         return this.clusters;  
  657.     }  
  658.   
  659.     public void setClusters(List<DocCluster> clusters) {  
  660.         this.clusters = clusters;  
  661.     }  
  662.   
  663.     public ICTHit[] getDocs() {  
  664.         return this.docs;  
  665.     }  
  666.   
  667.     public void setDocs(ICTHit[] docs) {  
  668.         this.docs = docs;  
  669.     }  
  670.   
  671.     public int getMaxLevels() {  
  672.         return this.maxLevels;  
  673.     }  
  674.   
  675.     public void setMaxLevels(int maxLevels) {  
  676.         this.maxLevels = maxLevels;  
  677.     }  
  678.   
  679.     public ClusteringOptions[] getOptions() {  
  680.         return this.options;  
  681.     }  
  682.   
  683.     public void setOptions(ClusteringOptions[] options) {  
  684.         this.options = options;  
  685.     }  
  686.   
  687.     public boolean isUseTagsAsTitle() {  
  688.         return this.useTagsAsTitle;  
  689.     }  
  690.   
  691.     public void setUseTagsAsTitle(boolean useTagsAsTitle) {  
  692.         this.useTagsAsTitle = useTagsAsTitle;  
  693.     }  
  694.   
  695.     public String getWordsExcluded() {  
  696.         return this.wordsExcluded;  
  697.     }  
  698.   
  699.     public void setWordsExcluded(String wordsExcluded) {  
  700.         this.wordsExcluded = wordsExcluded;  
  701.     }  
  702.   
  703.     private class DocValue {  
  704.         public List<Integer> idList = new ArrayList();  
  705.         public String titleListStr = "";  
  706.   
  707.         private DocValue() {  
  708.         }  
  709.     }  
  710.     /** 
  711.      * 主题词ID对,主题词ID为该主题词在主题词文档映射表中的主键位置。 
  712.     * @author  
  713.     * @version 创建时间:2011-3-9 下午02:52:44 
  714.      */  
  715.     private class IdPair {  
  716.         public int Id1;  
  717.         public int Id2;  
  718.   
  719.         public IdPair(int id1, int id2) {  
  720.             assert (id1 != id2);  
  721.             if (id1 < id2) {  
  722.                 this.Id1 = id1;  
  723.                 this.Id2 = id2;  
  724.             } else {  
  725.                 this.Id1 = id2;  
  726.                 this.Id2 = id1;  
  727.             }  
  728.         }  
  729.   
  730.         public int hashCode() {  
  731.             return -1;  
  732.         }  
  733.   
  734.         public boolean equals(Object o) {  
  735.             return (((IdPair) o).Id1 == this.Id1) && (((IdPair) o).Id2 == this.Id2);  
  736.         }  
  737.     }  
  738.   
  739.     public static class TagHitEntry {  
  740.         public String key;  
  741.         public long[] value;  
  742.   
  743.         public TagHitEntry() {  
  744.         }  
  745.   
  746.         public TagHitEntry(String k, long[] v) {  
  747.             this.key = k;  
  748.             this.value = v;  
  749.         }  
  750.   
  751.         public String getKey() {  
  752.             return this.key;  
  753.         }  
  754.   
  755.         public long[] getValue() {  
  756.             return this.value;  
  757.         }  
  758.     }  
  759. }  

 

   ClusteringOptions.java

 

 

Java代码  收藏代码
  1. /** 
  2.  *  
  3. * @author  
  4. * @version 创建时间:2011-3-8 上午10:23:27 
  5.  */  
  6. public class ClusteringOptions {  
  7.     public static int DefMaxClusterCount = 20;  
  8.     public static int DefMaxKeywordCount = 6;  
  9.     public static int DefMinWordsRelevance = 10;  
  10.     public static int DefTagMinDocCount = 3;  
  11.     public static int DefIgnoreSameDocs = 2;  
  12.     public static int DefSameDocPercent = 50;  
  13.     public static int DefMinDocsToCluster = 8;  
  14.     private int docMaxTagCount;  
  15.     private int maxClusterCount;  
  16.     private int minDocsToCluster;  
  17.     private int minSameDocPercent;  
  18.     private int minSameDocs;  
  19.     private int minTagRelevance;  
  20.     private int tagMinDocCount;  
  21.   
  22.     public ClusteringOptions() {  
  23.         this.maxClusterCount = DefMaxClusterCount;  
  24.         this.minTagRelevance = DefMinWordsRelevance;  
  25.         this.tagMinDocCount = DefTagMinDocCount;  
  26.         this.minSameDocs = DefIgnoreSameDocs;  
  27.         this.minSameDocPercent = DefSameDocPercent;  
  28.         this.docMaxTagCount = DefMaxKeywordCount;  
  29.         this.minDocsToCluster = DefMinDocsToCluster;  
  30.     }  
  31.   
  32.     public int getDocMaxTagCount() {  
  33.         return this.docMaxTagCount;  
  34.     }  
  35.   
  36.     public void setDocMaxTagCount(int docMaxTagCount) {  
  37.         this.docMaxTagCount = docMaxTagCount;  
  38.     }  
  39.   
  40.     public int getMaxClusterCount() {  
  41.         return this.maxClusterCount;  
  42.     }  
  43.   
  44.     public void setMaxClusterCount(int maxClusterCount) {  
  45.         this.maxClusterCount = maxClusterCount;  
  46.     }  
  47.   
  48.     public int getMinDocsToCluster() {  
  49.         return this.minDocsToCluster;  
  50.     }  
  51.   
  52.     public void setMinDocsToCluster(int minDocsToCluster) {  
  53.         this.minDocsToCluster = minDocsToCluster;  
  54.     }  
  55.   
  56.     public int getMinSameDocPercent() {  
  57.         return this.minSameDocPercent;  
  58.     }  
  59.   
  60.     public void setMinSameDocPercent(int minSameDocPercent) {  
  61.         this.minSameDocPercent = minSameDocPercent;  
  62.     }  
  63.   
  64.     public int getMinSameDocs() {  
  65.         return this.minSameDocs;  
  66.     }  
  67.   
  68.     public void setMinSameDocs(int minSameDocs) {  
  69.         this.minSameDocs = minSameDocs;  
  70.     }  
  71.   
  72.     public int getMinTagRelevance() {  
  73.         return this.minTagRelevance;  
  74.     }  
  75.   
  76.     public void setMinTagRelevance(int minTagRelevance) {  
  77.         this.minTagRelevance = minTagRelevance;  
  78.     }  
  79.   
  80.     public int getTagMinDocCount() {  
  81.         return this.tagMinDocCount;  
  82.     }  
  83.   
  84.     public void setTagMinDocCount(int tagMinDocCount) {  
  85.         this.tagMinDocCount = tagMinDocCount;  
  86.     }  
  87. }  

 

 

 

   DocCluster.java

 

Java代码  收藏代码
  1. /** 
  2.  *  
  3. * @author 
  4. * @version 创建时间:2011-3-8 上午10:23:35 
  5.  */  
  6. public class DocCluster {  
  7.     private String[] docIdList;  
  8.     private ICTHit[] docList;  
  9.     private int level;  
  10.     private List<DocCluster> subclusters;  
  11.     private String tags;  
  12.     private String title;  
  13.   
  14.     public String[] getDocIdList() {  
  15.         return this.docIdList;  
  16.     }  
  17.   
  18.     public void setDocIdList(String[] docIdList) {  
  19.         this.docIdList = docIdList;  
  20.     }  
  21.   
  22.     public ICTHit[] getDocList() {  
  23.         return this.docList;  
  24.     }  
  25.   
  26.     public void setDocList(ICTHit[] docList) {  
  27.         this.docList = docList;  
  28.     }  
  29.   
  30.     public int getLevel() {  
  31.         return level;  
  32.     }  
  33.   
  34.     public void setLevel(int level) {  
  35.         this.level = level;  
  36.     }  
  37.   
  38.     public List<DocCluster> getSubclusters() {  
  39.         return this.subclusters;  
  40.     }  
  41.   
  42.     public void setSubclusters(List<DocCluster> subclusters) {  
  43.         this.subclusters = subclusters;  
  44.     }  
  45.   
  46.     public String getTags() {  
  47.         return this.tags;  
  48.     }  
  49.   
  50.     public void setTags(String tags) {  
  51.         this.tags = tags;  
  52.     }  
  53.   
  54.     public String getTitle() {  
  55.         if (title == null)  
  56.             title = "";  
  57.         return this.title;  
  58.     }  
  59.   
  60.     public void setTitle(String title) {  
  61.         this.title = title;  
  62.     }  
  63. }  

 ICTHit.java

 

 

Java代码  收藏代码
  1. public class ICTHit implements Serializable {  
  2.     /* 
  3.      * 关键词数组 
  4.      */  
  5.     private String[] TagList;  
  6.     private String docId;  
  7.     private String title;  
  8.   
  9.     public String[] getTagList() {  
  10.         return TagList;  
  11.     }  
  12.   
  13.     public void setTagList(String[] tagList) {  
  14.         TagList = tagList;  
  15.     }  
  16.   
  17.     public String getDocId() {  
  18.         return docId;  
  19.     }  
  20.   
  21.     public void setDocId(String docId) {  
  22.         this.docId = docId;  
  23.     }  
  24.   
  25.     public String getTitle() {  
  26.         return title;  
  27.     }  
  28.   
  29.     public void setTitle(String title) {  
  30.         this.title = title;  
  31.     }     
  32.       
  33. }  

 

 

TagHitMatrix.java

 

 

 

 

Java代码  收藏代码
  1. public class TagHitMatrix extends LinkedHashMap<String, long[]> {  
  2.     /** 
  3.      *  
  4.      */  
  5.     private static final long serialVersionUID = -7511464445378974433L;  
  6.     public static int ii = 0;  
  7.     public ClusterDocInfo[] docs;  
  8.     public int hitsItemCount;  
  9.   
  10.     public TagHitMatrix(int DocCount, int MaxTagCount) {  
  11.         this.hitsItemCount = (int) (DocCount / 62.0D + 0.984375D);  
  12.         this.docs = new ClusterDocInfo[DocCount];  
  13.   
  14.         for (int i = 0; i < this.docs.length; i++)  
  15.             this.docs[i] = new ClusterDocInfo(MaxTagCount);  
  16.     }  
  17.   
  18.     public void AddDocHit(String TagStr, int Position) {  
  19.         TagStr = TagStr.trim();  
  20.   
  21.         int n = Position / 62;  
  22.         int m = Position % 62;  
  23.         long[] DocHits = (long[]) get(TagStr);  
  24.         if (DocHits == null) {  
  25.             DocHits = new long[this.hitsItemCount];  
  26.             put(TagStr, DocHits);  
  27.         }  
  28.         DocHits[n] |= Math.round(Math.pow(2.0D, m));  
  29.         ClusterDocInfo di = this.docs[Position];  
  30.         di.TagList[(di.TagCount++)] = TagStr;  
  31.     }  
  32.   
  33.     class ClusterDocInfo {  
  34.         public String[] TagList;  
  35.         public int TagCount;  
  36.   
  37.         public ClusterDocInfo(int MaxTagCount) {  
  38.             this.TagList = new String[MaxTagCount];  
  39.             this.TagCount = 0;  
  40.         }  
  41.     }  
  42. }  

 

 

   测试方法:

 

 

Java代码  收藏代码
  1. public void test(ICTHit[] icthits) throws IOException {  
  2.         ClusterBuilder clusterBuilder = new ClusterBuilder();  
  3.         // 设置需要聚类的数据集合,测试中用的null。  
  4.         clusterBuilder.setDocs(icthits);  
  5.         // 设置聚类级别,只使用1级  
  6.         clusterBuilder.setMaxLevels(10);  
  7.         clusterBuilder.setUseTagsAsTitle(true);  
  8.         // 一般将检索词设置为wordsExcluded  
  9.         clusterBuilder.setWordsExcluded("万美元,日本,公司,视频,北京时间,图文,新华网,新浪,消息,通讯,互联网,美国,中国");  
  10.         clusterBuilder  
  11.                 .setOptions(new ClusteringOptions[] { new ClusteringOptions(),new ClusteringOptions() });  
  12.   
  13.         // 开始聚类  
  14.         clusterBuilder.cluster();  
  15.         FileWriter fw1 = new FileWriter("c:/today-20110509-cluster.txt "true);  
  16.         BufferedWriter bw1 = new BufferedWriter(fw1);  
  17.   
  18.         // 打印结果  
  19.         if (clusterBuilder.getClusters() != null) {  
  20.             int i = 0;  
  21.             for (DocCluster docCluster : clusterBuilder.getClusters()) {  
  22.                 i++;  
  23.                 System.out.println("tag:" + docCluster.getTags() + "("  
  24.                         + docCluster.getDocIdList().length + ")");  
  25.                 bw1.write(docCluster.getTags() + "("+ docCluster.getDocIdList().length + ")"+"\r\n ");                
  26.                   
  27.                 if (docCluster.getDocList() != null  
  28.                         && docCluster.getDocList().length > 0) {  
  29.                     for (ICTHit co : docCluster.getDocList()) {  
  30.                         System.out.println("     DocID: " + co.getDocId());  
  31.                         bw1.write("标题为: "   + co.getTitle()+",ID为"+co.getDocId()+"\r\n ");    
  32.                         for (int m = 0; m < co.getTagList().length; m++) {                             
  33.                             bw1.write("标题为: "   + co.getTitle()+",ID为"+co.getDocId()+"\r\n ");    
  34.                             System.out.println("     Key Word: "  
  35.                                     + co.getTagList()[m]);  
  36.                         }  
  37.                         System.out.println("");  
  38.                     }  
  39.                     System.out.println("");  
  40.                 } else {  
  41.                     bw1.write("      该分类下无数据!"+"\r\n ");      
  42.                 }  
  43.                 bw1.write("-------------------------------------------------------------------------------\r\n");  
  44.             }  
  45.         }  
  46.         bw1.close();  
  47.         fw1.close();  
  48.     }  

 

 如上方法可以,是一个示例性的,没有用在生产当中。核心方法有了。大家可以引用到项目当中。效果比carrot2标准的方法要好很多。

 

http://heweiya.iteye.com/blog/1704401

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics