官术网_书友最值得收藏!

1.5 什么是分類

分類是數據挖掘領域最為常用的方法之一,不論是實際應用還是科研,都少不了它的身影。對于分類問題,我們通常能拿到表示實際對象或事件的數據集,我們知道數據集中每一條數據所屬的類別,這些類別把一條條數據劃分為不同的類。什么是類別?類別的值又是怎么回事?我們來看下面幾個例子。

? 根據檢測數據確定植物的種類。類別的值為“植物屬于哪個種類?”。

? 判斷圖像中有沒有狗。類別是“圖像里有狗嗎?”。

? 根據化驗結果,判斷病人有沒有患上癌癥。類別是“病人得癌癥了嗎?”。

上述三個問題中有兩個是二值(是/否)問題,但正如第一個確定植物類別的問題,多個類別的情況也很常見。

分類應用的目標是,根據已知類別的數據集,經過訓練得到一個分類模型,再用模型對類別未知的數據進行分類。例如,我們可以對收到的郵件進行分類,標注哪些是自己希望收到的,哪些是垃圾郵件,然后用這些數據訓練分類模型,實現一個垃圾郵件過濾器,這樣以后再收到郵件,就不用自己去確認它是不是垃圾郵件了,過濾器就能幫你搞定。

1.5.1 準備數據集

我們接下來將使用著名的Iris植物分類數據集。這個數據集共有150條植物數據,每條數據都給出了四個特征:sepal length、sepal width、petal length、petal width(分別表示萼片和花瓣的長與寬),單位均為cm。這是數據挖掘中的經典數據集之一(1936年就用到了數據挖掘領域!)。該數據集共有三種類別:Iris Setosa(山鳶尾)、Iris Versicolour(變色鳶尾)和Iris Virginica(維吉尼亞鳶尾)。我們這里的分類目的是根據植物的特征推測它的種類。

scikit-learn庫內置了該數據集,可直接導入。

     from sklearn.datasets import load_iris
     dataset = load_iris()
     X = dataset.data
     y = dataset.target

用print(dataset.DESCR)命令查看數據集,大概了解一下,包括特征的說明。

數據集中各特征值為連續型,也就是有無數個可能的值。測量得到的數據就是這個樣子,比如,測量結果可能是1、1.2或1.25,等等。連續值的另一個特點是,如果兩個值相近,表示相似度很大。一種萼片長1.2cm的植物跟一種萼片寬1.25cm的植物很相像。

與此相反,類別的取值為離散型。雖然常用數字表示類別,但是類別值不能根據數值大小比較相似性。Iris數據集用不同的數字表示不同的類別,比如類別0、1、2分別表示Iris Setosa、Iris Versicolour、Iris Virginica。但是這不能說明前兩種植物,要比第一種和第三種更相近——盡管單看表示類別的數字時確實如此。在這里,數字表示類別,只能用來判斷兩種植物是否屬于同一種類別,而不能說明是否相似。

當然,還有其他類型的特征,后續章節會講到其中幾種。

數據集的特征為連續值,而我們即將使用的算法使用類別型特征值,因此我們需要把連續值轉變為類別型,這個過程叫作離散化。

最簡單的離散化算法,莫過于確定一個閾值,將低于該閾值的特征值置為0,高于閾值的置為1。我們把某項特征的閾值設定為該特征所有特征值的均值。每個特征的均值計算方法如下。

     attribute_means = X.mean(axis=0)

我們得到了一個長度為4的數組,這正好是特征的數量。數組的第一項是第一個特征的均值,以此類推。接下來,用該方法將數據集打散,把連續的特征值轉換為類別型。

     X_d = np.array(X >= attribute_means, dtype='int')

后面的訓練和測試,都將使用新得到的X_d數據集(打散后的數組X),而不再使用原來的數據集(X)。

1.5.2 實現OneR算法

OneR算法的思路很簡單,它根據已有數據中,具有相同特征值的個體最可能屬于哪個類別進行分類。OneR是One Rule(一條規則)的簡寫,表示我們只選取四個特征中分類效果最好的一個用作分類依據。后續章節中的分類算法比起OneR要復雜很多,但這個看似不起眼的簡單算法,在很多真實數據集上表現得也不凡。

