來源引用:https://blog.csdn.net/han_xiaoyang/article/details/50629608
1、引言
貝葉斯是經典的機器學習算法,朴素貝葉斯經常運用於機器學習的案例。比如說
文本分類/垃圾郵件的分類/情感分析:在文本分類中,貝斯依舊占有一席之地,因為文本數據中,分布獨立這個假設基本上成立的。
推薦系統:朴素貝葉斯和協同過濾一起使用,經常出現在推薦系統。以后有機會會好好寫一篇關於推薦系統的文章。
值得提醒的,以下部分點是要知道的:
- 數據要服從正態分布,
- 使用拉普斯平滑來處理測試數據中的0頻次項
- sklearn中的可調參數很少,只有拉普斯平滑因子alpha,類別先驗概率class_prior和預算數據類別先驗fit_prior。所以建議加強特征工程的操作來完善模型。
- 集成方法對貝葉斯沒有用,因為集成方法是用來減少過擬合的,減少variance的,而貝葉斯沒有variance可以減少。
在sklearn中分為三類先驗:高斯分布,多項式分布,伯努利分布
這三個類適用的分類場景各不相同,一般來說,
- 如果樣本特征的分布大部分是連續值,使用GaussianNB會比較好。
- 如果如果樣本特征的分大部分是多元離散值,使用MultinomialNB比較合適。
- 如果樣本特征是二元離散值或者很稀疏的多元離散值,應該使用BernoulliNB。
接下來分析下kaggle比賽里面的舊金山犯罪分類預測問題。
給出時間,地點,街區等特征來推測舊金山下一個犯罪類型是什么。
來做一個小小的demo
import pandas as pd import numpy as np #用pandas載入csv訓練數據,並解析第一列為日期格式 train=pd.read_csv('../input/train.csv', parse_dates = ['Dates']) test=pd.read_csv('../input/test.csv', parse_dates = ['Dates']) train import pandas as pd import numpy as np from sklearn.cross_validation import train_test_split from sklearn import preprocessing #用LabelEncoder對不同的犯罪類型編號 leCrime = preprocessing.LabelEncoder() crime = leCrime.fit_transform(train.Category) #因子化星期幾,街區,小時等特征,就是one hot編碼 days = pd.get_dummies(train.DayOfWeek) district = pd.get_dummies(train.PdDistrict) hour = train.Dates.dt.hour hour = pd.get_dummies(hour) #組合特征 trainData = pd.concat([hour, days, district], axis=1) trainData['crime']=crime #對於測試數據做同樣的處理 days = pd.get_dummies(test.DayOfWeek) district = pd.get_dummies(test.PdDistrict) hour = test.Dates.dt.hour hour = pd.get_dummies(hour) testData = pd.concat([hour, days, district], axis=1) trainData from sklearn.cross_validation import train_test_split from sklearn import preprocessing from sklearn.metrics import log_loss from sklearn.naive_bayes import BernoulliNB from sklearn.linear_model import LogisticRegression import time # 只取星期幾和街區作為分類器輸入特征 features = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', 'BAYVIEW', 'CENTRAL', 'INGLESIDE', 'MISSION', 'NORTHERN', 'PARK', 'RICHMOND', 'SOUTHERN', 'TARAVAL', 'TENDERLOIN'] # 分割訓練集(3/5)和測試集(2/5) training, validation = train_test_split(trainData, train_size=.60) #朴素貝葉斯建模,計算log_loss model = BernoulliNB() nbStart = time.time() model.fit(training[features], training['crime']) nbCostTime = time.time() - nbStart predicted = np.array(model.predict_proba(validation[features]))
#predict, predict_proba, predict_log_probas三種方法的區別 print("朴素貝葉斯建模耗時 %f 秒" %(nbCostTime)) print("朴素貝葉斯log損失為 %f" %(log_loss(validation['crime'], predicted))) #邏輯回歸建模,計算log_loss model = LogisticRegression(C=.01) lrStart= time.time() model.fit(training[features], training['crime']) lrCostTime = time.time() - lrStart predicted = np.array(model.predict_proba(validation[features]))
print("邏輯回歸建模耗時 %f 秒" %(lrCostTime)) print("邏輯回歸log損失為 %f" %(log_loss(validation['crime'], predicted)))
然后另一個經典應用是情感分析,kaggle類似的比賽就是 Bag of Words Meets Bags of Popcorn
給出各個用戶對電影的評價語句來判斷對該電影的評價是好還是壞。
我們知道DL的效果是好,但是耗時耗資源,貝葉斯建模快而且效果還可以。
首先我們explore下數據,train集數據包含三部分,分別是id,sentiment(好壞),review(內容),根據kaggle的官方指導,要對評論進行處理:去掉Html的標簽,‘/r’ 的處理,詞語轉化處理
import re #正則表達式
from bs4 import BeautifulSoup #html標簽處理 import pandas as pd def review_to_wordlist(review): ''' 把IMDB的評論轉成詞序列 ''' # 去掉HTML標簽,拿到內容 review_text = BeautifulSoup(review).get_text() # 用正則表達式取出符合規范的部分 review_text = re.sub("[^a-zA-Z]"," ", review_text) # 小寫化所有的詞,並轉成詞list words = review_text.lower().split() # 返回words return words # 使用pandas讀入訓練和測試csv文件
# “header = 0”表示文件的第一行包含列名,“delimiter = \t”表示字段由制表符分隔,quoting = 3表示Python忽略雙引號,否則可能會遇到錯誤。
train = pd.read_csv('../input/labeledTrainData.tsv', header=0, delimiter="\t", quoting=3) test = pd.read_csv('../input/testData.tsv', header=0, delimiter="\t", quoting=3 ) # 取出情感標簽,positive/褒 或者 negative/貶 y_train = train['sentiment'] # 將訓練和測試數據都轉成詞list train_data = []
# xrange 用法與 range 完全相同,所不同的是生成的不是一個list對象,而是一個生成器。不用事先占用大內存。 for i in xrange(0,len(train['review'])): train_data.append(" ".join(review_to_wordlist(train['review'][i]))) test_data = [] for i in xrange(0,len(test['review'])): test_data.append(" ".join(review_to_wordlist(test['review'][i])))
接下來進行特征處理
評論經過上面的處理后還是一串字符串,要把它變成數字才好進行模型擬合。kaggle中的引導是使用word2vec的特征抽取方式,當然還有其它的特征抽取方法,比如說利用互信息的提取,有點類似決策樹的特征判斷。這里的話,使用sklearn的一種文本檢索有效的方法:TF-IDF向量法。該方法會把電影評論轉化成一個TF-IDF向量。簡要的解釋是,TF-IDF是一種統計方法,用以評估一字詞(或者n-gram)對於一個文件集或一個語料庫中的其中一份文件的重要程度。字詞的重要性隨着它在文件中出現的次數成正比增加,但同時會隨着它在語料庫中出現的頻率成反比下降。
以下是在sklearn的具體解釋,以后會整理出具體的用法:
http://sklearn.apachecn.org/cn/0.19.0/modules/feature_extraction.html#text-feature-extraction
具體以下代碼是去掉停用詞,在單詞級別上拓展到2元語言模型
from sklearn.feature_extraction.text import TfidfVectorizer as TFIV # 初始化TFIV對象,去停用詞,加2元語言模型 tfv = TFIV(min_df=3, max_features=None, strip_accents='unicode', analyzer='word',token_pattern=r'\w{1,}', ngram_range=(1, 2), use_idf=1,smooth_idf=1,sublinear_tf=1, stop_words = 'english') # 合並訓練和測試集以便進行TFIDF向量化操作 X_all = train_data + test_data len_train = len(train_data) # 這一步有點慢 tfv.fit(X_all) X_all = tfv.transform(X_all) # 恢復成訓練集和測試集部分 X = X_all[:len_train] X_test = X_all[len_train:]
邏輯回歸和貝葉斯模型擬合:
# 多項式朴素貝葉斯 from sklearn.naive_bayes import MultinomialNB as MNB model_NB = MNB() model_NB.fit(X, y_train) MNB(alpha=1.0, class_prior=None, fit_prior=True) from sklearn.cross_validation import cross_val_score import numpy as np print "多項式貝葉斯分類器20折交叉驗證得分: ", np.mean(cross_val_score(model_NB, X, y_train, cv=20, scoring='roc_auc')) # 多項式貝葉斯分類器20折交叉驗證得分: 0.950837239 # 邏輯回歸 from sklearn.linear_model import LogisticRegression as LR from sklearn.grid_search import GridSearchCV # 設定grid search的參數 grid_values = {'C':[30]} # 設定打分為roc_auc model_LR = GridSearchCV(LR(penalty = 'L2', dual = True, random_state = 0), grid_values, scoring = 'roc_auc', cv = 20) model_LR.fit(X,y_train) # 20折交叉驗證,開始漫長的等待... GridSearchCV(cv=20, estimator=LogisticRegression(C=1.0, class_weight=None, dual=True, fit_intercept=True, intercept_scaling=1, penalty='L2', random_state=0, tol=0.0001), fit_params={}, iid=True, loss_func=None, n_jobs=1, param_grid={'C': [30]}, pre_dispatch='2*n_jobs', refit=True, score_func=None, scoring='roc_auc', verbose=0) #輸出結果 print model_LR.grid_scores_ #[mean: 0.96459, std: 0.00489, params: {'C': 30}]
