数据挖掘笔记-特征选择-算法实现-1

来源:互联网 发布:mysql 创建覆盖索引 编辑:程序博客网 时间:2024/05/29 02:47

关于特征选择相关的知识可以参考一下连接

数据挖掘笔记-特征选择-开方检验

数据挖掘笔记-特征选择-信息增益

数据挖掘笔记-特征选择-期望交叉熵

数据挖掘笔记-特征选择-互信息

数据挖掘笔记-特征选择-遗传算法

数据挖掘笔记-特征选择-整体汇总

项目源码里面包含Java和Python的实现,这里只列出Python实现:

代码托管:https://github.com/fighting-one-piece/repository-datamining.git

[python] view plaincopy
  1. class Doc:  
  2.       
  3.     def __init__(self, name):  
  4.         self._name = name  
  5.        
  6.     def setName(self, name):  
  7.         self._name = name  
  8.       
  9.     def getName(self):  
  10.         return self._name  
  11.       
  12.     def setCategory(self, category):  
  13.         self._category = category  
  14.           
  15.     def getCategory(self):  
  16.         return self._category  
  17.           
  18.     def setWords(self, words):  
  19.         self._words = words  
  20.           
  21.     def getWords(self):  
  22.         return self._words  
  23.       
  24.     def setTfidfWords(self, tfidfWords):  
  25.         self._tfidfWords = tfidfWords  
  26.           
  27.     def getTfidfWords(self):  
  28.         return self._tfidfWords  
  29.       
  30.     def getSortedTfidfWords(self):  
  31.         results = [sorted(self._tfidfWords.items(), key=lambda i : i[1], reverse=True), ]  
  32.         return results  
  33.       
  34.     def setCHIWords(self, chiWords):  
  35.         self._chiWords = chiWords  
  36.           
  37.     def getCHIWords(self):  
  38.         return self._chiWords  
  39.   
  40.     def setSimilarities(self, similarities):  
  41.         self._similarities = similarities  
  42.           
  43.     def getSimilarities(self):  
  44.         return self._similarities  
