機器學習練習(四)——異常檢測

我們的任務是使用高斯模型來檢測數據集中一個未標記(unlabeled)的樣本是否應被視爲異常。 我們從一個簡單的 2 維數據集開始,因此我們可以很容易地可視化這算法的工作原理。 讓我們 導入數據並畫出散點圖。


#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 使用高斯模型來檢測數據集中一個未標記(unlabeled)的樣本是否應被視爲異常
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
from scipy.io import loadmat
from scipy import stats
# atplotlib inline

data = loadmat('data/ex8data1.mat')
X = data['X']
# X.shape
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax1.scatter(X[:,0], X[:,1])
# plt.show()
# 該聚類的中心十分緊密,只有幾個值遠離聚類中心。 在這個簡單的例子中,這些可以被認爲是異常。 爲了弄清楚這些,我們的任務是
# 估計數據中每個特徵的高斯分佈。 爲了定義概率分佈,我們需要兩個東西——均值和方差。 爲了實現這一點,我們將創建一個簡單的
# 函數來計算數據集中每個特徵的均值和方差。
def estimate_gaussian(X):
    mu = X.mean(axis=0)  # 對X的每一列(每一個特徵)計算均值
    sigma = X.var(axis=0)  # 對X的每一列計算方差
    return mu, sigma

mu, sigma = estimate_gaussian(X)
print(mu, sigma)

# 現在有了我們模型的參數,我們需要確定概率閾值,其指示一個樣本是否應該被認爲是異常。 爲此,我們需要使用一組已被標記的驗證
# 數據(其中真正的異常已經被標記出來了),並在不同閾值條件下測試模型識別異常的能力。
Xval = data['Xval']    # 驗證數據
yval = data['yval']    # 分類的標註(0,1 正常,異常)

# fig,ax = plt.subplots()
# ax.scatter(Xval[:,0], Xval[:,1])

# print(Xval)
# Xval.shape, yval.shape
# 需要一種方法能夠在給定參數下計算數據點屬於一個正態分佈的概率

# print(X[:,0][0:50])
dist = stats.norm(mu[0], sigma[0]) # 第一列的均值和方差
dist.pdf(X[:,0])[0:50]     # X點的概率密度

# za = dist.pdf(X[:,0])

p = np.zeros((X.shape[0], X.shape[1]))
p[:,0] = stats.norm(mu[0], sigma[0]).pdf(X[:,0])   # X第一列的概率密度
p[:,1] = stats.norm(mu[1], sigma[1]).pdf(X[:,1])   # X第二列的概率密度


pval = np.zeros((Xval.shape[0], Xval.shape[1]))
pval[:,0] = stats.norm(mu[0], sigma[0]).pdf(Xval[:,0])   # Xval第一列的概率密度
pval[:,1] = stats.norm(mu[1], sigma[1]).pdf(Xval[:,1])
# print(pval)

# 我們需要一個只要給定概率密度值和真標籤就能找出最佳閾值的函數。 爲此,我們需要計算不同的 ϵ 值的 F1 範數。 F1 範數是真正
# ( true positive)、假正(false positive)、假負(false negative)的函數。

# print(pval.min(),pval.max())
# 7.51302142773e-15 0.233334292828

# pre = pval < pval.max()
# print((np.logical_and(pre[10,:] == 1, yval == 0)))
# print([True,True]==1)

def select_threshold(pval, yval):   # 驗證數據兩列的概率密度, 驗證數據的標註
    best_epsilon = 0
    best_f1 = 0
    f1 = 0

    step = (pval.max() - pval.min()) / 100

    for epsilon in np.arange(pval.min(), pval.max(), step):   # 等差數列 起始 步長
        preds = pval < epsilon  # 比較結果賦值給preds
        # (307, 2)的比較結果

        tp = np.sum(np.logical_and(preds == 1, yval == 1)).astype(float)   # 邏輯與、類型轉換  #真正
        # 計數  統計預測1實際1的數目
        fp = np.sum(np.logical_and(preds == 1, yval == 0)).astype(float)  # 假正
        # 驗證數列正常數據中有一點概率密度小於閾值
        fn = np.sum(np.logical_and(preds == 0, yval == 1)).astype(float)  # 假負
        # 驗證數列異常數據中有一點概率密度大於閾值

        # 假正指的是這樣的一個數據實例:我們創建的這個模型預測它應該是正的,但事實相反,實際值卻是負的。同樣地,假負指的
        # 是這樣一個數據實例:我們創建的這個模型預測它應該是負的,但事實相反,實際值卻是正的。
        precision = tp / ((tp + fp)+ 0.0000000001)     # 被模型預測爲正的正樣本/被模型預測爲正的正樣本+被模型預測爲正的負樣本
        recall = tp / (tp + fn)   # 真正例率   正樣本預測結果數 / 全部正樣本實際數
        # FP /(FP + TN) 假正例率    被預測爲正的負樣本結果數 /負樣本實際數
        f1 = (2 * precision * recall) / ((precision + recall)+0.000000000001)

        if f1 > best_f1:
            best_f1 = f1
            best_epsilon = epsilon
    return best_epsilon, best_f1

epsilon, f1 = select_threshold(pval, yval)
print(epsilon,f1)  # 0.00956670600596 0.714285714283
outliers = np.where(p < epsilon)
# outliers = np.where(za<0.04)
# print(outliers)

fig, ax = plt.subplots()
ax.scatter(X[:,0], X[:,1])
ax.scatter(X[outliers[0],0], X[outliers[0],1], s=50, color='r', marker='o')
plt.show()




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