from : http://blog.csdn.net/lsldd/article/details/41551797
在本系列文章中提到過用Python開始機器學習(3:數據擬合與廣義線性回歸)中提到過回歸算法來進行數值預測。邏輯回歸算法本質還是回歸,只是其引入了邏輯函數來幫助其分類。實踐發現,邏輯回歸在文本分類領域表現的也很優秀。現在讓我們來一探究竟。
1、邏輯函數
假設數據集有n個獨立的特征,x1到xn為樣本的n個特征。常規的回歸算法的目標是擬合出一個多項式函數,使得預測值與真實值的誤差最小:
而我們希望這樣的f(x)能夠具有很好的邏輯判斷性質,最好是能夠直接表達具有特征x的樣本被分到某類的概率。比如f(x)>0.5的時候能夠表示x被分為正類,f(x)<0.5表示分為反類。而且我們希望f(x)總在[0, 1]之間。有這樣的函數嗎?
sigmoid函數就出現了。這個函數的定義如下:
先直觀的了解一下,sigmoid函數的圖像如下所示(來自http://computing.dcu.ie/~humphrys/Notes/Neural/sigmoid.html):
sigmoid函數具有我們需要的一切優美特性,其定義域在全體實數,值域在[0, 1]之間,並且在0點值為0.5。
那么,如何將f(x)轉變為sigmoid函數呢?令p(x)=1為具有特征x的樣本被分到類別1的概率,則p(x)/[1-p(x)]被定義為讓步比(odds ratio)。引入對數:
上式很容易就能把p(x)解出來得到下式:
現在,我們得到了需要的sigmoid函數。接下來只需要和往常的線性回歸一樣,擬合出該式中n個參數c即可。
2、測試數據
測試數據我們仍然選擇康奈爾大學網站的2M影評數據集。
在這個數據集上我們已經測試過KNN分類算法、朴素貝葉斯分類算法。現在我們看看羅輯回歸分類算法在處理此類情感分類問題效果如何。
同樣的,我們直接讀入保存好的movie_data.npy和movie_target.npy以節省時間。
3、代碼與分析
邏輯回歸的代碼如下:
- # -*- coding: utf-8 -*-
- from matplotlib import pyplot
- import scipy as sp
- import numpy as np
- from matplotlib import pylab
- from sklearn.datasets import load_files
- from sklearn.cross_validation import train_test_split
- from sklearn.feature_extraction.text import CountVectorizer
- from sklearn.feature_extraction.text import TfidfVectorizer
- from sklearn.naive_bayes import MultinomialNB
- from sklearn.metrics import precision_recall_curve, roc_curve, auc
- from sklearn.metrics import classification_report
- from sklearn.linear_model import LogisticRegression
- import time
- start_time = time.time()
- #繪制R/P曲線
- def plot_pr(auc_score, precision, recall, label=None):
- pylab.figure(num=None, figsize=(6, 5))
- pylab.xlim([0.0, 1.0])
- pylab.ylim([0.0, 1.0])
- pylab.xlabel('Recall')
- pylab.ylabel('Precision')
- pylab.title('P/R (AUC=%0.2f) / %s' % (auc_score, label))
- pylab.fill_between(recall, precision, alpha=0.5)
- pylab.grid(True, linestyle='-', color='0.75')
- pylab.plot(recall, precision, lw=1)
- pylab.show()
- #讀取
- movie_data = sp.load('movie_data.npy')
- movie_target = sp.load('movie_target.npy')
- x = movie_data
- y = movie_target
- #BOOL型特征下的向量空間模型,注意,測試樣本調用的是transform接口
- count_vec = TfidfVectorizer(binary = False, decode_error = 'ignore',\
- stop_words = 'english')
- average = 0
- testNum = 10
- for i in range(0, testNum):
- #加載數據集,切分數據集80%訓練,20%測試
- x_train, x_test, y_train, y_test\
- = train_test_split(movie_data, movie_target, test_size = 0.2)
- x_train = count_vec.fit_transform(x_train)
- x_test = count_vec.transform(x_test)
- #訓練LR分類器
- clf = LogisticRegression()
- clf.fit(x_train, y_train)
- y_pred = clf.predict(x_test)
- p = np.mean(y_pred == y_test)
- print(p)
- average += p
- #准確率與召回率
- answer = clf.predict_proba(x_test)[:,1]
- precision, recall, thresholds = precision_recall_curve(y_test, answer)
- report = answer > 0.5
- print(classification_report(y_test, report, target_names = ['neg', 'pos']))
- print("average precision:", average/testNum)
- print("time spent:", time.time() - start_time)
- plot_pr(0.5, precision, recall, "pos")
代碼運行結果如下:
0.8
0.817857142857
0.775
0.825
0.807142857143
0.789285714286
0.839285714286
0.846428571429
0.764285714286
0.771428571429
precision recall f1-score support
neg 0.74 0.80 0.77 132
pos 0.81 0.74 0.77 148
avg / total 0.77 0.77 0.77 280
average precision: 0.803571428571
time spent: 9.651551961898804
首先注意我們連續測試了10組測試樣本,最后統計出准確率的平均值。另外一種好的測試方法是K折交叉檢驗(K-Fold)。這樣都能更加准確的評估分類器的性能,考察分類器對噪音的敏感性。
其次我們注意看最后的圖,這張圖就是使用precision_recall_curve繪制出來的P/R曲線(precition/Recall)。結合P/R圖,我們能對邏輯回歸有更進一步的理解。
前文我們說過,通常我們使用0.5來做划分兩類的依據。而結合P/R分析,閾值的選取是可以更加靈活和優秀的。
在上圖可以看到,如果選擇的閾值過低,那么更多的測試樣本都將分為1類。因此召回率能夠得到提升,顯然准確率犧牲相應准確率。
比如本例中,或許我會選擇0.42作為划分值——因為該點的准確率和召回率都很高。
最后給一些比較好的資源:
浙大某女學霸的博客!記錄的斯坦福Andrew老師主講的LR公開課筆記:http://blog.csdn.net/abcjennifer/article/details/7716281
一個總結LR還不錯的博客:http://xiamaogeng.blog.163.com/blog/static/1670023742013231197530/
Sigmoid函數詳解:http://computing.dcu.ie/~humphrys/Notes/Neural/sigmoid.html