[python] view plaincopy
  1. #文档操作工具类          
  2. class DocHelper:  
  3.       
  4.     #获取目录下所有的文档  
  5.     @staticmethod  
  6.     def genDocs(path):  
  7.         docs = []  
  8.         DocHelper.genDocsIterator(path, docs)  
  9.         return docs  
  10.       
  11.     #遍历目录获取目录下所有的文档  
  12.     @staticmethod  
  13.     def genDocsIterator(path, docs):  
  14.         if os.path.isdir(path):  
  15.             for subPathName in os.listdir(path):  
  16.                 subPath = os.path.join(path, subPathName)  
  17.                 DocHelper.genDocsIterator(subPath, docs)  
  18.         else:  
  19.             name = path[path.rfind('\\') + 1 : path.rfind('.')]  
  20.             doc = Doc(name)  
  21.             doc.setCategory(path.split('\\')[-2])  
  22.             doc.setWords(WordUtils.splitFile(path));  
  23.             docs.append(doc)  
  24.       
  25.     #文档中是否包含指定词  
  26.     @staticmethod  
  27.     def docHasWord(doc, word):  
  28.         for dword in doc.getWords():  
  29.             if dword == word:  
  30.                 return True  
  31.         return False  
  32.       
  33.     #文档中词频统计  
  34.     @staticmethod  
  35.     def docWordsStatistics(doc):  
  36.         map = {}  
  37.         for word in doc.getWords():  
  38.             count = map.get(word)  
  39.             if count is None:  
  40.                 count = 0  
  41.             map[word] = count + 1  
  42.         return map  
  43.       
  44.     #根据文档所属类型分割文档集  
  45.     @staticmethod  
  46.     def docCategorySplit(docs):  
  47.         docSplits = {}  
  48.         for doc in docs:  
  49.             category = doc.getCategory()  
  50.             if docSplits.has_key(category):  
  51.                 cDocs = docSplits.get(category)  
  52.                 cDocs.append(doc)  
  53.             else :  
  54.                 cDocs = [doc]  
  55.                 docSplits[category] = cDocs  
  56.         return docSplits  
  57.       
  58.     #根据TFIDF取文档排行前N的词  
  59.     @staticmethod  
  60.     def docTopNWords(doc, n):  
  61.         sortedWords = DocHelper.sortWordValueMap(doc.getTfidfWords())  
  62.         words = []  
  63.         for item in sortedWords[0:n]:  
  64.             words.append(item[0])  
  65.         return words  
  66.                       
  67.     #文档中词的向量化  
  68.     @staticmethod  
  69.     def docWordsVector(doc, words):  
  70.         vector = []  
  71.         docWords = DocHelper.docWordsStatistics(doc)  
  72.         for word in words:  
  73.             count = docWords.get(word)  
  74.             if count is None:  
  75.                 vector.append(0)  
  76.             else :  
  77.                 vector.append(count)  
  78.         return vector  
  79.       
  80.     #根据词所属文档类型获取同类文档集和非同类文档集  
  81.     @staticmethod  
  82.     def categorySplit(category, docs):  
  83.         belongDocs = []  
  84.         nobelongDocs = []  
  85.         for doc in docs:  
  86.             if category == doc.getCategory():  
  87.                 belongDocs.append(doc)  
  88.             else:  
  89.                 nobelongDocs.append(doc)  
  90.         return belongDocs, nobelongDocs  
  91.       
  92.     #根据词所属文档类型获取同类文档集数量  
  93.     @staticmethod  
  94.     def categoryStatistics(category, docs):  
  95.         sum = 0  
  96.         for doc in docs:  
  97.             if category == doc.getCategory():  
  98.                 sum = sum + 1  
  99.         return sum  
  100.   
  101.     #根据词所属文档类型获取文档集中含有词数量  
  102.     @staticmethod  
  103.     def categoryWordStatistics(category, word, docs):  
  104.         sum = 0  
  105.         for doc in docs:  
  106.             if category == doc.getCategory() and \  
  107.                 DocHelper.docHasWord(doc, word):  
  108.                 sum = sum + 1  
  109.         return sum  
  110.       
  111.     #获取包含词文档集和非包含词文档集  
  112.     @staticmethod  
  113.     def wordDocsSplit(word, docs):  
  114.         belongDocs = []  
  115.         nobelongDocs = []  
  116.         for doc in docs:  
  117.             flag = False  
  118.             for dword in doc.getWords():  
  119.                 if word == dword:  
  120.                     flag = True  
  121.                     belongDocs.append(doc)  
  122.                     break;  
  123.             if flag == False:          
  124.                 nobelongDocs.append(doc)  
  125.         return belongDocs, nobelongDocs  
  126.       
  127.     #统计文档集包含词的文档数  
  128.     @staticmethod  
  129.     def wordInDocsStatistics(word, docs):  
  130.         sum = 0  
  131.         for doc in docs:  
  132.             if DocHelper.docHasWord(doc, word):  
  133.                 sum += 1  
  134.         return sum  
  135.   
  136.     #统计文档集不包含词的文档数  
  137.     @staticmethod  
  138.     def wordNotInDocsStatistics(word, docs):  
  139.         sum = 0  
  140.         for doc in docs:  
  141.             if DocHelper.docHasWord(doc, word) == False:  
  142.                 sum += 1  
  143.         return sum  
  144.       
  145.     #文档集包含词的文档数所属类型在包含次文档数中的概率  
  146.     @staticmethod  
  147.     def wordCategoryInDocsPercent(word, category, docs):  
  148.         sumWord = 0  
  149.         sumCategory = 0  
  150.         for doc in docs:  
  151.             if DocHelper.docHasWord(doc, word):  
  152.                 sumWord += 1  
  153.             if category == doc.getCategory():  
  154.                 sumCategory += 1  
  155.         return float(sumCategory) / sumWord  
  156.      
  157.     @staticmethod  
  158.     def calculateTF(doc):  
  159.         tf = {}  
  160.         for word in doc.getWords():  
  161.             if tf.has_key(word):  
  162.                 tf[word] = tf.get(word) + 1  
  163.             else:  
  164.                 tf[word] = 1  
  165.         return tf  
  166.       
  167.     #计算TFIDF  
  168.     @staticmethod  
  169.     def calculateTFIDF(docs):  
  170.         docTotalCount = float(len(docs))  
  171.         for doc in docs:  
  172.             wordTotalCount = len(doc.getWords())  
  173.             tfidfWords = {}  
  174.             docWords = DocHelper.docWordsStatistics(doc)  
  175.             for word in docWords.keys():  
  176.                 wordCount = docWords.get(word)  
  177.                 tf = float(wordCount) / wordTotalCount  
  178.                 docCount = DocHelper.wordInDocsStatistics(word, docs) + 1  
  179.                 if docCount > docTotalCount:  
  180.                     docCount = docTotalCount  
  181.                 idf = math.log(docTotalCount / docCount);  
  182.                 tfidf = tf * idf  
  183.                 tfidfWords[word] = tfidf  
  184.             doc.setTfidfWords(tfidfWords)  
  185.               
  186.     #根据开方检验特征选择算法计算文档集中各个文档的词与类别的开方值  
  187.     @staticmethod  
  188.     def calculateCHI(docs):  
  189.         docTotalCount = len(docs)  
  190.         for doc in docs:  
  191.             chiWords = {}  
  192.             words = doc.getWords()  
  193.             belongDocs,nobelongDocs = DocHelper.categorySplit(\  
  194.                 doc.getCategory(), docs)  
  195.             for word in words:  
  196.                 a = DocHelper.wordInDocsStatistics(word, belongDocs)  
  197.                 b = DocHelper.wordInDocsStatistics(word, nobelongDocs)  
  198.                 c = DocHelper.wordNotInDocsStatistics(word, belongDocs)  
  199.                 d = DocHelper.wordNotInDocsStatistics(word, nobelongDocs)  
  200.                 x = float((a*d-b*c)**2) / ((a+b)*(c+d))  
  201.                 chiWords[word] = x  
  202.             doc.setCHIWords(chiWords)  
  203.               
  204.     #根据信息增益特征选择算法计算文档集中词的信息增益  
  205.     @staticmethod  
  206.     def calculateInformationGain(docs):  
  207.         docTotalCount = len(docs)  
  208.         splits = DocHelper.docCategorySplit(docs)  
  209.         categories = []  
  210.         pcSum = 0  
  211.         for item in splits.items():  
  212.             categories.append(item[0])  
  213.             categoryCount = float(len(item[1]))  
  214.             pc = categoryCount / docTotalCount  
  215.             pcSum += pc * (math.log(pc) / math.log(2))  
  216.         words = []  
  217.         for doc in docs:  
  218.             words += [i for i in doc.getWords()]  
  219.         wordDict = {}  
  220.         for word in words:  
  221.             belongDocs,nobelongDocs = DocHelper.wordDocsSplit(word, docs)  
  222.             wordInDocsCount = len(belongDocs)  
  223.             wordNotInDocsCount = len(nobelongDocs)  
  224.             pctSum = 0;pcntSum = 0  
  225.             for category in categories:  
  226.                 ctCount = len(DocHelper.categorySplit(category, belongDocs)[0])  
  227.                 pct = float(ctCount) / wordInDocsCount  
  228.                 if pct != 0:  
  229.                     pctSum += pct * (math.log(pct) / math.log(2))  
  230.                 cntCount = len(DocHelper.categorySplit(category, nobelongDocs)[0])  
  231.                 if cntCount != 0:  
  232.                     pcnt = float(cntCount) / wordNotInDocsCount  
  233.                     if pcnt != 0:  
  234.                         pcntSum += pcnt * (math.log(pcnt) / math.log(2))  
  235.             pt = float(wordInDocsCount) / docTotalCount  
  236.             pnt = float(wordNotInDocsCount) / docTotalCount  
  237.             ig = -pcSum + pt * pctSum + pnt * pcntSum  
  238.             wordDict[word] = ig  
  239.         return DocHelper.sortWordValueMap(wordDict)  
  240.       
  241.     #计算文档集中词的交叉期望熵  
  242.     @staticmethod  
  243.     def calculateKL(docs):  
  244.         docTotalCount = len(docs)  
  245.         allWords = []  
  246.         categories = []  
  247.         cateToCount = {}  
  248.         wordToCount = {}  
  249.         for doc in docs:  
  250.             cate = doc.getCategory()  
  251.             categories.append(cate)  
  252.             cateCount = cateToCount.get(cate)  
  253.             if cateCount is None:  
  254.                 cateToCount[cate] = 1  
  255.             else:  
  256.                 cateToCount[cate] = cateCount + 1   
  257.             words = doc.getWords()  
  258.             for word in words:  
  259.                 allWords.append(word)  
  260.                 count = wordToCount.get(word)  
  261.                 if count is None:  
  262.                     wordToCount[word] = 1  
  263.                 else :  
  264.                     wordToCount[word] = count + 1  
  265.         allWords = set(allWords)  
  266.         categories = set(categories)  
  267.         wordDict = {}  
  268.         word_len = len(allWords)  
  269.         for word in allWords:  
  270.             pt = float(wordToCount.get(word)) / word_len  
  271.             sum = 0; cd = 0; dd = 0  
  272.             nt = DocHelper.wordInDocsStatistics(word, docs)  
  273.             for category in categories:  
  274.                 cateCount = cateToCount.get(category)  
  275.                 pc = float(cateCount) / docTotalCount  
  276.                 pct = DocHelper.wordCategoryInDocsPercent(word, category, docs)  
  277.                 sum += pct * math.log(pct / pc)  
  278.                 nct = DocHelper.categoryWordStatistics(category, word, docs)  
  279.                 cd += float(nct) / nt  
  280.                 dd += float(nct) / cateCount  
  281.             wordDict[word] = cd * dd * pt * sum  
  282.         return DocHelper.sortWordValueMap(wordDict)      
  283.                   
  284.               
  285.     #计算文档集之间的相似度      
  286.     @staticmethod  
  287.     def calculateSimilar(docs):  
  288.         for doc in docs:  
  289.             topWords = DocHelper.docTopNWords(doc, 20)  
  290.             similarities = []  
  291.             for odoc in docs:  
  292.                 otopWords = DocHelper.docTopNWords(odoc, 20)  
  293.                 words = WordUtils.mergeAndRemoveRepeat(topWords, otopWords);  
  294.                 v1 = DocHelper.docWordsVector(doc, words)  
  295.                 v2 = DocHelper.docWordsVector(odoc, words)  
  296.                 cosine = DistanceUtils.cosine(v1,v2)  
  297.                 similarity = DocSimilarity()  
  298.                 similarity.setName1(doc.getName())  
  299.                 similarity.setName2(odoc.getName())  
  300.                 similarity.setVector1(v1)  
  301.                 similarity.setVector2(v2)  
  302.                 similarity.setCosine(cosine)  
  303.                 similarities.append(similarity)  
  304.             doc.setSimilarities(similarities)  
  305.       
  306.     #根据字典的value字段倒排序              
  307.     @staticmethod  
  308.     def sortWordValueMap(wordValueMap):  
  309.         results = sorted(wordValueMap.items(), key=lambda i : i[1], reverse=True)  
  310.         return results  


