|
蛙蛙牌自動提取Tag算法 摘要:Tag系統(tǒng)是Web2.0的一個招牌應(yīng)用,如果你有一個經(jīng)營了好幾年的論壇,是不是也想生成自己的一套TAG。別聽他們說什么語義WEB,文本聚類算法,TIIDF,余弦定理,相似度算法啥的高深算法(我一個也沒整明白),跟我來,簡單的計算詞頻來提取tag的效果就很好。 分析;把每個帖子進行分詞,然后把詞的出現(xiàn)頻率倒序排列,取出前N個就作為TAG了。當然要一個板塊一個板塊的提取tag,如果把軍事板塊和情感板塊的帖子混雜在一起提取tag,提取出來的tag相關(guān)性比較差一些,如果分開提取,相關(guān)性要好一些,整體效果好。好多時候做訓(xùn)練算法,語料很重要。先分詞吧,自己寫分詞算法也是弄個詞庫,自己用正向最大匹配來分詞,或者兩個兩個字的來當詞,所以還不如直接用中科院那套呢,直接使用了隱式馬爾可夫算法,效果雖說不是很好吧,也能滿足需求了,對吧。具體測試代碼、分詞組件、詞庫下載見以下鏈接
開始上代碼 namespace WawaSoft.Search.Common![]() ![]() { public sealed class WawaSplitWorder![]() { static List<string> _stopWords = new List<string>(); static NICTCLAS _nictclas; public static void Init()![]() { try![]() { //1、初始化分詞器 _nictclas = new NICTCLAS(); _nictclas.OperateType = eOperateType.OnlySegment; _nictclas.OutputFormat = eOutputFormat.PKU;![]() //2、加載停止詞 using (StreamReader sr = new StreamReader("data\\StopWords.txt", Encoding.Default))![]() { string temp; while ((temp = sr.ReadLine()) != null)![]() { _stopWords.Add(temp); } } } catch (Exception ex)![]() { Trace.TraceError("初始化分詞器錯誤:{0}", ex); } }![]() ![]() /**//// <summary> /// 分詞并去除停止詞 /// </summary> /// <param name="input"></param> /// <returns></returns> public static IEnumerable<string> SplitWords(string input)![]() { Console.WriteLine(input); //預(yù)處理,不處理那個分詞組件有可能內(nèi)存讀寫錯誤,那玩意兒寫的不太健壯,容錯性8行的說,呵呵 input = input.Replace("/", ""); input = input.Replace(".", ""); string result = string.Empty; List<string> ret = null; try![]() { //1、分詞 _nictclas.ParagraphProcessing(input, ref result); ret = new List<string>(![]() result.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries)); //2、去除干擾詞 List<string> needRemove = new List<string>(); foreach (string word in ret)![]() { foreach (string s in _stopWords)![]() { if (string.Compare(s, word, false) == 0)![]() { needRemove.Add(word); break; } } }![]() foreach (string removeWord in needRemove)![]() { ret.Remove(removeWord); } } catch (Exception ex)![]() { //錯誤的時候除了打出錯誤詳細信息后打出出錯的上下文,傳入的參數(shù),臨時變量等有助于從trace里分析錯誤,要不死了也不知道怎么死的 Console.WriteLine("{0}\r\n{1}",input,ex); }![]() return ret; } } }![]() ![]() 計算詞頻 class AutoGenTag![]() ![]() { //大字典,保存每個詞的詞頻,key是詞,value是詞頻 static Dictionary<string,int> _hashlist = new Dictionary<string, int>(10240);![]() public static void Excute()![]() { //1、取出帖子,越多越好,越多提取的準確性越高 IEnumerable<string> source = Dao.GetPostTitles(); foreach (string str in source)![]() { //2、把每個帖子主題分詞 IEnumerable<string> words = WawaSplitWorder.SplitWords(str); if(words == null) continue;![]() //3、把每個詞插入到大字典里,以前存在就把詞頻加1 foreach (string word in words)![]() { if(_hashlist.ContainsKey(word))![]() { _hashlist[word]++; } else![]() { _hashlist.Add(word,0); } } } //4、把大于某個閾值(這里是20)的詞插入數(shù)據(jù) foreach (KeyValuePair<string, int> pair in _hashlist)![]() { //如果一次循環(huán)插入幾萬個詞,SQLSERVE每秒提交的批會很高,有可能CPU瞬間很高,Sleep(0)能讓CPU長得慢點兒,Sleep(1)也行,不過我不知道這兩個的區(qū)別。或者直接 用sqlserver的bilkcopy性能也8錯 Thread.Sleep(0); if (pair.Value > 20)![]() { Console.WriteLine("{0}-{1}",pair.Key,pair.Value); Dao.addtags(pair.Key, pair.Value); } } } }![]() ![]() 代碼寫的比較糙,大家湊合看,都是隨手寫的。最后寫一個sql查出tag并按詞頻倒序排列,選出一個datatable,用datalist一綁定就O了。當然了,我這是提取標簽的土法,大師們看了別吐,呵呵。 |
|
|