算法首先遍歷每個特征的每一個取值,對于每一個特征值,統計它在各個類別中的出現次數,找到它出現次數最多的類別,并統計它在其他類別中的出現次數。

舉例來說,假如數據集的某一個特征可以取0或1兩個值。數據集共有三個類別。特征值為0的情況下,A類有20個這樣的個體,B類有60個,C類也有20個。那么特征值為0的個體最可能屬于B類,當然還有40個個體確實是特征值為0,但是它們不屬于B類。將特征值為0的個體分到B類的錯誤率就是40%,因為有40個這樣的個體分別屬于A類和C類。特征值為1時,計算方法類似,不再贅述;其他各特征值最可能屬于的類別及錯誤率的計算方法也一樣。

統計完所有的特征值及其在每個類別的出現次數后,我們再來計算每個特征的錯誤率。計算方法為把它的各個取值的錯誤率相加,選取錯誤率最低的特征作為唯一的分類準則(OneR),用于接下來的分類。

現在,我們就來實現該算法。首先創建一個函數,根據待預測數據的某項特征值預測類別,并給出錯誤率。在這之前需要導入前面用過的defaultdict和itemgetter模塊。

     from collections import defaultdict
     from operator import itemgetter

下面創建函數聲明,參數分別是數據集、類別數組、選好的特征索引值、特征值。

     def train_feature_value(X, y_true, feature_index, value):

接下來遍歷數據集中每一條數據(代表一個個體),統計具有給定特征值的個體在各個類別中的出現次數。

         class_counts = defaultdict(int)
         for sample, y in zip(X, y_true):
             if sample[feature_index] == value:
                 class_counts[y] += 1

對class_counts字典進行排序,找到最大值,就能找出具有給定特征值的個體在哪個類別中出現次數最多。

         sorted_class_counts = sorted(class_counts.items(),
           key=itemgetter(1), reverse=True)
         most_frequent_class = sorted_class_counts[0][0]

接著計算該條規則的錯誤率。OneR算法會把具有該項特征值的個體統統分到上面找到的出現次數最多的類別中。錯誤率為具有該特征值的個體在其他類別(除出現次數最多的類別之外的)中的出現次數,它表示的是分類規則不適用的個體的數量。

     incorrect_predictions = [class_count for class_value, class_count
                             in class_counts.items()
                             if class_value != most_frequent_class]
     error = sum(incorrect_predictions)

最后返回使用給定特征值得到的待預測個體的類別和錯誤率。

         return most_frequent_class, error

對于某項特征,遍歷其每一個特征值,使用上述函數,就能得到預測結果和每個特征值所帶來的錯誤率,然后把所有錯誤率累加起來,就能得到該特征的總錯誤率。我們來定義一個函數,實現這些操作。

函數聲明如下,這次只用到三個參數,上面已經介紹過。

     def train_on_feature(X, y_true, feature_index):

接下來找出給定特征共有幾種不同的取值。下面這行代碼X[:,feature_index]以數組的形式返回由feature_index所指的列。然后用set函數將數組轉化為集合,從而找出有幾種不同的取值。

         values = set(X[:,feature_index])

再創建字典predictors,用作預測器。字典的鍵為特征值,值為類別。比如鍵為1.5、值為2,表示特征值為1.5的個體屬于類別2。創建errors列表,存儲每個特征值的錯誤率。

         predictors = {}
         errors = []

函數的主干部分遍歷選定特征的每個不同的特征值,用前面定義的train_feature_value()函數找出每個特征值最可能的類別,計算錯誤率,并將其分別保存到預測器predictors和errors中。

         for current_value in values:
           most_frequent_class, error = train_feature_value(X,
             y_true, feature_index, current_value)
           predictors[current_value] = most_frequent_class
           errors.append(error)

最后,計算該規則的總錯誤率,返回預測器及總錯誤率。

         total_error = sum(errors)
         return predictors, total_error

1.5.3 測試算法

