zoukankan      html  css  js  c++  java
  • EX8:异常检测与推荐系统的练习

    EX8 异常检测与推荐系统的练习

    ​ 在本练习中,首先将异常检测算法应用于检测网络中的故障服务器。 在第二部分中,将使用协作过滤来构建电影推荐系统。

    1.异常检测-Anomaly detection

    ​ 在本节练习中,将实施异常检测算法来检测服务器计算机中的异常行为。该功能测量每个服务器的响应的吞吐量-throughput(mb / s)和延迟-latency(ms)。当服务器正在运行时,共收集了m = 307个例子,说明它们的行为方式,因此有一个未标记的数据集{(x^{(1)},...,x^{(m)})}。这里绝大多数是正常运行的(非异常)示例,但也可能存在一些在此数据集中异常运行的服务器示例。

    ​ 我们将使用高斯模型来检测数据集中的异常示例。首先从2D数据集开始,因为它可以更方便地可视化算法正在做什么。在该数据集上,高斯分布的模型是适合的,然后找到具有非常低概率的值,从而可以将其视为异常。之后,我们会将异常检测算法应用于具有许多维度的较大数据集。

    ​ 首先,可视化数据集如下:

    ![1.jpg](http://wx2.sinaimg.cn/mw690/7b8d2108gy1fi2bey0qi3j20bz09cjrg.jpg)
    #### 1.1高斯分布-Gaussian distribution

    ​ 为了实行异常检测,我们首先需要拟合适合数据集分布的模型,给定训练集{(x^{(1)},...,x^{(m)})}(其中(x^{(i)}in mathbb{R}^n)),要估计每个特征x_i的高斯分布。 对于每个特征i = 1,...,n,需要找到拟合第i维数据的参数(mu_i)(sigma_i^2)。高斯分布公式如下:(其中(mu)为均值,(sigma^2)表示方差)

    ![2.jpg](http://wx2.sinaimg.cn/mw690/7b8d2108gy1fi2bey9d9lj208h023a9y.jpg)
    #### 1.2估计高斯参数

    ​ 我们可以使用下面的式子来估计参数((mu_i,sigma_i^2)),如为了估计均值有:(mu_i=frac{1}{m}Sigma_{j=1}^mx_i^{(j)}),为了估计方差有:(sigma_i^2=frac{1}{m}Sigma_{j=1}^m(x_i^{(j)}-mu_i)^2)

    ​ 完成estimateGaussian.m的代码,该函数将数据矩阵X作为输入,并输出保持所有n个特征的平均值的n维向量mu,以及保存所有特征的方差的n维向量sigma2。代码如下:

    % Useful variables
    [m, n] = size(X);
    
    % You should return these values correctly
    mu = zeros(n, 1);
    sigma2 = zeros(n, 1);
    
    % ====================== YOUR CODE HERE ======================
    % Instructions: Compute the mean of the data and the variances
    %               In particular, mu(i) should contain the mean of
    %               the data for the i-th feature and sigma2(i)
    %               should contain variance of the i-th feature.
    %
    for i=1:n
        mu(i)=1/m*sum(X(:,i));
    end
    
    for i=1:n
        for j=1:m
            sigma2(i) = sigma2(i)+(X(j,i)-mu(i))^2;
        end
        sigma2(i) = sigma2(i)/m;
    end
    

    ​ 运行后如下图,可以看出,大部分的例子都是在最高概率的地区,而异常的例子是在概率较低的地区。

    ![3.jpg](http://wx4.sinaimg.cn/mw690/7b8d2108gy1fi2beyu8g8j20cg09c3z7.jpg)
    #### 1.3选择限值

    ​ 现在已经估计了高斯参数,可以调查哪些示例在给定此分布的情况下具有非常高的概率,哪些示例的概率非常低,低概率的例子更有可能是我们数据集中的异常现象。 确定哪些示例是异常的一种方法是基于交叉验证集来选择阈值。 在这部分练习中,将使用交叉验证集上的F1分数来实施一个算法以选择阈值。

    ​ 完成代码selectThreshold.m。我们将使用交叉验证集{((x_{cv}^{(1)},y_{cv}^{(1)}),..,(x_{cv}^{(m_{cv})},y_{cv}^{(m_{cv})}))},其中标签y = 1对应于异常示例,并且y = 0对应于正常示例。 对于每个交叉验证示例,我们将计算(p(x_{cv}^{(i)}))。 所有这些概率(p(x_{cv}^{(1)}),p(x_{cv}^{(2)}),...,p(x_{cv}^{(m_{cv})}))以向量的形式被传递给向量pval中, 相应的标签(y_{cv}^{(1)},y_{cv}^{(2)},...,y_{cv}^{(m_{cv})})被传递给向量yval中。

    ​ 函数selectThreshold.m应该返回两个值; 第一个是所选择的阈值$varepsilon $ ,如果一个例子x具有低概率$P(x)<varepsilon $,则被认为是异常。 第二个应该返回F1分数,在给定一定的阈值时,通过计算当前阈值正确和不正确地分类样本以计算得到的F1分数,它说明在寻找异常方面做得效果如何。

    ​ F_1的计算用到了预测(prec)和召回(rec),具体公式为:(F_1=frac{2prec*rec}{prec+rec}),对预测和召回值得计算按照:(prec = frac{tp}{tp+fp})(rec = frac{tp}{tp+fn})

    ​ tp是真阳的数量(true positive):标签说这是一个异常同时我们的算法将其也正确地分类为异常。

    ​ fp是假阳-误报的数量(false positive):标签说这不是一个异常,但我们的算法将其分类为异常。

    ​ fn是假阴-漏报的数量(false negative):标签说是一个异常,而我们的算法将其分类为正常。

    关于fn和fp的理解

    函数selectThreshold.m代码如下:

    bestEpsilon = 0;
    bestF1 = 0;
    F1 = 0;
    
    stepsize = (max(pval) - min(pval)) / 1000;
    for epsilon = min(pval):stepsize:max(pval)
        
        % ====================== YOUR CODE HERE ======================
        % Instructions: Compute the F1 score of choosing epsilon as the
        %               threshold and place the value in F1. The code at the
        %               end of the loop will compare the F1 score for this
        %               choice of epsilon and set it to be the best epsilon if
        %               it is better than the current choice of epsilon.
        %               
        % Note: You can use predictions = (pval < epsilon) to get a binary vector
        %       of 0's and 1's of the outlier predictions
    
        cvPredictions = (pval < epsilon);
        tp = sum((cvPredictions == 1) & (yval == 1));
    	fp = sum((cvPredictions == 1) & (yval == 0));
        fn = sum((cvPredictions == 0) & (yval == 1));
    
        prec = tp/(tp+fp);
        rec = tp/(tp+fn);
    
        F1 = (2*prec*rec)/(prec+rec);
        % =============================================================
    
        if F1 > bestF1
           bestF1 = F1;
           bestEpsilon = epsilon;
        end
    end
    

    ​ 运行后,最佳的epsilon值为8.99e-05,最大的F1值为0.875,选定最佳epsilon后识别异常过的图形如下:

    ![4.jpg](http://wx3.sinaimg.cn/mw690/7b8d2108gy1fi2bezemh9j20cg09cmy2.jpg)
    ​ 这里其实还需要补充一点,对于主程序中有以下代码段:
    %  通过数据集估计参数
    [mu sigma2] = estimateGaussian(X);
    
    %  训练训练集模型
    p = multivariateGaussian(X, mu, sigma2);
    
    %  训练交叉验证集模型(用来选择最终的epsilon)
    pval = multivariateGaussian(Xval, mu, sigma2);
    
    %  Find the best threshold
    [epsilon F1] = selectThreshold(yval, pval);
    

    ​ 其中multivariateGaussian函数的定义如下:

    function p = multivariateGaussian(X, mu, Sigma2)
    
    n = length(mu);
    
    %Sigma2若为列向量或行向量时,将其变换为对角阵
    if (size(Sigma2, 2) == 1) || (size(Sigma2, 1) == 1)
        Sigma2 = diag(Sigma2);
    end
    
    X = bsxfun(@minus, X, mu(:)');%  X := X-mu
    p = (2 * pi) ^ (- n / 2) * det(Sigma2) ^ (-0.5) * ...
        exp(-0.5 * sum(bsxfun(@times, X * pinv(Sigma2), X), 2));%det 取行列式  times 乘法
    
    end
    

    ​ 给出相应公式作为对照:

    ![5.jpg](http://wx2.sinaimg.cn/mw690/7b8d2108gy1fhxanuwvhaj20fl01mjrb.jpg?_=7217215)

    2.推荐系统

    ​ 在本部分的练习中,将通过协同过滤学习算法并将其应用于电影评级数据集,该数据集由1到5的等级组成。数据集具有n_u = 943个用户,n_m = 1682部电影。 练习的下一部分,将实现计算协同拟合目标函数和渐变的函数cofiCostFunc.m。 实现成本函数和渐变后,将使用fmincg.m来学习协作过滤的参数。

    2.1电影评分数据集

    ​ 脚本ex8 cofi.m的第一部分将加载数据集ex8 movies.mat,从而提供变量Y和R。 矩阵Y(num movies×num_users尺寸)存储所评分的等级(y^{(i,j)})(从1到5)。 矩阵R是二进制值指示符矩阵,其中如果用户j对电影i给出评级,则(R(i,j)=1),否则为(R(i,j)=0)

    ​ 协同过滤算法的目的是预测用户尚未评估的电影的电影评级,即(R(i,j)=0)的项。从而推荐具有最高预测等级的电影给 用户。

    ​ 为了更好的了解矩阵Y,脚本ex8_cofi.m将计算第一部电影(Toy Story)的平均影片评分,并将平均评分显示到屏幕。 在整个练习过程中,将使用矩阵X和Theta:

    ![6.jpg](http://wx1.sinaimg.cn/mw690/7b8d2108gy1fi2bezrwrnj209m02igli.jpg)

    ​ X矩阵的每一行表示第i部电影的特征(x^{(i)}),Theta矩阵的每一行表示第j个用户的参数向量( heta^{(j)})。这里我们设定n=100,即X为n_m*100,Theta为n_u*100。

    2.2协同滤波学习算法

    ​ 协同过滤算法考虑了一组n维参数向量(x^{(1)},...,x^{(n_m)})( heta^{(1)},..., heta^{(n_u)}),其中模型将用户j对电影i的评级预测为(y^{(i,j)}=( heta^{(j)})^Tx^{(i)})。 给定一些由一些用户在某些电影上产生的评分组成的数据集,希望学习参数向量(x^{(1)},...,x^{(n_m)})( heta^{(1)},..., heta^{(n_u)})以产生最佳的拟合效果(最小化平方误差)。

    ​ 函数cofiCostFunc.m中的代码用来计算协同过滤的代价函数和梯度。函数的参数(即尝试学习的值)是X和Theta。 为了使用诸如fmincg的现成最小化库,代价函数已被设置为将参数展开为单个向量参数。

    2.2.1协同滤波的代价函数

    ​ 不包含正则化下的代价函数计算公式如下:

    ![1.jpg](http://wx4.sinaimg.cn/mw690/7b8d2108gy1fi31nftrskj20ey01ut8o.jpg)
    ​ 函数cofiCostFunc.m 代码如下:
    % 主程序中的调用方式
    % J = cofiCostFunc([X(:) ; Theta(:)], Y, R, num_users, num_movies, ...
    %               num_features, 0);
    % Unfold the U and W matrices from params
    X = reshape(params(1:num_movies*num_features), num_movies, num_features);
    Theta = reshape(params(num_movies*num_features+1:end), ...
                    num_users, num_features);
                    
    J = sum(sum(((X*Theta').*R-Y).^2))/2;                
    
    2.2.2 协同滤波的梯度

    ​ 现在应该完成cofiCostFunc.m中的梯度部分代码,该函数能够返回X_grad和Theta_grad两个参数,当然X_grad和Theta_grad得尺寸与X和Theta的尺寸相同。代价函数的梯度计算工式如下:

    ![2.jpg](http://wx1.sinaimg.cn/mw690/7b8d2108gy1fi31ng5gftj20af044aa9.jpg)
    ​ 请注意,该函数通过将它们展开为单个向量来返回变量集的梯度。 在计算梯度后,脚本ex8_cofi.m将运行梯度校验(checkCostFunction)以数字形式检查梯度的实现。如果实现正确,会发现分析和数值梯度紧密配合。

    ​ 无正则化的cofiCostFunc.m代码如下:

    % Unfold the U and W matrices from params
    X = reshape(params(1:num_movies*num_features), num_movies, num_features);
    Theta = reshape(params(num_movies*num_features+1:end), ...
                    num_users, num_features);
                
    % You need to return the following values correctly
    J = 0;
    X_grad = zeros(size(X));
    Theta_grad = zeros(size(Theta));
    
    for i=1:num_movies
        idx = find(R(i,:)==1);
        Theta_temp = Theta(idx,:);
        Y_temp = Y(i,idx);
        X_grad(i,:)= (X(i,:)*Theta_temp'-Y_temp)*Theta_temp;
    end
    
    %调试中要搞清楚矩阵Y、R行列表示的具体含义,X、Theta亦然,num_users和num_movies调试值可为4*5
    for i=1:num_users
        idx = find(R(:,i)==1);
        X_temp = X(idx,:);
        Y_temp = Y(idx,i);
        Theta_grad(i,:) = ((X_temp*Theta(i,:)'-Y_temp))'*X_temp;
    end
    

    ​ 梯度校验(checkCostFunction)代码段如下:

    % Set lambda
    if ~exist('lambda', 'var') || isempty(lambda)
        lambda = 0;
    end
    
    %% Create small problem
    X_t = rand(4, 3);
    Theta_t = rand(5, 3);
    
    % Zap out most entries
    Y = X_t * Theta_t';
    Y(rand(size(Y)) > 0.5) = 0;
    R = zeros(size(Y));
    R(Y ~= 0) = 1;
    
    %% Run Gradient Checking
    X = randn(size(X_t));
    Theta = randn(size(Theta_t));
    num_users = size(Y, 2);
    num_movies = size(Y, 1);
    num_features = size(Theta_t, 2);
    
    numgrad = computeNumericalGradient( ...
                    @(t) cofiCostFunc(t, Y, R, num_users, num_movies, ...
                                    num_features, lambda), [X(:); Theta(:)]);
    
    [cost, grad] = cofiCostFunc([X(:); Theta(:)],  Y, R, num_users, ...
                              num_movies, num_features, lambda);
    
    disp([numgrad grad]);
    fprintf(['The above two columns you get should be very similar.
    ' ...
             '(Left-Your Numerical Gradient, Right-Analytical Gradient)
    
    ']);
    
    diff = norm(numgrad-grad)/norm(numgrad+grad);
    fprintf(['If your cost function implementation is correct, then 
    ' ...
             'the relative difference will be small (less than 1e-9). 
    ' ...
             '
    Relative Difference: %g
    '], diff);
    
    %数值上计算梯度函数computeNumericalGradient代码段如下:
    function numgrad = computeNumericalGradient(J, theta)
    
    numgrad = zeros(size(theta));
    perturb = zeros(size(theta));
    e = 1e-4;
    for p = 1:numel(theta)
        % Set perturbation vector
        perturb(p) = e;
        loss1 = J(theta - perturb);
        loss2 = J(theta + perturb);
        % Compute Numerical Gradient
        numgrad(p) = (loss2 - loss1) / (2*e);
        perturb(p) = 0;
    end
    
    end
    
    2.2.3正则化代价函数

    ​ 含有正则化参数的协同滤波代价函数公式如下:

    ![3.jpg](http://wx1.sinaimg.cn/mw690/7b8d2108gy1fi31ngnmn2j20hd045mxd.jpg)
    ​ 完成后的cofiCostFunc.m代价函数部分代码为:
    J = sum(sum(((X*Theta').*R-Y).^2))/2;
    J = J + sum(sum(Theta.^2))*lambda/2 + sum(sum(X.^2))*lambda/2
    
    2.2.4正则化梯度下降

    ​ 对含有正则化代价函数的梯度运算公式为:

    ![4.jpg](http://wx4.sinaimg.cn/mw690/7b8d2108gy1fi31nh1k3pj20ce046mxf.jpg)
    ​ 完成后的cofiCostFunc.m梯度下降部分完整代码为:
    for i=1:num_movies
        idx = find(R(i,:)==1);
        Theta_temp = Theta(idx,:);
        Y_temp = Y(i,idx);
        X_grad(i,:)= (X(i,:)*Theta_temp'-Y_temp)*Theta_temp;
        X_grad(i,:) = X_grad(i,:)+lambda*X(i,:);
    end
    
    for j=1:num_users
        idx = find(R(:,j)==1);
        X_temp = X(idx,:);
        Y_temp = Y(idx,j);
        Theta_grad(j,:) = ((X_temp*Theta(j,:)'-Y_temp))'*X_temp;
        Theta_grad(j,:) = Theta_grad(j,:) + lambda*Theta(j,:);
    end
    % =============================================================
    
    grad = [X_grad(:); Theta_grad(:)];
    

    2.3 学习推荐电影

    ​ 在ex8 cofi.m脚本的最后一部分,可以输入自己喜爱的电影,便于算法运行时,可以获得系统推荐给自己的电影! 所有电影的列表及其在数据集中的编号可以在文件movie idx.txt中找到。

    movie idx.txt部分内容如下:


    1 Toy Story (1995)
    2 GoldenEye (1995)
    3 Four Rooms (1995)
    4 Get Shorty (1995)
    5 Copycat (1995)
    6 Shanghai Triad (Yao a yao yao dao waipo qiao) (1995)
    7 Twelve Monkeys (1995)
    8 Babe (1995)
    9 Dead Man Walking (1995)
    10 Richard III (1995)
    11 Seven (Se7en) (1995)
    12 Usual Suspects, The (1995)
    13 Mighty Aphrodite (1995)
    14 Postino, Il (1994)
    15 Mr. Holland's Opus (1995)


    ​ 读取该内容的完整程序为:

    % movieList = loadMovieList();
    
    function movieList = loadMovieList()
    %	GETMOVIELIST reads the fixed movie list in movie.txt and returns a
    %	cell array of the words
    %   movieList = GETMOVIELIST() reads the fixed movie list in movie.txt 
    %   and returns a cell array of the words in movieList.
    
    %% Read the fixed movieulary list
    fid = fopen('movie_ids.txt');
    
    % Store all movies in cell array movie{}
    n = 1682;  % Total number of movies 
    
    movieList = cell(n, 1);
    for i = 1:n
        % Read line
        line = fgets(fid);%fgets函数用于读取文件中指定一行,并保留换行符,与之前的fopen配套使用
        % Word Index (can ignore since it will be = i)
        [idx, movieName] = strtok(line, ' ');%按“ ”分类捕捉索引和字符串电影名变量
        % Actual Word
        movieList{i} = strtrim(movieName);%此函数返回字符串str的副本并删除了所有前导和尾随空格字符
    end
    fclose(fid);
    
    end
    

    ​ 在额外的额定值被添加到数据集之后,脚本将继续训练协同过滤模型,具体添加过程如下:

    %  初始化个人观影评分
    my_ratings = zeros(1682, 1);
    
    % Check the file movie_idx.txt for id of each movie in our dataset
    % For example, Toy Story (1995) has ID 1, so to rate it "4", you can set
    my_ratings(1) = 4;
    
    % Or suppose did not enjoy Silence of the Lambs (1991), you can set
    my_ratings(98) = 2;
    
    % We have selected a few movies we liked / did not like and the ratings we
    % gave are as follows:
    my_ratings(7) = 3;
    my_ratings(12)= 5;
    my_ratings(54) = 4;
    my_ratings(64)= 5;
    my_ratings(66)= 3;
    my_ratings(69) = 5;
    my_ratings(183) = 4;
    my_ratings(226) = 5;
    my_ratings(355)= 5;
    

    ​ 此后,算法将同过调用训练集学习参数X和Theta,从而预测电影i对用户j的评级(( heta^{(j)})^Tx^{(i)})。 脚本的下一部分计算所有电影和用户的评分,根据脚本中上面输入的评分,进而显示它推荐的电影。


    Top recommendations for you:
    Predicting rating 5.0 for movie Star Kid (1997)
    Predicting rating 5.0 for movie Prefontaine (1997)
    Predicting rating 5.0 for movie Great Day in Harlem, A (1994)
    Predicting rating 5.0 for movie Someone Else's America (1995)
    Predicting rating 5.0 for movie Marlene Dietrich: Shadow and Light (1996)
    Predicting rating 5.0 for movie Aiqing wansui (1994)
    Predicting rating 5.0 for movie Entertaining Angels: The Dorothy Day Story (1996)
    Predicting rating 5.0 for movie Santa with Muscles (1996)
    Predicting rating 5.0 for movie They Made Me a Criminal (1939)
    Predicting rating 5.0 for movie Saint of Fort Washington, The (1993)


    版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
  • 相关阅读:
    批处理文件入门
    批处理入门学习地址
    react资料
    React 学习参考资料链接
    Spring boot + jdbc学习笔记
    iOS-升级Https证书报错
    Java-006-循环结构和控制语句详解(while, dowhile ,for ,switch)
    Java-005-运算符详解
    Java-004-变量类型和修饰符详解
    Java-001简介和基础语法[类方法、实例方法、public class 与 class 区别](第一个Java程序)
  • 原文地址:https://www.cnblogs.com/SrtFrmGNU/p/7260943.html
Copyright © 2011-2022 走看看