原理:
1、先给本聚类内的所有文档进行分词,然后用一个字典保存每个词出现的次数
2、遍历每个词,得到每个词在所有文档里的IDF值,和在本聚类内出现的次数(TF)相乘的值
3、用一个字典(key是词,value是TF*IDF权重)来保存所有的词信息,然后按value对字典排序,最后取权重排名靠前的几个词作为关键词测试
数据还是昨天的数据,但每个文章前面都加了个a,所以这个词的IDF肯定很低,如果单村用词频来提取关键词,这个a肯定被当场关键词了,所以要乘以IDF值来调整特征提取的精度。我们要用程序把上面的文档分成3类,并提取每个类的两个关键词
我给TFIDFMeasure类加了一个GetKeyword的方法,第一个参数是传入几个文档id列表,第二个参数是要在这几个文档里提取几个关键词,下面是使用该方法的代码
//4、初始化k-means算法,第一个参数表示输入数据,第二个参数表示要聚成几个类
WawaKMeans kmeans = new WawaKMeans(data, K);
//5、开始迭代
kmeans.Start();
//6、获取聚类结果并输出
WawaCluster[] clusters = kmeans.Clusters; StringBuilder sb = new StringBuilder(); foreach (WawaCluster cluster in clusters) { List<int> members = cluster.CurrentMembership; //获取该聚类的关键词并打印 IEnumerable<string> keywords = tf.GetKeyword(cluster.CurrentMembership, 2); StringBuilder sbTemp = new StringBuilder(); sbTemp.Append("---------"); foreach (string s in keywords) { sbTemp.AppendFormat("{0},", s); } sbTemp.Append("-------\r\n"); Console.WriteLine(sbTemp); //打印该聚类的成员 sb.Append(sbTemp.ToString()); foreach (int i in members) { Console.WriteLine(docs); sb.AppendFormat("{0}\r\n", docs); } } </string></int>
再看GetKeyword方法的实现
/// <summary> /// 获取某组文档的关键词 /// </summary> /// <param name="arr"/> /// <param name="count"/> /// <returns></returns> public IEnumerable<string> GetKeyword(List<int> arr, int count) { //1、给每个文档分词并保存在一个列表里 List<string> allWords = new List</string><string>(); foreach (int i in arr) { //这里把一个文档里出现的多个词进行消重 allWords.AddRange(GetDistinctWords(_tokenizer.Partition(_docs))); } //2、用一个字典保存词的词频,key是词,value是重复次数 Dictionary</string><string , int> tfDict = SortByDuplicateCount(allWords); //3、遍历已排序的词频字典,并获取每个词的IDF值,并把更新后的结果放入一个tfidfDict词典 //该词典的key是词,value是tfidf值 Dictionary</string><string ,float> tfidfDict = new Dictionary</string><string , float>(tfDict.Count); foreach (KeyValuePair</string><string , int> pair in tfDict) { int tremIndex; if(_tremIndex.TryGetValue(pair.Key,out tremIndex)) { float idf = GetInverseDocumentFrequency(tremIndex); tfidfDict.Add(pair.Key, pair.Value * idf); } } //4、给tfidf字典俺权重排序 tfidfDict = GetSortByValueDict(tfidfDict); //5、更新要提取的关键词数量 int keywordCount = count; if (keywordCount > tfidfDict.Count) keywordCount = tfidfDict.Count; //6、用一个数组保存tfidf字典的keys,这些key已排序 string[] keywordArr = new string[tfidfDict.Count]; tfidfDict.Keys.CopyTo(keywordArr,0); //7、在关键词数组里取出前几个关键词返回给调用者 List</string><string> result = new List</string><string>(keywordCount); int tempCount = 0; foreach (string str in keywordArr) { tempCount++; result.Add(str); if(tempCount >=keywordCount) break; } return result; } </string></int></string>
这里面用到一个SortByDuplicateCount方法,是对一个集合里的元素按重复次数排序,输出一个字典,字典的key是原始元 素,value是出现次数,并按出现次数从大到小排序,像 { “abcd”, “ab”, “b”, “a”, “abcd”, “ab”, “ab”, “ab”, “cd”, “cd”, “cd” }这样一个集合应该输入如下结果。
ab-4
cd-3
abcd-2
b-1
a-1
原理是先用一个字典计算每个元素的出现次数,然后把该字典按value的大小排序,下面是实现代码
/// <summary> /// 把一个集合按重复次数排序 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="inputList"/> /// <returns></returns> public static Dictionary<t , int> SortByDuplicateCount</t><t>(IList</t><t> inputList) { //用于计算每个元素出现的次数,key是元素,value是出现次数 Dictionary</t><t , int> distinctDict = new Dictionary</t><t , int>(); for (int i = 0; i < inputList.Count; i++) { //这里没用trygetvalue,会计算两次hash if (distinctDict.ContainsKey(inputList)) distinctDict[inputList]++; else distinctDict.Add(inputList, 1); } Dictionary<T, int> sortByValueDict = GetSortByValueDict(distinctDict); return sortByValueDict; } </t>
这里用到一个把一个字典按值的大小排序的方法GetSortByValueDict,代码如下,是泛型的
/// <summary> /// 把一个字典俺value的顺序排序 /// </summary> /// <typeparam name="K"></typeparam> /// <typeparam name="V"></typeparam> /// <param name="distinctDict"/> /// <returns></returns> public static Dictionary<k , V> GetSortByValueDict</k><k ,V>(IDictionary</k><k , V> distinctDict) { //用于给tempDict.Values排序的临时数组 V[] tempSortList = new V[distinctDict.Count]; distinctDict.Values.CopyTo(tempSortList, 0); Array.Sort(tempSortList); //给数据排序 Array.Reverse(tempSortList);//反转 //用于保存按value排序的字典 Dictionary</k><k , V> sortByValueDict = new Dictionary</k><k , V>(distinctDict.Count); for (int i = 0; i < tempSortList.Length; i++) { foreach (KeyValuePair<K, V> pair in distinctDict) { //比较两个泛型是否相当要用Equals,不能用==操作符 if (pair.Value.Equals(tempSortList) && !sortByValueDict.ContainsKey(pair.Key)) sortByValueDict.Add(pair.Key, pair.Value); } } return sortByValueDict; } </k>
对一个文章内出现的多个词进行消重是因为如果一个文章里堆叠关键词会影响本聚类关键词提取的准确性,所以要排重,算法如下,也是泛型的
/// <summary> /// 对一个数组进行排重 /// </summary> /// <param name="scanKeys"/> /// <returns></returns> public static IEnumerable<t> GetDistinctWords</t><t>(IEnumerable</t><t> scanKeys) { T temp = default(T); if (scanKeys.Equals(temp)) return new T[0]; else { Dictionary</t><t , T> fixKeys = new Dictionary</t><t , T>(); foreach (T key in scanKeys) { fixKeys[key] = key; } T[] result = new T[fixKeys.Count]; fixKeys.Values.CopyTo(result, 0); return result; } } </t>
丈夫喝酒时有个坏习惯,他总是一口就要喝掉一杯。妻子对此很担心,于是她想出一个好办法。她为丈夫买回一只美人杯。当这杯子装满酒时,杯底就会出现美人,但丈夫还是像以往那样一口喝下一杯。妻子劝他说:“别喝干,喝干了就见不着杯底的美人了。”丈夫回答说:“不行,我实在不忍心把美人浸在酒中! ”
27、在欣赏、赞美和认可对方的同时,也不妨让自己放得开一些,适度来些自夸。这样做不仅会让自己更加自信、可爱,而且会给普通的自己罩上一个独特别致的光环,让对方更容易看到自己的优点。[标签:标题]
你如果现在是一个人,我祝你元旦
.玫瑰象征幸福甜蜜,牡丹寓意富贵华丽,百合蕴含百年好和,月季代表四季如意。新婚大喜日,统统送给你。四花陪伴你,婚姻好惬意!
不必惊吓,本是鬼节,不必静坐,本是闹节,不必郁闷,本该轻松,不必庄重,本需装扮胡来,万圣佳节,需要的是放开,装扮的是精彩,祝你玩出个性,乐到开怀。
让短信装满我的祝福,让文字写出我的关怀,让手机发出我的愿望!祝朋友生日快乐!在这个日子里,一定要很开心,很幸福才可以哦!祝福你!
捧腹网是中国领先的笑话幽默分享网站,捧腹致力于打造一个分享各类欢乐内容的互动平台,让我们一起: “捧腹开怀、乐享人生”!搞笑,社会