精华内容
下载资源
问答
  • 如何剔除异常数据
    千次阅读
    2021-02-05 15:20:09

    筛选异常值的方法有z-scores, modified z-score, box plots, Grubb’s test,Tietjen-Moore测试指数平滑法,Kimber测试指数分布和移动窗口滤波算法。然而比较详细的两个方法是:

    Inter Quartile Range

    An outlier is a point of data that lies over 1.5 IQRs below the first quartile (Q1) or above third quartile (Q3) in a given data set.

    High = (Q3) + 1.5 IQR

    Low = (Q1) – 1.5 IQR

    Tukey Method

    It uses interquartile range to filter very large or very small numbers. It is practically the same method as above except that it uses the concept of “fences”. The two values of fences are:

    Low outliers = Q1 – 1.5(Q3 – Q1) = Q1 – 1.5(IQR)

    High outliers = Q3 + 1.5(Q3 – Q1) = Q3 + 1.5(IQR)

    在这个区域外的任何值都是异常值

    当你发现异常值时,你不应该不对它进行一个定性评估就删除它,因为这样你改变了数据,使其不再纯粹。重要的是要在理解分析的背景下或者说重要的是“为什么的问题——为什么异常值不同于其他数据点?”

    这个原因是至关重要的。如果归因于异常值错误,你可能把它排除,但如果他们意味着一种新趋势、模式或显示一个有价值的深度数据,你应该保留它。

    更多相关内容
  • 风电机组异常数据识别与清洗-baseline

    千次阅读 多人点赞 2020-09-23 11:34:00
    风电机组异常数据识别与清洗-baseline 比赛类型:数据挖掘 比赛数据:表格题(csv) 学习方式:无监督 主办方:国家电力投资集团有限公司科技与创新部 比赛链接 比赛任务:依据提供的8台风力电机1年的10min间隔...

    风电机组异常数据识别与清洗-baseline

    比赛类型:数据挖掘
    比赛数据:表格题(csv)
    学习方式:无监督
    主办方:国家电力投资集团有限公司科技与创新部
    

    比赛链接
    比赛任务:依据提供的8台风力电机1年的10min间隔SCADA运行数据,包括时间戳信息、风速信息和功率信息等,利用机器学习相关技术,建立鲁棒的风电机组异常数据检测模型,用于识别并剔除潜在的异常数据,提高数据质量。

      此任务未给出异常数据标签,视为聚类任务,为引导选手向赛题需求对接,现简单阐述异常数据定义。异常数据是由风机运行过程与设计运行工况出现较大偏离时产生,如风速仪测风异常导致采集的功率散点明显偏离设计风功率。

    任务概述:根据给出数据 ,12台风力电机 的 【‘风机编号’,‘时间戳’,‘风速’,‘功率’,‘风轮转速’】表格数据进行异常数据的检测,通过无监督的方式(学习方式不限)判断为异常数据进行打标签1,否则为0。
    比赛难点:首先,学习方式是无监督的方法,不是简单的二分类表格题,使得一些如xgb树、CNN网络等之类的成熟模型将无法使用,除非通过半监督的方式进行人为打标,但这样风险过大,易过拟合。
    其次,可用的方式多种多样,可以通过一定的风电机组发动机实际物理模型进行数学意义上的异常分析,或通过图像法来人为选定异常值,当然,我们也可以按照比赛要求使用经典的无监督模型进行聚类分析。
    最后,数据的特征太少了,每一个电机只有【‘时间戳’,‘风速’,‘功率’,‘风轮转速’】四种特征,对于表格题来说,仅仅四种特征无论什么模型效果都会很一般,故特征工程是一定要做的。

    :本baseline仅供共同学习使用



    前言

    在本篇您将学到:
      ● 数据分析的基本流程
      ● 四种经典无监督模型的异常检测
      ● 本比赛的基本流程

    I 数据分析

    1.1 数据读取

    一共有两个数据集,dataset.csv 以行的方式存放了12台风机的数据,submission.csv 以行的方式存放了风机编号、时间戳和标签label,一共有三列,其中标签label就是我们要建模“预测”提交的。

    注意,本数据集不再划分训练集、验证集和测试集,因为训练集和测试集的主键相同(即ID均相同),且学习方式是无监督。如果你考虑使用半监督学习的方式,可以进行数据集的划分,但这样是有一定风险的,因为你要自己打标,这个标签不一定准,且有可能过拟合A榜而导致最终B榜分数有问题,以及实际应用中这种方式将不再实用。

    data = pd.read_csv('../data/dataset.csv')
    submit = pd.read_csv('../data/submission.csv')
    
    data.columns = ['风机编号','时间戳','风速','功率','风轮转速']
    # data['label'] = 0 # 1为异常数据
    print('Data shape:{}'.format(data.shape))
    print('Submit shape:{}'.format(submit.shape))
    print('训练集与测试集主键是否相同:',(data['时间戳'] == submit['Time']).all())
    data.head()
    

    在这里插入图片描述

    1.2 数据可视化

    sns.set()
    print(data['风速'].loc[data['风机编号']==1].describe())
    data['风速'].loc[data['风机编号']==1].hist()
    

    在这里插入图片描述
    风机1号的全年风速图

    mpl.rcParams['font.sans-serif'] = ['SimHei']
    mpl.rcParams['axes.unicode_minus'] = False
    data.loc[data['风机编号']==1].plot(x='时间戳',y='风速',figsize=(12,6))
    

    在这里插入图片描述
    风机12号的全年风速图

    mpl.rcParams['font.sans-serif'] = ['SimHei']
    mpl.rcParams['axes.unicode_minus'] = False
    data.loc[data['风机编号']==12].plot(x='时间戳',y='风速',figsize=(12,6))
    

    在这里插入图片描述
    12台风机的全年风速图

    a1 = data.loc[data['风机编号']==1,'风速']
    a2 = data.loc[data['风机编号']==2,'风速']
    a3 = data.loc[data['风机编号']==3,'风速']
    a4 = data.loc[data['风机编号']==4,'风速']
    a5 = data.loc[data['风机编号']==5,'风速']
    a6 = data.loc[data['风机编号']==6,'风速']
    a7 = data.loc[data['风机编号']==7,'风速']
    a8 = data.loc[data['风机编号']==8,'风速']
    a9 = data.loc[data['风机编号']==9,'风速']
    a10 = data.loc[data['风机编号']==10,'风速']
    a11 = data.loc[data['风机编号']==11,'风速']
    a12 = data.loc[data['风机编号']==12,'风速']
    plt.figure(figsize=(15,10))
    plt.hist(a1,bins=50 , alpha=0.5,label='风机编号1')
    plt.hist(a2,bins=50 , alpha=0.5,label='风机编号2')
    plt.hist(a3,bins=50 , alpha=0.5,label='风机编号3')
    plt.hist(a4,bins=50 , alpha=0.5,label='风机编号4')
    plt.hist(a5,bins=50 , alpha=0.5,label='风机编号5')
    plt.hist(a6,bins=50 , alpha=0.5,label='风机编号6')
    plt.hist(a7,bins=50 , alpha=0.5,label='风机编号7')
    plt.hist(a8,bins=50 , alpha=0.5,label='风机编号8')
    plt.hist(a9,bins=50 , alpha=0.5,label='风机编号9')
    plt.hist(a10,bins=50 , alpha=0.5,label='风机编号10')
    plt.hist(a11,bins=50 , alpha=0.5,label='风机编号11')
    plt.hist(a12,bins=50 , alpha=0.5,label='风机编号12')
    plt.legend(loc='upper right')
    plt.xlabel('风速')
    plt.ylabel('统计')
    plt.show()
    

    在这里插入图片描述
    从上面的直方图中可以看出各个风机的全年风速的趋势类似,都是有一定正态分布的规律的,在此分析上,可以对风速进行np.log1p的数字特征处理来减低偏度等。

    1.3 特征工程

    根据比赛官方给出的不同风机各自的风轮直径、额定功率、切入风速、切出风速、风轮转速范围进行添加。

    # 官方给的每个风机的风轮直径、额定功率、切入风速、切出风速、风轮转速范围
    def wheel_diameter(id_):
        id_ = int(id_)
        if id_==5:return 100.5
        elif id_==11:return 115
        elif id_==12:return 104.8
        else:return 99 
    def rated_p(id_):
        return 2000
    def cutin_wind(id_):
        id_ = int(id_)
        if id_ == 11:return 2.5
        else:        return 3 
    def cutout_wind(id_):
        id_ = int(id_)
        if id_==5 or id_==12:return 22
        elif id_==11:        return 19
        else:                return 25
    def wheel_speed(id_):
        id_ = int(id_)
        if id_ == 5:return [5.5,19]
        elif id_ == 11:return [5,14]
        elif id_ == 12:return [5.5,17]
        return [8.33,16.8]
        
        
    data['风轮直径'] = data['风机编号'].apply(wheel_diameter)
    data['额定功率'] = data['风机编号'].apply(rated_p)
    data['切入风速'] = data['风机编号'].apply(cutin_wind)
    data['切出风速'] = data['风机编号'].apply(cutout_wind)
    data['风轮转速范围'] = data['风机编号'].apply(wheel_speed)
    data.head()
    

    在这里插入图片描述

    在此,为保证比赛竞争性,本baseline再仅提供一个二值特征,比赛群里讨论发现,风轮转速<7约有89%的异常数据,故该二值特征很有意义(能上分)。

    def speed(v):
        return 0 if v>7 else 1
    data['风轮转速_01'] = data['风轮转速'].apply(speed)
    

    提示:你可以通过时间戳做时序特征、根据功率和风轮转速做物理特征、根据切入风速、切出风速等做风速判断等等,以及对数字特征做统计特征等。

    II 建立模型

    2.1 基于聚类的异常检测

    k-means是一种广泛使用的聚类算法。 它创建了k个具有相似特性的数据组。 不属于这些组的数据实例可能会被标记为异常。 在我们开始k-means聚类之前,我们使用elbow方法来确定最佳聚类数量。

    data_num = data[['风速','功率','风轮转速']]
    n_cluster = range(1, 20)
    kmeans = [KMeans(n_clusters=i).fit(data_num) for i in n_cluster]
    scores = [kmeans[i].score(data_num) for i in range(len(kmeans))]
    
    fig, ax = plt.subplots(figsize=(10,6))
    ax.plot(n_cluster, scores)
    plt.xlabel('N_cluster')
    plt.ylabel('Score')
    plt.title('Elbow Curve')
    plt.show()
    

    在这里插入图片描述
    为了找出合理的距离中心数,我们尝试尽可能多的聚类中心数(从1个到20个聚类中心),然后我们画出Elbow曲线,通过观察Elbow曲线,我们发现当我们的聚类中心数量增加到10个以上时Elbow曲线趋于收敛,因此我们大致可以将聚类中心数定为10.

    :在此,请时刻记得我们的任务是什么,是对12台风机的全年数据进行异常数据的检测,聚类成10类仅仅是从整体数据的角度进行考虑的。可以考虑的是分成12组进行分组聚类,聚类的类别为2组,即一组正常、一组异常。

    下面我们将K-means算法的n_clusters设置为10,然后我们将数据进行3D可视化。

    X = data_num
    X = X.reset_index(drop=True)
    km = KMeans(n_clusters=10)
    km.fit(X)
    km.predict(X)
    labels = km.labels_
     
    fig = plt.figure(1, figsize=(15,15))
    ax = Axes3D(fig, rect=[0, 0, 0.95, 1], elev=48, azim=134)
    ax.scatter(X.iloc[:,0], X.iloc[:,1], X.iloc[:,2],
              c=labels.astype(np.float), edgecolor="k")
    # '风速','功率','风轮转速'
    ax.set_xlabel("风速")
    ax.set_ylabel("功率")
    ax.set_zlabel("风轮转速")
    plt.title("K Means", fontsize=14)
    

    在这里插入图片描述
    让我们再单独看看给1号风机进行类别为2种的聚类

    X = data[['风速','功率','风轮转速']].loc[data['风机编号']==1]
    X = X.reset_index(drop=True)
    km = KMeans(n_clusters=2)
    km.fit(X)
    km.predict(X)
    labels = km.labels_
     
    fig = plt.figure(1, figsize=(10,10))
    ax = Axes3D(fig, rect=[0, 0, 0.95, 1], elev=48, azim=134)
    ax.scatter(X.iloc[:,0], X.iloc[:,1], X.iloc[:,2],
              c=labels.astype(np.float), edgecolor="k")
    # '风速','功率','风轮转速'
    ax.set_xlabel("风速")
    ax.set_ylabel("功率")
    ax.set_zlabel("风轮转速")
    plt.title("风机编号1 K Means", fontsize=14)
    

    在这里插入图片描述

    接下来让我们来确定需要保留数据中的哪些主要成分(特征)

    X = data_num.values
    
    # 标准化 均值为0 标准差为1
    X_std    = StandardScaler().fit_transform(X)
    mean_vec = np.mean(X_std,axis=0)
    # 协方差,协方差矩阵反应了特征变量之间的相关性
    # 如果两个特征变量之间的协方差为正则说明它们之间是正相关关系
    # 如果为负则说明它们之间是负相关关系
    cov_mat = np.cov(X_std.T)
    
    # 特征值和特征向量
    eig_vals,eig_vecs = np.linalg.eig(cov_mat)
    # 特征值对应的特征向量
    eig_pairs = [ (np.abs(eig_vals[i]),eig_vecs[:,i]) for i in range(len(eig_vals))]
    eig_pairs.sort(key = lambda x: x[0], reverse= True)
    # 特征之求和
    eig_sum = sum(eig_vals)
    
    
    # 解释方差
    var_exp = [(i/eig_sum)*100 for i in sorted(eig_vals, reverse=True)]
    # 累计的解释方差
    cum_var_exp = np.cumsum(var_exp)
    
    plt.figure(figsize=(10,5))
    plt.bar(range(len(var_exp)), var_exp, alpha=0.3, align='center', label='独立的解释方差', color = 'g')
    plt.step(range(len(cum_var_exp)), cum_var_exp, where='mid',label='累积解释方差')
    plt.ylabel('解释方差率')
    plt.xlabel('主成分')
    plt.legend(loc='best')
    plt.show()
    

    在这里插入图片描述
    我们首先对数据进行标准化处理(StandardScaler),
      然后再计算特征变量之间的协方差矩阵,协方差矩阵反应了特征变量之间的相关性,如果两个特征变量之间的协方差为正则说明它们之间是正相关关系,如果为负则说明它们之间是负相关关系,如果为0则说明特征变量之间是相互独立的关系,不存在相关关系(有时候我们也会用相关系数矩阵来代替协方差矩阵)。
      最后在协方差矩阵的基础上又计算了协方差矩阵的特征值和特征向量,根据特征值计算出每个主成分(特征)的解释方差,以及累计解释方差,
      我们这样做的目的是为了下一步做主成分分析(PCA)挑选出特征变量中的主成分。
    我们挑选第一个主成分,因为它的累计解释方差为80%。

    从上图可知我们的三个主成分,第一个主成分(特征)解释了将近80%的方差变化,第二个主成分解释了近15%的方差变化,那么第一个主成分解释了近80%的方差。因此接下来我们将使用PCA算法进行降维并将设置参数n_components=1。

    # 标准化处理,均值为0,标准差为1
    X_std = StandardScaler().fit_transform(data_num.values)
    data_std = pd.DataFrame(X_std)
     
    #将特征维度降到1
    pca = PCA(n_components=1)
    data_std = pca.fit_transform(data_std)
    # 降维后将1个新特征进行标准化处理
    scaler = StandardScaler()
    np_scaled = scaler.fit_transform(data_std)
    data_std = pd.DataFrame(np_scaled)
     
    kmeans = [KMeans(n_clusters=i).fit(data_std) for i in n_cluster]
    data['cluster'] = kmeans[9].predict(data_std) # 刚才Elbow曲线10类基本收敛了,故还是选择10类
    data.index = data_std.index
    data['principal_feature1'] = data_std[0]
    data.head()
    

    在这里插入图片描述
    基于聚类的异常检测中的假设是,如果我们对数据进行聚类,则正常数据将属于聚类,而异常将不属于任何聚类或属于小聚类。 我们使用以下步骤来查找和可视化异常值。

    计算每个数据点与其最近的聚类中心之间的距离。 最大的距离被认为是异常的。设定一个异常值的比例outliers_fraction为40%,这样设置是因为在标准正太分布的情况下(N(0,1))我们一般认定3个标准差以外的数据为异常值,3个标准差以内的数据包含了数据集中99%以上的数据,所以剩下的1%的数据可以视为异常值。

    根据异常值比例outliers_fraction,计算异常值的数量number_of_outliers。设定一个判定异常值的阈值threshold,通过阈值threshold来判定数据是否为异常值。以及对数据进行可视化(包含正常数据和异常数据)

    # 计算每个数据点到其聚类中心的距离
    def getDistanceByPoint(data, model):
        distance = pd.Series()
        for i in range(0,len(data)):
            Xa = np.array(data.loc[i])
            Xb = model.cluster_centers_[model.labels_[i]]
            distance.set_value(i, np.linalg.norm(Xa-Xb))
        return distance
     
    #设置异常值比例
    outliers_fraction = 0.4
     
    # 得到每个点到取聚类中心的距离,我们设置了10个聚类中心,kmeans[9]表示有10个聚类中心的模型
    distance = getDistanceByPoint(data_std, kmeans[9])
     
    #根据异常值比例outliers_fraction计算异常值的数量
    number_of_outliers = int(outliers_fraction*len(distance))
     
    #设定异常值的阈值
    threshold = distance.nlargest(number_of_outliers).min()
     
    #根据阈值来判断是否为异常值
    data['anomaly1'] = (distance >= threshold).astype(int)
    
    #数据可视化
    fig, ax = plt.subplots(figsize=(10,6))
    colors = {0:'blue', 1:'red'}
    ax.scatter(data['principal_feature1'],data['风速'],c=data["anomaly1"].apply(lambda x: colors[x]))
    plt.xlabel('principal feature1')
    plt.ylabel('风速')
    plt.show()
    

    在这里插入图片描述
    上图中红色的点即是被认定的异常值,它们大约占总数据量的40%。
    下述代码也证实了这一点。
    在这里插入图片描述

    fig, ax = plt.subplots(figsize=(12,6))
     
    a = data.loc[data['anomaly1'] == 1, ['时间戳', '风轮转速']] #anomaly
     
    ax.plot(data['时间戳'], data['风轮转速'], color='blue', label='正常值')
    ax.scatter(a['时间戳'],a['风轮转速'], color='red', label='异常值')
    plt.xlabel('时间戳')
    plt.ylabel('风轮转速')
    plt.legend()
    plt.show()
    

    在这里插入图片描述
    从上图可知,经过PCA和KMeans计算出的异常值,它们的风轮转速大多位于区间的最高点和最低点处,这应该是合理的。

    2.2 孤立森林(IsolationForest)异常检测

    IsolationForest算法它是一种集成算法(类似于随机森林)主要用于挖掘异常(Anomaly)数据,或者说离群点挖掘,总之是在一大堆数据中,找出与其它数据的规律不太符合的数据。该算法不采样任何基于聚类或距离的方法,因此他和那些基于距离的的异常值检测算法有着根本上的不同,孤立森林认定异常值的原则是异常值是少数的和不同的数据。它通常用于网络安全中的攻击检测和流量异常等分析,金融机构则用于挖掘出欺诈行为。

      ●当我们使用IsolationForest算法时需要设置一个异常值比例的参数contamination, 该参数的作用类似于之前的outliers_fraction。
      ●使用 fit 方法对孤立森林模型进行训练
      ●使用 predict 方法去发现数据中的异常值。返回1表示正常值,-1表示异常值。

    # 训练孤立森林模型
    model =  IsolationForest(contamination=outliers_fraction)
    model.fit(data_std)
     
    #返回1表示正常值,-1表示异常值
    data['anomaly2'] = pd.Series(model.predict(data_std)) 
     
    fig, ax = plt.subplots(figsize=(10,6))
    a = data.loc[data['anomaly2'] == -1, ['时间戳', '风轮转速']] #异常值
    ax.plot(data['时间戳'], data['风轮转速'], color='blue', label = '正常值')
    ax.scatter(a['时间戳'],a['风轮转速'], color='red', label = '异常值')
    plt.legend()
    plt.show()
    

    在这里插入图片描述
    从上图可知,使用孤立森林预测的异常值,它们的风轮转速大多位于区间的最高点或最低点处。

    2.3 支持向量机(SVM)的异常检测

    SVM通常应用于监督式学习,但OneClassSVM算法可用于将异常检测这样的无监督式学习,它学习一个用于异常检测的决策函数其主要功能将新数据分类为与训练集相似的正常值或不相似的异常值。

    SVM使用大边距的方法,它用于异常检测的主要思想是:将数据密度较高的区域分类为正,将数据密度较低的区域分类为负

      ●在训练OneClassSVM模型时,我们需要设置参数nu = outliers_fraction,它是训练误差分数的上限和支持向量分数的下限,并且必须在0和1之间。基本上它代表了我们期望的异常值在我们的数据集中的比例。
      ●指定要在算法中使用的核类型:rbf。 它使SVM能够使用非线性函数将超空间投影到更高维度。
      ●gamma是RBF内核类型的参数,并控制各个训练样本的影响 - 这会影响模型的“平滑度”。
      ●predict 对数据进行分类,因为我们的模型是单类模型,所以返回+1或-1,-1表示是异常值,1表示是正常值。

    # 训练 oneclassSVM 模型
    model = OneClassSVM(nu=outliers_fraction, kernel="rbf", gamma=0.01)
    model.fit(data_std)
     
    data['anomaly3'] = pd.Series(model.predict(data_std))
    fig, ax = plt.subplots(figsize=(10,6))
     
    a = data.loc[data['anomaly3'] == -1, ['时间戳', '风轮转速']] #异常值
    
    ax.plot(data['时间戳'], data['风轮转速'], color='blue', label = '正常值')
    ax.scatter(a['时间戳'],a['风轮转速'], color='red', label = '异常值')
    plt.legend()
    plt.show()
    

    在这里插入图片描述
    从上图可知,使用OneClassSVM预测的异常值,它们的风轮转速大多位于区间的最高点或最低点处。

    2.4 基于高斯概分布的异常检测

    高斯分布也称为正态分布。 它可以被用来进行异常值检测,不过我们首先要假设我们的数据是正态分布的。 不过这个假设不能适应于所有数据集。但如果我们做了这种假设那么它将会有一种有效的方法来发现异常值。

    Scikit-Learn的EllipticEnvelope模型,它在假设我们的数据是多元高斯分布的基础上计算出高斯分布的一些关键参数过程。过程大致如下:

      ●根据前面定义的类别创建两个不同的数据集 : search_Sat_night和Search_Non_Sat_night。
      ●在每个类别应用EllipticEnvelope(高斯分布)。
      ●我们设置contamination参数,它表示我们数据集中异常值的比例。
      ●使用decision_function来计算给定数据的决策函数。 它等于移位的马氏距离(Mahalanobis distances)。 异常值的阈值为0,这确保了与其他异常值检测算法的兼容性。
      ●使用predict 来预测数据是否为异常值(1 正常值, -1 异常值)

    # 基于高斯概分布的异常检测
    df_class0 = data.loc[data['风轮转速'] >7, '风轮转速']
    df_class1 = data.loc[data['风轮转速'] <=7, '风轮转速']
     
    envelope =  EllipticEnvelope(contamination = outliers_fraction) 
    X_train = df_class0.values.reshape(-1,1)
    envelope.fit(X_train)
    df_class0 = pd.DataFrame(df_class0)
    df_class0['deviation'] = envelope.decision_function(X_train)
    df_class0['anomaly'] = envelope.predict(X_train)
     
    envelope =  EllipticEnvelope(contamination = outliers_fraction) 
    X_train = df_class1.values.reshape(-1,1)
    envelope.fit(X_train)
    df_class1 = pd.DataFrame(df_class1)
    df_class1['deviation'] = envelope.decision_function(X_train)
    df_class1['anomaly'] = envelope.predict(X_train)
     
    df_class = pd.concat([df_class0, df_class1])
    
    data['anomaly4'] = df_class['anomaly']
    fig, ax = plt.subplots(figsize=(10, 6))
    a = data.loc[data['anomaly4'] == -1, ('时间戳', '风轮转速')] 
    ax.plot(data['时间戳'], data['风轮转速'], color='blue', label = '正常值')
    ax.scatter(a['时间戳'],a['风轮转速'], color='red', label = '异常值')
    plt.show()
    

    在这里插入图片描述
    从上图可知,使用EllipticEnvelope预测的异常值,它们的风轮转速大多位于区间的最高点处,而在最低点处没有出现异常值。

    到目前为止,我们已经用四种不同的方法进行了风轮数据异常检测。 因为我们的异常检测是无监督学习。 在构建模型之后,我们不知道他们的异常检测效果怎么样,因为我们没有办法可以对他们进行测试。 通常异常检测只有在实际的应用场景中才能测试出它的效果。

    III “预测”提交

    让我们先来看一下我们的训练集data
    在这里插入图片描述
    根据上述四种不同模型的异常检测我们得到了anomaly1-4的检测值,在此基础上,你可以选择投票的方式得到最终的结果“预测”,或一票决定。

    data['sum'] = data['风轮转速_01'] + data['anomaly1'] + data['anomaly2'] + data['anomaly3'] + data['anomaly4']
    ## 注意,请选择以下两种方式的一种进行运行,直接运行将会使一票决定覆盖投票
    # 投票
    submit.loc[:,'label'] = data.loc[:,'sum'].map({0:0,1:0,2:0,3:1,4:1,5:1})
    # 一票决定
    submit.loc[:,'label'] = data.loc[:,'sum'].map({0:0,1:1,2:1,3:1,4:1,5:1})
    

    最终提交,并评测

    submit.to_csv('../output/baseline.csv',index=False)
    submit.head()
    



    完整ipynb代码文件和比赛数据可见Github
    https://github.com/AmangAris/Abnormal-data-identification-and-cleaning-of-wind-turbine

    数据集放在了Q群,群文件免费下载:782589269

    展开全文
  • 数据挖掘--风电机组异常数据识别与清洗

    千次阅读 多人点赞 2020-10-22 17:11:04
    一、赛题背景 (一)背景 风能是一种环境友好且经济实用的可再生能源。...但风电机组受设备、环境、运行状态等因素影响,SCADA系统实时采集的风机运行数据会存在有大量异常值和缺失值,这些“脏数据”的

    一、赛题背景

    (一)背景

    风能是一种环境友好且经济实用的可再生能源。中国是世界排名第一的风力发电国家、新装风力发电设备装机容量最大的国家,并且保持快速增长。由于风力发电正处于飞速发展阶段,风电场数量和规模不断扩大,然而受地理条件和环境因素限制,风电场多位于偏僻遥远的平原、山区或海上,因此为风电公司引入SCADA系统(数据采集与监视控制系统)对风电场群的日常运行进行集中监控、调度和管理,但风电机组受设备、环境、运行状态等因素影响,SCADA系统实时采集的风机运行数据会存在有大量异常值和缺失值,这些“脏数据”的存在严重影响后续的风电机组状态分析、故障诊断等功能。因此,识别并排除风电机组的异常数据具有重要的探究意义。

    (二) 赛题任务

    依据提供的8台风力电机1年的10min间隔SCADA运行数据,包括时间戳信息、风速信息、风机转速信息和功率信息等,利用机器学习相关技术,建立鲁棒的风电机组异常数据检测模型,用于识别并剔除潜在的异常数据,提高数据质量。
    此任务未给出异常数据标签,视为聚类任务,为引导选手向赛题需求对接,现简单阐述异常数据定义。异常数据是由风机运行过程与设计运行工况出现较大偏离时产生,如风速仪测风异常导致采集的功率散点明显偏离设计风功率。

    (三)数据介绍

    数据来源自某风电场群的1年SCADA真实运行数据,主要有4个维度信息分别为时间戳、风速、功率和风轮转速,并且给出风机参数说明罗列了各风机的风轮直径、额定功率和风轮转速范围等信息,该数据集从风机实际生产过程中收集,是风机在实际工况条件下运行的典型结果,因此每台风机的原始数据中都包含大量异常数据点,该数据集与风机SCADA系统异常数据检测应用场景相适配。
    在这里插入图片描述注:赛题链接

    二、赛题解析

    首先,学习方式是无监督的方法,不是简单的二分类问题,使得一些如xgb树、CNN网络等之类的成熟模型将无法使用,除非通过半监督的方式进行人为打标,但这样风险过大,易过拟合。
    其次,数据的特征太少了,每一个电机只有【‘时间戳’,‘风速’,‘功率’,‘风轮转速’】四种特征,并且该数据集为时间序列,古可以做很多的特征衍生
    最后,可以通过一定的风电机组发动机实际物理模型进行数学意义上的异常分析,或通过图像法来人为选定异常值,当然,我们也可以按照比赛要求使用经典的无监督模型进行聚类分析

    本文主要从以下几个方面介绍:

    • 第一部分对数据做特征处理;
    • 第二部分将分别从单特正和多组联合特征直观展示每个风机的数据特征分布;
    • 第三部分基于规则筛选异常值;
    • 第四部分建立多个无监督聚类模型进行异常数据监测;如:DBSCAN、IsolationForest、Gaussian distribution;
    • 第五部分基于物理学理论模型建立风速和功率的回归模型,设定阀值确定异常数据。

    三、特征处理

    (一) 读取数据

    import pandas as pd
    import warnings
    import numpy as np
    import matplotlib.pyplot as plt
    warnings.filterwarnings('ignore')
    
    plt.rcParams['font.sans-serif'] =['SimHei'] ##显示中文
    plt.rcParams['axes.unicode_minus'] = False
    
    data = pd.read_csv('./data/dataset.csv')
    

    查看数据特征信息

    data.info()
    

    在这里插入图片描述

    data.head()
    

    在这里插入图片描述

    (二)特征工程

    特征工程没有什么标准规则来设计新的特征,可以根据业务设计出新的特征,也可以自己再不了解业务的情况下,设计出新的特征。以下设计的特征也是时间序列常用的一些特征衍生。

    1.单位风速和单位风机转速的功率

    data['per_windspeed_power'] = data['Power']/(data['WindSpeed']+0.0112) ###+0.0112防止分母为0
    data['per_rotorspeed_power'] = data['Power']/(data['RotorSpeed']+0.0112)
    

    2.单位功率的风速和单位功率的风机转速

    data['per_power_windspeed'] = data['WindSpeed']/(data['Power']+0.0112)
    data['per_power_rotorspeed'] = data['RotorSpeed']/(data['Power']+0.0112)
    

    3.时间特征
    根据时间特征,提取年、月、日、时、分、星期、工作日等特征

    def process_dt(df=None,dt=None):
        """
        df:dataFrame类型
        dt:日期类型列名,字符串
        """
        df['dateTime'] = pd.to_datetime(df[dt])
        df['day'] = df['dateTime'].dt.day
        df['hours'] = df['dateTime'].dt.hour
        df['minute'] =df['dateTime'].dt.minute
        return df
    data = process_dt(df=data,dt='Time')
    data = data.sort_values(['WindNumber','dateTime']).reset_index(drop=True)
    

    4.计算日志丢失率
    因为分机每十分钟生成一条运行数据,再某些情况下,可能会产生数据丢失,因此,有必要计算日志数据的每个时间点的丢失率。

    def generate_init(df=data,init_col_name=list(),group_col_name=None,dt=None):
    	"""
    	计算每一个风机最初特征值
    	"""
        init_data =data[[group_col_name]+init_col_name].sort_values(dt).drop_duplicates([group_col_name]).reset_index(drop=True)
        init_data.rename(columns=dict(zip(init_col_name,['init_'+col for col in init_col_name])),inplace=True)
        return init_data
    
    
    init_data=generate_init(data,['dateTime'],group_col_name='WindNumber',dt='dateTime')
    data = data.merge(['init_dateTime','WindNumber']],how='left',on=['WindNumber'])
    
    def stat_log_loss(df,group_col_name=None,date=None,init_date=None):
        """
        计算数据日志损失率,正常情况下,一台风机按照每10分中记录一次日志频率。
        """
        df[date]=pd.to_datetime(df[date])
        df[init_date]=pd.to_datetime(df[init_date])
        tmp =df[[group_col_name]]
        tmp['count']=10
        df['log_cumsum'] = tmp.groupby([group_col_name])['count'].transform(np.cumsum)
        df['miss_log_rate'] = 1-df['log_cumsum']/(((df[date]-df[init_date])/pd.Timedelta(1, 'min')).fillna(0).astype(int)+0.0001)
        return df
    
    data=stat_log_loss(data,group_col_name='WindNumber',date='dateTime',init_date='init_dateTime')
    
    

    5.差分特征

    def diff(df,diff_feature_list=list(),group_col_name='WindNumber',diff_number=list()):
        tmp = df.loc[:,[group_col_name]+diff_feature_list].groupby(group_col_name)
        for i in diff_number:
            diff_colname =['diff_{}_'.format(i)+col for col in diff_feature_list]
            df[diff_colname] = tmp[diff_feature_list].shift(0)-tmp[diff_feature_list].shift(i)
        del tmp
        return df
    
    data=diff(data,['WindSpeed','Power','RotorSpeed'],diff_number=[1,2,3,6,12])
    

    6.变化率

    def gct_change(df,gct_col=list(),group_col_name='WindNumber'):
        tmp= df.groupby([group_col_name])
        for col in gct_col:
            df['pct_'+col] = tmp[col].pct_change(fill_method='ffill')
            
        del tmp 
        return df
        
    data=gct_change(data,gct_col=['WindSpeed','Power','RotorSpeed'])
    

    7.指数平滑

    def ewm_calculate(df,ewm_col_list=list(),group_col_name='WindNumber',spans=list()):
        """
        指数平滑,取mean和std
        """
        tmp = df.groupby([group_col_name])
        for i in spans:
            for col in tqdm(ewm_col_list):
                df['ewm_'+str(i)+"_"+col+'_mean'] =tmp[col].transform(lambda x: pd.Series.ewm(x,span=i).mean())
                df['ewm_'+str(i)+"_"+col+'_std'] =tmp[col].transform(lambda x: pd.Series.ewm(x,span=i).std())
        del tmp
        return df
    
    data = ewm_calculate(data,ewm_col_list=['WindSpeed','Power','RotorSpeed'],group_col_name='WindNumber',spans=list([3,6,12]))
    

    8.缺失值填充

    ##按每组均值填充缺失值
    for column in list(data.columns[data.isnull().sum()>0]):
        data[column] =data[["WindNumber",column]].groupby("WindNumber").\
        transform(lambda x:x.fillna(x.mean()))
    ##或直接填充为0值
    for column in list(data.columns[data.isnull().sum()>0]):
        data[column].fillna(0,inplace=True)
    
    

    做完特征工程后,特征扩充到如下:

    featuresValuenot nulltype
    WindNumber497837non-nullint64
    Time497837non-nullobject
    WindSpeed497837non-nullfloat64
    Power497837non-nullfloat64
    RotorSpeed497837non-nullfloat64
    dateTime497837non-nulldatetime64[ns]
    day497837non-nullint64
    hours497837non-nullint64
    minute497837non-nullint64
    init_dateTime497837non-nulldatetime64[ns]
    log_cumsum497837non-nullint64
    miss_log_rate497837non-nullfloat64
    per_windspeed_power497837non-nullfloat64
    per_rotorspeed_power497837non-nullfloat64
    per_power_windspeed497837non-nullfloat64
    per_power_rotorspeed497837non-nullfloat64
    diff_1_WindSpeed497837non-nullfloat64
    diff_1_Power497837non-nullfloat64
    diff_1_RotorSpeed497837non-nullfloat64
    diff_2_WindSpeed497837non-nullfloat64
    diff_2_Power497837non-nullfloat64
    diff_2_RotorSpeed497837non-nullfloat64
    diff_3_WindSpeed497837non-nullfloat64
    diff_3_Power497837non-nullfloat64
    diff_3_RotorSpeed497837non-nullfloat64
    diff_6_WindSpeed497837non-nullfloat64
    diff_6_Power497837non-nullfloat64
    diff_6_RotorSpeed497837non-nullfloat64
    diff_12_WindSpeed497837non-nullfloat64
    diff_12_Power497837non-nullfloat64
    diff_12_RotorSpeed497837non-nullfloat64
    pct_WindSpeed497837non-nullfloat64
    pct_Power497837non-nullfloat64
    pct_RotorSpeed497837non-nullfloat64
    pct_miss_log_rate497837non-nullfloat64
    ewm_3_WindSpeed_mean497837non-nullfloat64
    ewm_3_WindSpeed_std497837non-nullfloat64
    ewm_3_Power_mean497837non-nullfloat64
    ewm_3_Power_std497837non-nullfloat64
    ewm_3_RotorSpeed_mean497837non-nullfloat64
    ewm_3_RotorSpeed_std497837non-nullfloat64
    ewm_6_WindSpeed_mean497837non-nullfloat64
    ewm_6_WindSpeed_std497837non-nullfloat64
    ewm_6_Power_mean497837non-nullfloat64
    ewm_6_Power_std497837non-nullfloat64
    ewm_6_RotorSpeed_mean497837non-nullfloat64
    ewm_6_RotorSpeed_std497837non-nullfloat64
    ewm_12_WindSpeed_mean497837non-nullfloat64
    ewm_12_WindSpeed_std497837non-nullfloat64
    ewm_12_Power_mean497837non-nullfloat64
    ewm_12_Power_std497837non-nullfloat64
    ewm_12_RotorSpeed_mean497837non-nullfloat64
    ewm_12_RotorSpeed_std497837non-nullfloat64

    四、数据可视化

    (一)单特征的数据可视化

    1.风速密度直方图

    plt.figure(figsize=(15,18))
    font = {'weight':'normal','size':10}
    for  i in list(range(1,13)):
        ax=plt.subplot(4,3,i)
        ax.hist(data.loc[data['WindNumber']==i,'WindSpeed'],range=(-0.1,16.5),bins=50,density=True)
        plt.xlabel("Power(kw)",fontdict=font)
        plt.ylabel("Probability",fontdict=font)
        plt.title(r"Histogram of $windNumber-%s WindSpeed"%i,fontdict=font)
        plt.tight_layout()
    plt.savefig('./pic/Power_WindSpeed.png',bbox_inches='tight',pad_inches=0.5,dpi=300)
    

    在这里插入图片描述可以看出大部分风机的样本风速呈现正太分布,只有6号风机和12号风机呈现正偏态。

    2.风机转速密度直方图

    plt.figure(figsize=(15,18))
    font = {'weight':'normal','size':10}
    for  i in list(range(1,13)):
        ax=plt.subplot(4,3,i)
        ax.hist(data.loc[data['WindNumber']==i,'RotorSpeed'],range=(-0.1,16.5),bins=50,density=True)
        plt.xlabel("RotorSpeed(m/s)",fontdict=font)
        plt.ylabel("Probability",fontdict=font)
        plt.title(r"Histogram of $windNumber-%s RotorSpeed"%i,fontdict=font)
        plt.tight_layout()
    plt.savefig('./pic/test.png',bbox_inches='tight',pad_inches=0.5,dpi=300)
    

    在这里插入图片描述
    从图中可以看出除了10号风机,其他的风机转速为0的概率密度较高,特别是12号风机较为异常。风机转速主要集中于8-15之间,我们可以推测在此范围外的风机转速出现异常数据可能性较大。

    3.风机功率密度直方图

    plt.figure(figsize=(15,18))
    font = {'weight':'normal','size':10}
    for  i in list(range(1,13)):
        ax=plt.subplot(4,3,i)
        ax.hist(data.loc[data['WindNumber']==i,'Power'],range=(-110,2200.5),bins=50,density=True)
        plt.xlabel("Power(kw)",fontdict=font)
        plt.ylabel("Probability",fontdict=font)
        plt.title(r"Histogram of windNumber-%s Power"%i,fontdict=font)
        plt.tight_layout()
    plt.savefig('./pic/Power_Histogram.png',bbox_inches='tight',pad_inches=0.5,dpi=300)
    

    在这里插入图片描述
    从图中可以看出,每台风机功率的分布并不是呈现正态分布,功率在0值附近概率分布较大。

    (二)组合特征数据可视化

    1.单位风速的功率和单位风机转速的功率散点图

    f=plt.figure(figsize=(15,12))
    font = {'weight':'normal','size':10}
    for  i in list(range(1,13)):
        ax=plt.subplot(4,3,i)
        Y= data.loc[data['WindNumber']==i,'per_windspeed_power'] 
        X=data.loc[data['WindNumber']==i,'per_rotorspeed_power'] 
        plt.xlabel("Power of per WindSpeed",fontdict=font)
        plt.ylabel("Power of per RotorSpeed",fontdict=font)
        plt.title(r"scatter figure of  windNumber-%s"%i,fontdict=font)
        T = np.arctan2(Y,X) #for color  value
        plt.scatter(X,Y,s=55,c=T,alpha=0.5)
        if i in [5,10,11,12]:
            plt.xlim((-50,150))
            plt.ylim((-50,350))
        else:
            plt.xlim((-300,150))
            plt.ylim((-150,250))
        plt.tight_layout()
    plt.savefig('./pic/per_Power.png',bbox_inches='tight',pad_inches=0.5,dpi=300)
    
    

    在这里插入图片描述从图中可以看出,1,2,3,4,6,7,8,9号风机有较多的功率为负值的情况(紫色区域),猜测这些点可能都是异常数据。还有部分点明显偏离整体区域,如:风机11,12绿色区域的点,因此这些点也可以定义为异常值。

    2.单位功率的风速和单位功率的风机转速散点图

    
    f=plt.figure(figsize=(15,12))
    font = {'weight':'normal','size':10}
    plt.title(r"scatter of  windNumber-%s of windspeed and rotorspee of  per Power "%i,fontdict=font)
    for  i in list(range(1,13)):
        ax=plt.subplot(4,3,i)
        Y= data.loc[(data['WindNumber']==i)&(data['Power']>=0),'per_power_windspeed'] 
        X=data.loc[(data['WindNumber']==i)&(data['Power']>=0),'per_power_rotorspeed'] 
        plt.title(r"scatter figure of  windNumber-%s"%i,fontdict=font)
        plt.xlabel("WindSpeed of per Power",fontdict=font)
        plt.ylabel("RotorSpeed of per Power",fontdict=font)
        T = np.arctan2(Y,X) #for color  value
        plt.scatter(X,Y,s=35,c=T,alpha=0.5)
        plt.tight_layout()
    
    plt.savefig('./pic/windspeed_and_rotorspeed_per_Power.png',bbox_inches='tight',pad_inches=0.5,dpi=300)
    

    在这里插入图片描述正常情况下单位功率的风速和单位功率的风机转速都是在0值(非负)附近,但是由于个别值偏离,导致x,y轴坐标偏大,从图中可以很明显看出5,11,12号风机出现较多的单位功率的风速和单位功率的风机转速较大的情况,即功率较小或者为0,但是风速和转速较大或不为0。

    当把X轴坐标取值范围定义为[0,0.5],Y轴坐标取值范围定义为[0,0.2],单位功率的风速和单位功率的风机转速散点图呈现正向线性关系。
    在这里插入图片描述

    五、基于规则筛选异常数据

    基于以上分析及赛题对风机特征定义,本文给出几个基于规则定义异常数据标准:

    • 风速、风机转速、功率其中任意一个小于等于0;
    • 风速小于切入,功率大于0;
    • 风速大于切除,功率大于0;
    • 功率大于额定功率1.2倍;

    这是赛题中

    index_df = pd.read_excel('../data/index.xlsx', names=["WindNumber", "fan_diam", "rated_power",\
     "speed_in", "speed_out", "speed_min", "speed_max"])
    index_df
    

    在这里插入图片描述

    data = data.merge(index_df, on='WindNumber')
    

    基于自定义规则筛选异常值

    data['label'] = 0
    #异常值
    #三列值小于0
    data.loc[(data['WindSpeed'] <= 0) ,'label'] = 1
    data.loc[(data['Power'] <=0    ) ,'label'] = 1
    data.loc[(data['RotorSpeed'] <= 0),'label'] = 1
    #风速小于切入,功率大于0
    data.loc[(data['WindSpeed'] < data['speed_in'])  & (data['Power'] > 0 ) ,'label'] = 1
    #风速大于切除,功率大于0
    data.loc[(data['WindSpeed'] > data['speed_out']) & (data['Power'] > 0)  ,'label'] = 1
     
    #功率大于额定功率1.2倍
    data.loc[ data['Power'] > 1.2*data['rated_power'] ,'label'] = 1
    

    基于规则,筛选的异常值在15以上,直接将其提交成绩在80左右。
    在这里插入图片描述

    六、基于聚类算法的异常数据筛选

    这一部分主要是基于规则筛选异常值后,对于剩余样本值进一步通过聚类算法筛选,用到的聚类算法有,k-means,DBSCAN,IsolationForest、Gaussian distribution;

    (一) k-means算法

    import pandas as pd
    from sklearn.cluster import KMeans,MiniBatchKMeans
    from sklearn.preprocessing import StandardScaler
    from sklearn.metrics import silhouette_score
    from sklearn.pipeline import Pipeline
    from scipy.spatial.distance import cdist
    from sklearn import metrics
    import numpy as np
    
    %matplotlib inline
    import matplotlib.pyplot as plt
    from matplotlib.font_manager import FontProperties
    import matplotlib as mpl
    mpl.rcParams['font.sans-serif'] = [u'SimHei']  # 黑体 FangSong/KaiTi
    mpl.rcParams['axes.unicode_minus'] = False
    
    def kmeans_model(k,isStandard=True):
    	"""
    	定义kmeans的model 
    	"""
        if isStandard:
            model = Pipeline([
            ('ss', StandardScaler()), #数据标准化过程
            ('kmeans', KMeans(n_clusters=k, init='k-means++',n_jobs=-1))])
        else:
              model = Pipeline([
            ('kmeans', KMeans(n_clusters=k, init='k-means++',n_jobs=-1))])
        return model
    
    
    
    def evaluate(model,data,method='elbow'):
        """
        三种方法来评估肘部法则(MeanDistortions),轮廓系数(Silhouette),elbow方法
        """
        if method.lower() =='elbow':
            return model.score(data)
        
        elif method.lower() =='silhouette':
            return metrics.silhouette_score(data,model._final_estimator.labels_)
        
        else:
            return sum(np.min(
                cdist(data,model._final_estimator.cluster_centers_,
                     'euclidean'),axis=1))/data.shape[0]
        
    ### 筛选出最优的k(簇数)
    features=['WindSpeed','Power','RotorSpeed']
    data1=data[(data['WindNumber']==1)&(data['label']==0)][features]
    K=range(2,22)
    plt.figure(figsize=(15, 5), facecolor='#FFFFFF')
    font = {'weight':'normal','size':14}
    for index,method in enumerate(['elbow','silhouette','MeanDistortions']):
        ax=plt.subplot(1,3,index+1)
        scores=[]
        for k in K:
            model=kmeans_model(k,isStandard=True)
            model.fit(data1)
            score = evaluate(model,data1,method=method)
            scores.append(score)
        plt.plot(K,scores,'bx-')
        plt.xlabel('k',fontdict=font)
        plt.ylabel(u'%s scores'%method,fontdict=font)
    plt.tight_layout(2.5)
    plt.subplots_adjust(top=0.92)
    plt.suptitle(u'k-means evaluate score', fontsize=18)
    
    

    在这里插入图片描述为了找出合理的距离中心数,我们尝试尽可能多的聚类中心数(从1个到20个聚类中心),然后我们画出多种评估方法曲线,通过观察我们发现当我们的聚类中心数量增加到10个以上时三种评估方法曲线趋于收敛,因此我们大致可以将聚类中心数定为10.

    # 计算每个数据点到其聚类中心的距离
    from sklearn.preprocessing import StandardScaler
    def getDistanceByPoint(df1, model):
        ss = StandardScaler()
        nd=ss.fit_transform(df1)
        distance = []
        for i in range(0,len(df1)):
            Xa = np.array(nd[i,:])
            Xb = model._final_estimator.cluster_centers_[model._final_estimator.labels_[i]]
            distance.append(np.linalg.norm(Xa-Xb))
        return pd.Series(distance)
    
    ##针对每一类机组做10个簇聚类模型,设定阈值,筛选出每一类的阈值之外样本作为异常值。
    for num in WindNumberList:
        df1 = data[(data['WindNumber']==num)&(data['label']==0)][features].copy()
        model = kmeans_model(k=10)
        #设置异常值比例
        #df1 = df1.reset_index(drop=True)
        model.fit(df1)
        outliers_fraction = 0.1
        # 得到每个点到取聚类中心的距离,我们设置了10个聚类中心,kmeans[9]表示有10个聚类中心的模型
        distance = getDistanceByPoint(df1, model)
        #根据异常值比例outliers_fraction计算异常值的数量
        number_of_outliers = int(outliers_fraction*len(distance))
        #设定异常值的阈值
        threshold = distance.nlargest(number_of_outliers).min()
        #根据阈值来判断是否为异常值
        distace =list((distance >= threshold).astype(int))
        df1['label'] = distace
        data.iloc[df1[df1['label']==1].index,5] = 1
    
    

    在这里插入图片描述根据文献资料,风机的功率和风速是呈现函数关系,因此这里我们做了一个功率和风速的散点图,图中红色点标记为异常点,一些离群的样本被筛选出来,最后综合得分在0.87左右,因此模型达到预期提升效果。但是k-means模型任然有很多不足地方,例如设计阈值,聚类簇数以及聚类中心处置的选择等,都是一些超参数,直接影响模型聚类效果。

    (二) DBSCAN算法

    DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪声的基于密度的聚类方法)是一种基于密度的空间聚类算法。 该算法将具有足够密度的区域划分为簇,并在具有噪声的空间数据库中发现任意形状的簇,它将簇定义为密度相连的点的最大集合。

    形象来说,我们可以认为这是系统在众多样本点中随机选中一个,围绕这个被选中的样本点画一个圆,规定这个圆的半径以及圆内最少包含的样本点,如果在指定半径内有足够多的样本点在内,那么这个圆圈的圆心就转移到这个内部样本点,继续去圈附近其它的样本点,类似传销一样,继续去发展下线。等到这个滚来滚去的圈发现所圈住的样本点数量少于预先指定的值,就停止了。那么我们称最开始那个点为核心点,如A,停下来的那个点为边界点,如B、C,没得滚的那个点为离群点,如N

    def dbscn_model(df,standar=True,eps=10, min_samples=2):
    "dbscan模型的算法"
        if standar:
            model = Pipeline([
            ('ss', StandardScaler()), #数据标准化过程
            ('dbscan', DBSCAN(eps=eps, min_samples=min_samples))])
        else:
              model = Pipeline([
            ('dbscan', DBSCAN(eps=eps, min_samples=min_samples))])
        model.fit(df)
        return model
    
    
    new_data=pd.DataFrame()
    new_data=new_data.append(data[data['label']==1])
    features=['WindSpeed','Power']
    
    for num in WindNumberList:
        df1 = data[(data['WindNumber']==num)&(data['label']==0)].copy()
    	##min_samples最小样本点个数,eps核心区域半径
        dbscan = dbscn_model(df1[features],standar=True,eps=0.15,min_samples=7) 
        label = list(dbscan._final_estimator.labels_)
        modeNumber = stats.mode(label)[0][0]
        newLabelList =[]
        if modeNumber !=0:
            print("风机%s-【%s】"%(num,modeNumber))
            ##筛选出聚类后少数样本群体作为异常点
            for i in label:
                if i==modeNumber:
                    newLabelList.append(0)
                elif i==0:
                    newLabelList.append(modeNumber)
                else:
                    newLabelList.append(i)
        else:
            newLabelList.extend(label)
        df1['label'] = newLabelList
        new_data=new_data.append(df1)
        print("风机%s利用DBSCAN算法筛选后异常值数量【%s】"%(num,len(df1[df1['label']!=0])))
    new_data = new_data.sort_values(['WindNumber','Time']).reset_index(drop=True)
    new_data.loc[new_data['label']!=0,'label']=1
        
    

    在这里插入图片描述基于dbscan算法筛选异常值,模型综合得分和kmeans差不多,同样DBSCAN聚类算法也是超参数(min_samples最小样本点个数,eps核心区域半径)比较难以控制,并且DBSCAN适合于那些小规模异常点的识别。

    (三) 孤立森林(IsolationForest)异常检测

    IsolationForest算法它是一种集成算法(类似于随机森林)主要用于挖掘异常(Anomaly)数据,或者说离群点挖掘,总之是在一大堆数据中,找出与其它数据的规律不太符合的数据。该算法不采样任何基于聚类或距离的方法,因此他和那些基于距离的的异常值检测算法有着根本上的不同,孤立森林认定异常值的原则是异常值是少数的和不同的数据。它通常用于网络安全中的攻击检测和流量异常等分析,金融机构则用于挖掘出欺诈行为。

    ●当我们使用IsolationForest算法时需要设置一个异常值比例的参数contamination, 该参数的作用类似于之前的outliers_fraction。
      ●使用 fit 方法对孤立森林模型进行训练
      ●使用 predict 方法去发现数据中的异常值。返回1表示正常值,-1表示异常值。

    def isolationForest_model(contamination='auto',max_samples=0.1,isStandard=True):
        if isStandard:
            model = Pipeline([
            ('ss', StandardScaler()), #数据标准化过程
            ('iForest', IsolationForest(max_samples=max_samples,contamination=contamination))])
        else:
              model = Pipeline([
            ('iForest', IsolationForest(max_samples=max_samples,contamination=contamination))])
        return model
    
    features=['WindSpeed','Power', 'RotorSpeed']
    new_data=pd.DataFrame()
    new_data=new_data.append(data[data['label']==1])
    WindNumberList = list(data['WindNumber'].unique())
    
    
    for num in WindNumberList:
        df1 = data[(data['WindNumber']==num)&(data['label']==0)].copy()
        model = isolationForest_model(isStandard=True,contamination=0.05)
        model.fit(df1[features])
        #返回1表示正常值,-1表示异常值
        result = model.predict(df1[features])
        df1['label'] = result
        df1['label']=df1['label'].map({-1:1,1:0})
        new_data=new_data.append(df1)
        print("机组-【%s】,总数据量-【%s】,异常数据量-【%s】"%(num,len(df1),len(df1[df1['label']!=0])))
    new_data = new_data.sort_values(['WindNumber','Time']).reset_index(drop=True)
    new_data.loc[new_data['label']!=0,'label']=1
    

    在这里插入图片描述
    基于dbscan算法筛选异常值,其综合得分0.84,并没有实现预期显著提高,其主要原因是孤立森林算法的理论基础需要满足以下两点基础:

    • (1)异常数据占总样本量的比例很小;
    • (2)异常点的特征值与正常点的差异很大。

    (四)基于高斯概分布的异常检测

    高斯分布也称为正态分布。 它可以被用来进行异常值检测,不过我们首先要假设我们的数据是正态分布的。 不过这个假设不能适应于所有数据集。但如果我们做了这种假设那么它将会有一种有效的方法来发现异常值。

    多元正态分布密度函数
    在这里插入图片描述

    Scikit-Learn的EllipticEnvelope模型,它在假设我们的数据是多元高斯分布的基础上计算出高斯分布的一些关键参数过程。过程大致如下:
      ●在排除规则定义异常数据之外的剩余数据集应用EllipticEnvelope(高斯分布)。
      ●我们设置contamination参数,它表示我们数据集中异常值的比例。
      ●使用decision_function来计算给定数据的决策函数。 它等于移位的马氏距离(Mahalanobis distances)。 异常值的阈值为0,这确保了与其他异常值检测算法的兼容性。
      ●使用predict 来预测数据是否为异常值(1 正常值, -1 异常值)

    #针对机组1特征做高斯模型(手写算法模型)
    import numpy as np 
    import matplotlib.pyplot as plt 
    import scipy.io as sio
    import pandas as pd
    
    #获取训练集中的均值和方差
    def estimateGaussian(X,isCovariance):
        
        X_mean = np.mean(X,axis=0)  # (1,2),按列求均值
        if isCovariance:  #(多元高斯分布)
            sigma = (X-X_mean).T @ (X-X_mean) / len(X)  #(2,2)
        else:  #(原始高斯分布)
            sigma = np.var(X,axis=0)  #(1,2)求方差,按列
        return X_mean,sigma
    
    #高斯分布函数
    def gaussian(X,means,sigma):
        
        if np.ndim(sigma) == 1:  #np.ndim判断矩阵为几维。向量为一维,矩阵为二维,若有3个[],即为3维
            sigma = np.diag(sigma)  #若为一维,则生成一个以一维数组为对角线元素的矩阵;二维则输出对角线元素
        n = X.shape[1]
        first = np.power(2*np.pi,-n/2) * (np.linalg.det(sigma)**(-0.5))  #np.linalg.det求矩阵的行列式,**的意思是次方
        second = np.diag((X-means)@(np.linalg.inv(sigma))@(X-means).T)
    #     print(second)
        P = first * np.exp(-0.5*second)
        P = P.reshape((-1,1))   #(任意行,1)
        return P   #(307,1)
    
    #画等高线
    def plotGaussian(X,means,sigma):
        
        x = np.arange(-1, 3.5, 0.1) 
        y = np.arange(-1, 3.5, 0.1)
        xx, yy = np.meshgrid(x,y)  
        z= gaussian(np.c_[xx.flatten(),yy.flatten()], means, sigma)  # 计算对应的高斯分布函数
        zz = z.reshape(xx.shape)  
        plt.plot(X[:,0],X[:,1],'bx')
        plt.xlim((-1,3.5))
        plt.ylim((-1,3.5))
        contour_levels = [10**h for h in range(-20,0,3)]
        plt.contour(xx, yy, zz, contour_levels)
    
    
    df1=data[(data['WindNumber']==1)&(data['label']==0)].copy()
    features=['per_power_windspeed','per_power_rotorspeed']
    means,sigma1 = estimateGaussian(df1[features].values,isCovariance = True)
    plotGaussian(df1[features].values,means,sigma1)
    

    图4
    针对所有机组利用sklearn的API接口做高斯模型的的异常检测,代码如下:

    from sklearn.covariance import EllipticEnvelope
    from sklearn.pipeline import Pipeline
    from sklearn.preprocessing import StandardScaler
    
    def gaussian_model(contamination=0.05,standar=True):
        if standar:
            model = Pipeline([
            ('ss', StandardScaler()), #数据标准化过程
            ('gaussian', EllipticEnvelope(contamination=contamination))])
        else:
              model = Pipeline([
            ('gaussian', EllipticEnvelope(contamination=contamination))])
        return model
    
    
    WindNumberList = list(data['WindNumber'].unique())
    features=['per_power_windspeed','per_power_rotorspeed']
    new_data=pd.DataFrame()
    new_data=new_data.append(data[data['label']==1])
    
    
    for num in WindNumberList:
        df1 = data[(data['WindNumber']==num)&(data['label']==0)].copy()
        model = gaussian_model(standar=True,contamination=0.05)
        model.fit(df1[features])
        #返回1表示正常值,-1表示异常值
        result = model.predict(df1[features])
        df1['label'] = result
        df1['label']=df1['label'].map({-1:1,1:0})
        new_data=new_data.append(df1)
        print("机组-【%s】,总数据量-【%s】,异常数据量-【%s】"%(num,len(df1),len(df1[df1['label']!=0])))
    

    在这里插入图片描述

    基于高斯概分布的异常检测,综合得分低于0.8,效果比基于规则的判断异常值更低,其主要原因在于’per_power_windspeed’和’per_power_rotorspeed’这两个特征并不是呈现多元正太分布,因此基于高斯概分布的异常检测的前提假设并不成立导致模型应用效果并不理想。

    七、基于线性回归算法的异常数据筛选

    我们可以基于线性模型拟合风速和功率,并计算预测值和真实值的误差值,设定阈值,确定风机数据是否异常。

    import time
    import pandas as pd
    import numpy as np
    import warnings
    warnings.filterwarnings('ignore')
    
    from sklearn.linear_model import LinearRegression,RANSACRegressor
    from sklearn.preprocessing import PolynomialFeatures,StandardScaler
    
    def sample_data(data,i,scal):
        """
        按照排除规则按照分层取样
        """
        one=data[(data.WindNumber==i)&(data.label==0)]
        to_train_regression=one[(data.day<sup)&(data.day>inf)][data.Power<2000]
        to_train_regression['Power_n']=np.floor(to_train_regression.Power/scal)
        target_num = int(to_train_regression.groupby("Power_n")['Power_n'].count().quantile(0.4))
        sample_datas = []
        for pn in to_train_regression['Power_n'].unique().tolist():
            to_samp_data =to_train_regression[to_train_regression.Power_n==pn]
            al = to_samp_data['Power_n'].count()
            sample_data = to_samp_data.sample(n=min(target_num,al) )
            sample_datas.append(sample_data)
            
        return sample_datas
    
    
    data['timeStamp'] = data.apply(lambda x:time.mktime(time.strptime(x['Time'],'%Y/%m/%d %H:%M')),axis=1 )
    data['day'] = data.apply(lambda x: int(x['timeStamp'] /(3600*24)) ,axis=1 )
    
    
    models= []
    scal=10
    max_=[20000,20000,17750,20000,18200,20000,20000,20000,20000,20000,20000,20000]
    min_=[17780,17800,17650,18100,18100,17780,17800,17770,17770,18100,18100,18100]
    for i in list(range(12)):
        sup = max_[i]
        inf = min_[i]
        i=i+1
        sample_datas = sample_data(data,i,sup,inf,scal)
        d = pd.concat(sample_datas)
        x=d[['Power']]
        y=d[['WindSpeed']]
        ## 使用RANSAC清除异常值高鲁棒对的线性回归模型
        poly_linear_model = RANSACRegressor(LinearRegression(),loss='squared_loss' )
        ## PolynomialFeatures 扩充特征
        poly_linear_model.fit(PolynomialFeatures(degree = 3).fit_transform(x), y) 
        models.append(poly_linear_model)
    
    max_p=2000
    resx = []
    for i in list(range(12)):
        modle = models[i]
        i=i+1
        q1 = data[data.WindNumber==i]
        py=modle.predict(PolynomialFeatures(degree = 3).fit_transform(q1[['Power']]))
        q1['diffpWindSpeed']=(py-q1[['WindSpeed']])
        f=-1.1
        max_p =q1.Power.max()-150
        q1['ds']=q1.apply(lambda x:0 if ( (x['diffpWindSpeed'] > f and x['diffpWindSpeed'] <-f*1.5) or x['Power']>max_p )    else 1,axis=1)
        resx.append(q1)
    r = pd.concat(resx)
    r.sort_index()
    data['ds']=r['ds']
    data['diffpWindSpeed']= r['diffpWindSpeed']
    data['label']=data.apply(lambda x: 1 if (x['label']==1 or  x['ds']==1 ) else 0 ,axis=1)
    

    在这里插入图片描述
    基于线性模型拟合风速和功率,计算风速预测值和真实值差值,设定阈值,达到清洗异常数据的目的,其综合得分在0.9以上。模型效果显著提高。从上图中风机10和风机7还有小部分数据偏离整体群体,因此可以DBSCAN算法识别这部分k离群点。其最终模型效果F1score可以达到0.93以上。最终清洗后,风机功率散点图如下:
    在这里插入图片描述
    结束语:,本次数据风机异常数据的清洗主要利用“规则+线性拟合+DBSCAN聚类算法”三种方式组合完成数据清洗。由于本赛题属于无监督学习,对于所应用模型超参数调节很难控制,只能根据每天三次提交获得分数估计超参数是否合适。后期可以针对前面扩充的特征作为自变量,和已经预测出的label做半监督学习分类模型训练,或许效果更好。

    展开全文
  • 异常数据处理

    千次阅读 2019-07-06 09:49:44
    常用处理方法: 异常值的处理方法常用有四种: 1.删除含有异常值的记录 2.将异常值视为缺失值,...# 异常数据处理(异常数据过滤) new_df = df.replace('?', np.nan)#替换非法字符为np.nan datas = new_df.dropna(...

    常用处理方法:

    异常值的处理方法常用有四种

    1.删除含有异常值的记录

    2.将异常值视为缺失值,交给缺失值处理方法来处理

    3.用平均值来修正

    4.不处理

    需要强调的是,如何判定和处理异常值,需要结合实际

     

    # 异常数据处理(异常数据过滤)
    new_df = df.replace('?', np.nan)#替换非法字符为np.nan
    datas = new_df.dropna(axis=0,how = 'any') # 只要有一个数据为空,就进行行删除操作
    datas.describe().T#观察数据的多种统计指标

    关于replace函数

    语法:replace(self, to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad', axis=None)

    使用方法如下:

    1

    2

    3

    4

    import numpy as np

    import pandas as pd

    df = pd.read_csv('emp.csv')

    df

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    #Series对象值替换

    s = df.iloc[2]#获取行索引为2数据

    #单值替换

    s.replace('?',np.nan)#用np.nan替换?

    s.replace({'?':'NA'})#用NA替换?

    #多值替换

    s.replace(['?',r'$'],[np.nan,'NA'])#列表值替换

    s.replace({'?':np.nan,'$':'NA'})#字典映射

    #同缺失值填充方法类似

    s.replace(['?','$'],method='pad')#向前填充

    s.replace(['?','$'],method='ffill')#向前填充

    s.replace(['?','$'],method='bfill')#向后填充

    #limit参数控制填充次数

    s.replace(['?','$'],method='bfill',limit=1)

    #DataFrame对象值替换

    #单值替换

    df.replace('?',np.nan)#用np.nan替换?

    df.replace({'?':'NA'})#用NA替换?

    #按列指定单值替换

    df.replace({'EMPNO':'?'},np.nan)#用np.nan替换EMPNO列中?

    df.replace({'EMPNO':'?','ENAME':'.'},np.nan)#用np.nan替换EMPNO列中?和ENAME中.

    #多值替换

    df.replace(['?','.','$'],[np.nan,'NA','None'])##用np.nan替换?用NA替换. 用None替换$

    df.replace({'?':'NA','$':None})#用NA替换? 用None替换$

    df.replace({'?','$'},{'NA',None})#用NA替换? 用None替换$

    #正则替换

    df.replace(r'\?|\.|\$',np.nan,regex=True)#用np.nan替换?或.或$原字符

    df.replace([r'\?',r'\$'],np.nan,regex=True)#用np.nan替换?和$

    df.replace([r'\?',r'\$'],[np.nan,'NA'],regex=True)#用np.nan替换?用NA替换$符号

    df.replace(regex={r'\?':None})

    #value参数显示传递

    df.replace(regex=[r'\?|\.|\$'],value=np.nan)#用np.nan替换?或.或$原字符

    删除缺失数据
    df.dropna(axis=0, how='any')
    #any表示删除包含任何NaN值的给定轴,how=all会删除所有元素都是NaN的给定轴

    展开全文
  • 数据分析和建模的过程中,有相当多的时间要用在数据准备上:加载、清理、转换以及重塑。这些工作会占到分析师时间的80...数据处理中的清洗工作主要包括对需要分析的数据集中的缺失值(空值)、重复值、异常值的处理。
  • Python异常数据处理——箱型图分析

    万次阅读 2020-08-05 15:35:51
    在数据分析中,利用箱型图的方法对异常数据进行过滤,是一种很快速、很有效的异常数据处理方法。 箱形图(英文:Box plot),又称为盒须图、盒式图、盒状图或箱线图,是一种用作显示一组数据分散情况资料的统计图。...
  • 由于传感器故障、系统误差、多异构数据源、网络传输乱序等因素极易出现噪声、缺失值、数据不一致的情况,如何消除这些因素对模型精度和可靠性产生的负面影响……
  • 请问 Excel 如何剔除与平均数偏差较大的数字再求平均数?谢谢。把问题作为内容(邮件主定要包含“excel”,本人以此据辨别非垃圾邮件...yqch134@163.com怎么样在excel中剔除自己不想要的数据????筛选 删除如何在exc...
  • ![图片说明](https://img-ask.csdn.net/upload/201902/11/1549870745_801303.jpg) 数据源是csv格式的表格,图像是用weka生成的,怎样用python或者java去掉图中圈住的异常数据,然后将异常数据还原?
  • R语言:异常数据处理

    千次阅读 2019-06-05 14:36:42
    为了有效的避免这些异常点造成的损失,我们需要采取一定的方法对其进行处理,而处理的第一步便是找到异常点在数据中的位置。   什么是异常值?如何检测异常值? 目录  1. 单变量异常值检测  2. 使用LOF(...
  • 异常数据剔除

    万次阅读 2017-08-30 18:07:03
    1.在SPSS中做箱型图,图中可以显示异常值,然后剔除。但问题是大数据,采用箱形图已经不显示了 2.拉依达准则法(3δ):简单,无需查表。测量次数较多或要求不高时用。是最常用的异常值判定与剔除准则。但当测量...
  • 现在有这样一组数据,希望去除掉里面的异常数据。其中,异常数据可能比正常数据大也可能比正常数据小,可能是正的也可能是负的。 数据为deg=[] import numpy as np if(True): #new_nums = list(set(deg)) #...
  • 拉依达准则去除异常数据

    千次阅读 2020-07-25 17:07:15
    拉依达准侧(Pau’ta Criteron)是先假设一组数据中只含有随机误差,首先按照一定准侧计算标准偏差,按照一定概率确定一定区间,认为不在这个区间的为异常值。 使用数据类型:数据呈正太分布或者近似正太分布。 2....
  • 在19世纪,统计分析方法主要应用在生物数据分析,是习惯的研究人员假设观察遵循正态分布,如乔治·艾里先生和梅里曼教授,其作品被批评卡尔·皮尔逊在他的1900纸。 直到19世纪末,皮尔森注意到在一些生物观察中...
  • 要求用MATLAB写一个可以实现异常数据检测的程序,急求大神回复。
  • 利用标准差剔除异常数据

    千次阅读 2019-03-27 21:53:00
    此时利用标准差,可以发现此时标准差过大,抛弃此次数据,从而避免电池电量跳变。如若采用平均值滤波的方法(去除最高和最低值后求平均值)在采集到多个异常的场景无法剔除异常。 float calculate_sd(uint32_t *data...
  • 介绍: 在统计理论中,肖维勒准则(以William ...通过这样做,来自位于该概率带之外的n个样本的任何数据点可以被认为是异常值,从数据集中移除,并且可以计算基于剩余值和新样本大小的新的均值和标准偏差。 ...
  • 去除异常数据的思路

    千次阅读 2013-08-16 16:34:13
    在对大量数据进行分析时 如果有些数值不符合正常情况 可以用以下方法尝试 去异常值: 求出所有数值的均值m(主要不要去重) m=(x1+x2+....xn)/n 求出所有数值的标准差 s 标准差计算公式 : s=Math.Sqrt((x1...
  • 利用格拉布斯准则,剔除异常数据

    万次阅读 2018-08-13 15:31:02
    4、用这个Gi 值 与 格拉布斯临界表表中的 临界值比较,越大,越异常,需剔除 注: 这个临界值 与 顶尖水平(alpha)有关 在0.01 - 0.99中选,越小越严格 ,以及测量次数(数组集合长度) 查格拉布斯...
  • 拉依达准则是指先假设一组检测数据只含有随机误差,对其进行计算处理得到标准偏差,按一定概率确定一个区间,认为凡超过这个区间的误差,就不属于随机误差而是粗大误差,含有该误差的数据应予以剔除。 这种判别处理...
  • 异常数据处理——箱型图分析原理

    千次阅读 2018-09-13 12:41:59
    箱型图可以通过程序设置一个识别异常值的标准,即大于或小于箱型图设定的上下界的数值则识别为异常值,箱型图如下图所示: 首先我们定义下上四分位和下四分位: 上四分位我们设为 U,表示的是所有样本中只有1/4...
  • 那么,最近我发现,这个@Transactional的注解,并不是所有异常都可以进行数据回滚,他只有是RuntimeException类及其子类(中文称为:运行时异常/unchecked异常/未检异常异常的时候才会进行数据...
  • 基于深度学习的日志数据异常检测

    万次阅读 多人点赞 2020-12-27 12:00:12
    基于日志数据异常检测 数据对象 智能运维(AIOps)是通过机器学习等算法分析来自于多种运维工具和设备的大规模数据。智能运维的分析数据对象多源运维数据包括系统运行时数据和历史记录数据,历史记录数据主要包含...
  • 有时也称非离群点为“正常数据”,离群点为“异常数据”。 离群点跟噪声数据不一样,噪声是被观测变量的随机误差或方差。一般而言,噪声在数据分析(包括离群点分析)中不是令人感兴趣的,需要在数据预处理中剔除的...
  • 数据分析--异常值处理

    千次阅读 2020-10-04 18:19:35
    模型通常是对整体样本数据结构的一种表达方式,这种表达方式通常抓住的是整体样本一般性的性质,而那些在这些性质上表现完全与整体样本不一致的点,我们就称其为异常异常点在某些场景下极为重要,如疾病预测,...
  • Python数据分析基础: 异常值检测和处理

    万次阅读 多人点赞 2020-10-31 22:05:31
    本篇继续分享数据清洗中的另一个常见问题:异常值检测和处理。 1 什么是异常值? 在机器学习中,异常检测和处理是一个比较小的分支,或者说,是机器学习的一个副产物,因为在一般的预测问题中,模型通常是对整体样本...
  • 数据清洗:异常值识别和处理方法

    千次阅读 2022-04-26 10:47:46
    异常数据识别 异常数据是数据分布的常态,处于特定分布区域之外的数据通常会被定义为异常或“噪音”。产生数据“噪音”的原因很多,例如业务运营操作、数据采集问题、数据同步问题等。对异常数据进行处理前,需要先...
  • 数据预处理_异常值处理

    千次阅读 多人点赞 2020-04-12 18:45:53
    异常值 1.异常值是指样本中的个别值,其数值明显偏离其余的...真异常,并非业务运营而产生的,是客观反映数据本身存在异常的分布。 3.异常值分析 3σ原则 箱型图 4.异常值的处理方法 剔除异常值 视为缺...
  • 数据异常异常检测方法

    千次阅读 2018-09-27 14:45:04
    1.在线流数据异常检测(iforest隔离森林算法) 该方法的主要思想是,通过随机选定样本属性及其值...该方法是基于异常数据“少且不同”的特征,来采用随机隔离的思想设计异常检查。 该方法的主要优点是,在构建初始...
  • 第一次发表博客,先发一个简单的...最近在做一个项目(android端),需要剔除异常数据,就是根据之前一组数据判断新来的数据是否为合理数据,在相差过大的时候予以剔除,找到了格拉布斯准则,具体内容和步骤参见链接...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,955,866
精华内容 782,346
关键字:

异常数据