蛙蛙牌自動提取Tag算法

蛙蛙牌自動提取Tag算法

摘要:Tag系統是Web2.0的一個招牌應用,如果你有一個經營了好幾年的論壇,是不是也想生成自己的一套TAG。別聽他們說什麼語義WEB,文本聚類算法,TIIDF,餘弦定理,相似度算法啥的高深算法(我一個也沒整明白),跟我來,簡單的計算詞頻來提取tag的效果就很好。

分析;把每個帖子進行分詞,然後把詞的出現頻率倒序排列,取出前N個就作爲TAG了。當然要一個板塊一個板塊的提取tag,如果把軍事板塊和情感板塊的帖子混雜在一起提取tag,提取出來的tag相關性比較差一些,如果分開提取,相關性要好一些,整體效果好。好多時候做訓練算法,語料很重要。先分詞吧,自己寫分詞算法也是弄個詞庫,自己用正向最大匹配來分詞,或者兩個兩個字的來當詞,所以還不如直接用中科院那套呢,直接使用了隱式馬爾可夫算法,效果雖說不是很好吧,也能滿足需求了,對吧。具體測試代碼、分詞組件、詞庫下載見以下鏈接
http://www.cnblogs.com/edison1024/archive/2006/05/03/390832.html
得點了他那個廣告才能顯示下載地址,你就點吧,人家提供下載也不容易。分詞後要去除停止詞,停止詞自己從網上搜索一份,如果不去除停止詞,最後肯定是“了”,“的”,“我”等詞出現的頻率最高,你不會把這些常用詞做tags吧,呵呵。當然NICTCLAS是可以標註詞性的,你可以分詞後把語氣詞、副詞等虛詞去了,這樣更好一些,但我就懶得做了,直接分詞、去除停止詞兩步。
完了計算每個詞出現的頻率就好說了,弄一個全局的字典,每個詞出現一次增加一個計數,第一次出現先添加到字典,並計數爲0,最後把出現次數在某個閾值以上的詞插入到數據庫裏,這就是你要的tag了,先來看一下我的效果吧(大家別笑哦,我是從一個美女貼圖論壇提取了一些帖子的主題當語料的,爲了不降低博客園的PR值,就貼圖,不貼文字了)。

開始上代碼
先貼分詞

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);
            
            
//預處理,不處理那個分詞組件有可能內存讀寫錯誤,那玩意兒寫的不太健壯,容錯性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)
            
{
                
//錯誤的時候除了打出錯誤詳細信息後打出出錯的上下文,傳入的參數,臨時變量等有助於從trace裏分析錯誤,要不死了也不知道怎麼死的
                Console.WriteLine("{0}/r/n{1}",input,ex);
            }


            
return ret;
        }

    }

}



計算詞頻

class AutoGenTag
{
    
//大字典,保存每個詞的詞頻,key是詞,value是詞頻
    static Dictionary<string,int> _hashlist = new Dictionary<stringint>(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)的詞插入數據
        foreach (KeyValuePair<stringint> pair in _hashlist)
        
{
            
//如果一次循環插入幾萬個詞,SQLSERVE每秒提交的批會很高,有可能CPU瞬間很高,Sleep(0)能讓CPU長得慢點兒,Sleep(1)也行,不過我不知道這兩個的區別。或者直接 用sqlserver的bulkcopy 性能也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了。當然了,我這是提取標籤的土法,大師們看了別吐,呵呵。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章