[python] view plaincopy
  1. import jieba as ws  
  2.   
  3. #词工具类  
  4. class WordUtils:  
  5.   
  6.     #对文本进行分词  
  7.     @staticmethod  
  8.     def split(input):  
  9.         seg_list = ws.cut(input, cut_all=False)  
  10.         words = []  
  11.         for word in seg_list:  
  12.             words.append(word)  
  13.         return words  
  14.       
  15.     #对文件进行分词  
  16.     @staticmethod  
  17.     def splitFile(path):  
  18.         file = open(path)  
  19.         words = []  
  20.         for line in file.readlines():  
  21.             line = line.strip();  
  22.             if len(line) > 0:  
  23.                 for w in WordUtils.split(line):  
  24.                     words.append(w)  
  25.         file.close()  
  26.         return WordUtils.removeStopWords(words)  
  27.       
  28.     #根据停用词文件移除词集中的停用词  
  29.     @staticmethod  
  30.     def removeStopWords(words):  
  31.         file = open("stopwords.dic")  
  32.         stopwords = []  
  33.         for line in file.readlines():  
  34.             line = line.strip();  
  35.             if len(line) > 0:  
  36.                 stopwords.append(line)  
  37.         file.close()  
  38.         rwords = []  
  39.         for word in words:  
  40.             flag = True  
  41.             for stopword in stopwords:  
  42.                 #if word.encode('utf-8') == stopword.encode('utf-8'):  
  43.                 if word == stopword:  
  44.                     flag = False  
  45.                     break  
  46.             if flag and len(word.strip()) > 0:  
  47.                 rwords.append(word)  
  48.         return rwords  
  49.       
  50.     #词汇总并且去除重复  
  51.     @staticmethod  
  52.     def mergeAndRemoveRepeat(w1, w2):  
  53.         all = [i1 for i1 in w1]  
  54.         all += [i2 for i2 in w2]  
  55.         return [i for i in set(all)]  
  56.         #下面这种方式也可以   
  57.         #all = set(l1) | set(l2)  
  58.         #return [i for i in all]   