上一節中親和性分析算法的目標是從數據集中發現用以指導實踐的規則。而分類問題有所不同,我們想建立一個能夠根據已有知識對沒有見過的個體進行分類的模型。

我們因此把機器學習流程分為兩步:訓練和測試。在訓練階段,我們從數據集中取一部分數據,創建模型。在測試階段,我們測試模型在數據集上的分類效果。考慮到模型的目標是對新個體進行分類,因此不能用測試數據訓練模型,因為這樣做容易導致過擬合問題。

過擬合指的是模型在訓練集上表現很好,但對于沒有見過的數據表現很差。解決方法很簡單:千萬不要用訓練數據測試算法。詳細的處理方法很復雜,后續章節會有所涉及;我們這里簡單化處理,把數據集分為兩個小部分,分別用于訓練和測試。具體流程接下來會介紹。

scikit-learn庫提供了一個將數據集切分為訓練集和測試集的函數。

     from sklearn.cross_validation import train_test_split

該函數根據設定的比例(默認把數據集的25%作為測試集)將數據集隨機切分為兩部分,以確保測試結果的可信度。

     X_train, X_test, y_train, y_test = train_test_split(X_d, y, random_
     state=14)

這樣我們就得到了兩個數據集:訓練集X_train和測試集X_test。y_train和y_test分別為以上兩個數據集的類別信息。

切分函數的第三個參數random_state用來指定切分的隨機狀態。每次切分,使用相同的隨機狀態,切分結果相同。雖然看起來是隨機的,但是它所使用的算法是確定的,輸出結果也是一致的。在書中所有用到random_state的地方,我建議你跟我使用同一個值,這樣你得到的結果就應該跟我的相同,這樣便于你驗證結果。把random_state的值設置為none,每次切分結果將是真正隨機的。

接下來,計算所有特征值的目標類別(預測器)。記得只使用訓練集。遍歷數據集中的每個特征,使用我們先前定義的函數train_on_feature()訓練預測器,計算錯誤率。

     all_predictors = {}
     errors = {}
     for feature_index in range(X_train.shape[1]):
       predictors, total_error = train_on_feature(X_train, y_train,
         feature_index)
       all_predictors[feature_index] = predictors
       errors[feature_index] = total_error

然后找出錯誤率最低的特征,作為分類的唯一規則。

     best_variable, best_error = sorted(errors.items(), key=itemgetter(1))
     [0]

對預測器進行排序,找到最佳特征值,創建model模型。

     model = {'variable': best_variable,
       'predictor': all_predictors[best_variable]}

model模型是一個字典結構,包含兩個元素:用于分類的特征和預測器。有了模型后,就可以根據特征值對沒有見過的數據進行分類。示例如下:

     variable = model['variable']
     predictor = model['predictor']
     prediction = predictor[int(sample[variable])]

我們經常需要一次對多條數據進行預測,為此用上面的代碼實現了下面這個函數,通過遍歷數據集中的每條數據來完成預測。

     def predict(X_test, model):
         variable = model['variable']
         predictor = model['predictor']
         y_predicted = np.array([predictor[int(sample[variable])] for
           sample in X_test])
         return y_predicted

我們用上面這個函數預測測試集中每條數據的類別。

     y_predicted = predict(X_test, model)

比較預測結果和實際類別,就能得到正確率是多少。

     accuracy = np.mean(y_predicted == y_test) * 100
     print("The test accuracy is {:.1f}%".format(accuracy))

輸出結果為65.8%,對于只使用一條規則來說,這就很不錯了!

主站蜘蛛池模板: 天气| 临潭县| 贵定县| 五华县| 淳化县| 肥东县| 洛阳市| 宜城市| 阳东县| 巫溪县| 玉树县| 大关县| 右玉县| 祁门县| 威海市| 谷城县| 恭城| 乌鲁木齐县| 绍兴县| 彩票| 吉林省| 阿勒泰市| 长葛市| 宜兰县| 邢台市| 乐东| 永安市| 平泉县| 浮梁县| 左贡县| 图们市| 九江县| 舞钢市| 丰顺县| 巴塘县| 喀喇| 张北县| 金寨县| 山东省| 普格县| 阳谷县|