测试用例:
[python] view plaincopy
  1. def testTFIDF():  
  2.     path = r'D:\resources\test'  
  3.     docs = DocHelper.genDocs(path)  
  4.     DocHelper.calculateTFIDF(docs)  
  5.     for doc in docs:  
  6.         print '----------'  
  7.         tf = DocHelper.calculateTF(doc)  
  8.         tfidf = doc.getTfidfWords()  
  9.         for item in DocHelper.sortWordValueMap(tf)[0:20]:  
  10.             print '%s-%s-%s' %(item[0],item[1],tfidf.get(item[0]))  
  11.   
  12. def testSimilarity():   
  13.     path = r'D:\resources\test'  
  14.     docs = DocHelper.genDocs(path)  
  15.     DocHelper.calculateTFIDF(docs)  
  16.     DocHelper.calculateSimilar(docs)  
  17.     for doc in docs:  
  18.         print '----------'  
  19.         for similarity in doc.getSimilarities():  
  20.             print '%s-%s-%s' %(similarity.getName1(),\  
  21.                     similarity.getName2(), similarity.getCosine())  
  22.               
  23. def testCHI():  
  24.     path = r'D:\resources\test'  
  25.     docs = DocHelper.genDocs(path)  
  26.     DocHelper.calculateCHI(docs)  
  27.     for doc in docs:  
  28.         print '----------'  
  29.         for item in DocHelper.sortWordValueMap(doc.getCHIWords())[0:10]:  
  30.             print '%s-%s' %(item[0],item[1])  
  31.                   
  32. def testInformationGain():  
  33.     path = r'D:\resources\test'  
  34.     docs = DocHelper.genDocs(path)  
  35.     wordDict = DocHelper.calculateInformationGain(docs)  
  36.     for item in wordDict[0:30]:  
  37.         print '%s-%s' %(item[0],item[1])  
  38.       
  39. def testKL():  
  40.     path = r'D:\resources\test'  
  41.     docs = DocHelper.genDocs(path)  
  42.     wordDict = DocHelper.calculateKL(docs)  
  43.     for item in wordDict[0:30]:  
  44.         print '%s-%s' %(item[0],item[1])  
  45.   
  46. if __name__ == '__main__':  
  47.     print '-----TFIDF-----'   
  48.     testTFIDF()  
  49.     print '-----CHI-----'   
  50.     testCHI()  
  51.     print '-----IG-----'   
  52.     testInformationGain()  
  53.     print '-----KL-----'   
  54.     testKL()  
  55.     print '----------'  
0 0
原创粉丝点击