02多元异常点检测

第零步 : 明确任务

  1. 多元异常值检测(多元, 异常值检测)
  2. 可视化定性分析
  3. 定量分析与异常值处理

完成所有工作之后,进行了回溯,对上一步进行优化:

一. 明确一个大概:

  1. 明确是哪个方向的任务(有监督 / 无监督 / 半监督)
  2. 明确是什么样的任务(分类 / 回归)
  3. 大方向是什么( 预测 / 优化 )

二. 任务的初步探索

  1. 数据层
    1.1 定性方面
    1.2 定量方面
  2. 特征层
    2.1 定性方面
    2.2 定量方面
  3. 模型层:
    3.1 模型选取
    3.2 训练、验证及参数调整策略
    3.3 优化方法与融合方式

第一步:查看数据

在这里插入图片描述

从这里看出,数据是按照一定规则进行分布的(一定规则 : 每个数据之间是用 空格隔开的 , 且每一行都有5列,每个行之间是靠换行符隔开的 )

并且这些数据后面都写上了 e-02, 或 e-03: 那这里是什么意思呢?

答: 这里是表示小数点后几位的意思,也就是小数点要移动几位的意思

举例: 1.22e-02 = 小数点往前移动两位 = 0.0122
/ 这里的 - 代表 缩小的意思

这里的分割方式是 sep = " "

这里不需要第一行作为列名,因此需要在后面的地方进行设置,header = None

解决完上面的所有之后,才是正式对数据进行探索和处理

第二步:数据探索

2.1 读取数据

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt 

import seaborn as sns

path = r"F:/Python_Tensorflow_codes/006group_learning/team-learning-data-mining-master/AnomalyDetection/outlier.txt"
# df_txt1 = pd.read_csv(path, header=None)
# print(df_txt1)

df_txt = pd.read_table(path, sep=" ", header=None)

df_txt
01234
00.0368530.0343900.091979-0.010263-0.008141
1-0.0011520.021750-0.0204010.009866-0.034471
2-0.0125860.0473640.011108-0.011569-0.023341
3-0.0283780.0439800.0012640.0231380.005426
40.0222250.007152-0.037135-0.029387-0.099154
..................
9950.006989-0.0399000.013303-0.0354760.068688
996-0.004276-0.028075-0.000769-0.051646-0.057467
997-0.0005440.059539-0.0128970.032994-0.089494
998-0.0396970.000563-0.0329770.0154410.007677
999-0.0108660.0226040.014564-0.014077-0.025783

1000 rows × 5 columns

2.2 查看数据的基本信息和常见的统计量

从上面的结果看出数据一共有5列columns,一共有1000行rows

我们要想检测异常值,先针对第一列进行,然后用循环的方式去遍历其他的类别

df_txt.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 5 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   0       1000 non-null   float64
 1   1       1000 non-null   float64
 2   2       1000 non-null   float64
 3   3       1000 non-null   float64
 4   4       1000 non-null   float64
dtypes: float64(5)
memory usage: 39.2 KB
  1. 这个数据集一共有1000个样本, 且 数据样本是从 0 — 999

RangeIndex: 1000 entries, 0 to 999 ::: ‘RangeIndex = the range of index’

  1. 这个数据一共有 5 列, Data columns (total 5 columns), 接下来就是来对这些列进行说明

下面的 data columns : 表中写出了:

在这里插入图片描述

Non-null Count = 没有缺失值 统计, 这里表明没有缺失值,

数据类型是float64

df_txt.describe()
01234
count1000.0000001000.0000001000.0000001000.0000001000.000000
mean-0.0004050.000425-0.0017320.000764-0.001384
std0.0293940.0312590.0303640.0302000.030905
min-0.100500-0.100282-0.115040-0.101569-0.099154
25%-0.021540-0.020828-0.022276-0.020037-0.022739
50%0.0001500.000222-0.0026500.000652-0.000494
75%0.0195800.0229640.0184930.0216320.019515
max0.0942610.0843090.0919790.0885200.090503
print(df_txt.head())
          0         1         2         3         4
0  0.036853  0.034390  0.091979 -0.010263 -0.008141
1 -0.001152  0.021750 -0.020401  0.009866 -0.034471
2 -0.012586  0.047364  0.011108 -0.011569 -0.023341
3 -0.028378  0.043980  0.001264  0.023138  0.005426
4  0.022225  0.007152 -0.037135 -0.029387 -0.099154

2.3 数据的可视化分析(定性分析)

本次的任务是多元异常点的检测,既然没有缺失值,那么我们的着手就放在异常值的定性分析和定量分析上。

接下来,我们将进行异常值的定性分析(可视化判断)

那么可视化分析 = 画图 —> 画什么图呢?

答: 判断异常值常用的图形是—箱型图

首先绘制一个类别的箱型图

## 按照我们想要的情况取出数据
## 我们先要第一列,那么就通过类别的方式取出第一列

s = df_txt[0]


'''
## 这里有必要说明一下pandas的取数方法:
# df_txt[0][1]  ### 代表df_txt[列][行]   先取出列,再取出第几个
# df_txt[3:5]    ### 代表 df_txt[ 行数1 : 行数2 ] 这里取出的是从第4行到第6行数据(注意行数是从0开始计算的)
# df_txt[0:1, 2:3]   ### 为什么这样就不对了呢??? 另外不对的还有 df_txt[: , 2] 这种类型
### 重点 :  [num1 : num2 , num_a:num_b] 这是切片的方式,这种直接切片的方式不适用与pandas 
### pandas 中有切片的方法 就是 .iloc[切片1,切片2]
### 直接切片方法可以用到哪里: 切片(slice)是对序列型对象(如list, string, tuple)的一种高级索引方法

'''

sns.boxplot(data=s, orient="v")


#### 这里是将类别进行了遍历
columns = df_txt.columns.tolist()[:5]
fig = plt.figure(figsize=(80, 60), dpi=80)
for i in range(5):
    plt.subplot(5, 1, i+1)
    sns.boxplot(df_txt[i], orient="h", width=0.5)
    

在这里插入图片描述
在这里插入图片描述

从上面的图片我们可以定性的看出异常值的位置的

而且对于这些类别而言,异常值存在的数量并没有超出我们不能接受的程度:

异常值过多 —> 过多的异常值对目标特征(标签类别)的影响程度较大 —> 因此删除此类特征

异常值可以接受 —> 保留特征,同时找出异常值并进行处理:

处理方法如下:

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

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

3.用平均值来修正

4.不处理

2.4 定量查找异常值,并进行处理(定量分析异常值)

2.4.1 通过统计量(箱型图中异常值的计算阈值)找出异常值

## 通过箱型图对异常值的判定方式来检测异常值,并进行相关操作

def outliers(data, col_name, scale=3):  ## scale--尺度 一般取1.5-3        ## 定义异常值函数 = 寻找异常值 + 异常值处理

    def box_plot_outliers(data_ser, box_scale):                   ## 定义  寻找异常值函数, 通过箱形图的异常值判断公式判断(这里会给出箱体的参数:类别和尺度)
          ##IQR = 尺度*(上四分位点-下四分位点)                    ## 这里的尺度可以根据经验选取,常选用 1.5 作为经验值,效果很好
        IQR = box_scale * (data_ser.quantile(0.75) - data_ser.quantile(0.25))   # IQR = 箱形图的四分位数,内距 = (箱体的3/4 - 箱体的1/4)* 倍数
        val_low = data_ser.quantile(0.25) - IQR #计算下边缘                 ### 下边界阈值范围    ## 边界值
        val_up = data_ser.quantile(0.75) + IQR  #计算上边缘                 ### 上边界阈值范围
        rule_low = (data_ser < val_low)         #小于下边缘的值              ### 异常值(下方的)  ## rule_low, rule_up : 规则以下的值,规则以上的值。
        rule_up = (data_ser > val_up)           #大于上边缘的值              ### 异常值(上方的)
        return (rule_low, rule_up), (val_low, val_up)

    data_n = data.copy()                                          # 对数据进行 copy() ,  这里的 data_n = data_new
    data_series = data_n[col_name]                                # 这里取出来的是 某一类别下的数据
    rule, value = box_plot_outliers(data_series, box_scale=scale) # data_series数据的序列, box_scale是箱体的尺度
    ##对满足在rule_low以下或rule_up以上条件计数
    index = np.arange(data_series.shape[0])[rule[0] | rule[1]]    ### data_series.shape[0] 这个数据序列的长度是多少(有多少行) rule = (rule_low, rule_up)
    print("删除了: {} 个数据".format(len(index)))                  ### 竖杠的意思:按位或运算  60|13 = 61
    data_n.reset_index(drop=True, inplace=True)                   ##取删除离群点后的数据
    print("剩余: {} 个数据".format(data_n.shape[0]))
    index_low = np.arange(data_series.shape[0])[rule[0]]
    outliers = data_series.iloc[index_low]#计在下边缘以下的点
    print("小于下边缘线的数据详细:")
    print(pd.Series(outliers).describe())
    index_up = np.arange(data_series.shape[0])[rule[1]]#计在上边缘以上的点
    outliers = data_series.iloc[index_up]
    print("大于上边缘线的数据详细:")
    print(pd.Series(outliers).describe())
	##可视化数据
    fig, ax = plt.subplots(1, 2, figsize=(5, 3))
    sns.boxplot(y=data[col_name], data=data,ax=ax[0])
    sns.boxplot(y=data_n[col_name], data=data_n,ax=ax[1])
    return data_n

这里要注意: scale的选择 :

在这里插入图片描述

### 对第一组数据进行使用
outliers(df_txt, 0, scale=1)
# outliers(df_txt, 1, scale=1.5)
### 阈值选取的值不同,那它对于计算的阈值设定也就不同
# outliers(df_txt, 1, scale=3)
删除了: 35 个数据
剩余: 1000 个数据
小于下边缘线的数据详细:
count    15.000000
mean     -0.072242
std       0.010630
min      -0.100500
25%      -0.077237
50%      -0.070234
75%      -0.063716
max      -0.062705
Name: 0, dtype: float64
大于上边缘线的数据详细:
count    20.000000
mean      0.070432
std       0.008490
min       0.061253
25%       0.063830
50%       0.068014
75%       0.076154
max       0.094261
Name: 0, dtype: float64
01234
00.0368530.0343900.091979-0.010263-0.008141
1-0.0011520.021750-0.0204010.009866-0.034471
2-0.0125860.0473640.011108-0.011569-0.023341
3-0.0283780.0439800.0012640.0231380.005426
40.0222250.007152-0.037135-0.029387-0.099154
..................
9950.006989-0.0399000.013303-0.0354760.068688
996-0.004276-0.028075-0.000769-0.051646-0.057467
997-0.0005440.059539-0.0128970.032994-0.089494
998-0.0396970.000563-0.0329770.0154410.007677
999-0.0108660.0226040.014564-0.014077-0.025783

1000 rows × 5 columns

在这里插入图片描述

## 接下来通过多组循环的方式,对数据进行定量分析

# col_name = df_txt.columns    ### 试验

columns = df_txt.columns.tolist()[:5] 

for i in range(df_txt.shape[1]):
    print("category", i)
    outliers(df_txt, columns[i], scale=1)

category 0
删除了: 35 个数据
剩余: 1000 个数据
小于下边缘线的数据详细:
count    15.000000
mean     -0.072242
std       0.010630
min      -0.100500
25%      -0.077237
50%      -0.070234
75%      -0.063716
max      -0.062705
Name: 0, dtype: float64
大于上边缘线的数据详细:
count    20.000000
mean      0.070432
std       0.008490
min       0.061253
25%       0.063830
50%       0.068014
75%       0.076154
max       0.094261
Name: 0, dtype: float64
category 1
删除了: 35 个数据
剩余: 1000 个数据
小于下边缘线的数据详细:
count    16.000000
mean     -0.078005
std       0.009898
min      -0.100282
25%      -0.085692
50%      -0.076782
75%      -0.069292
max      -0.066077
Name: 1, dtype: float64
大于上边缘线的数据详细:
count    19.000000
mean      0.073268
std       0.005226
min       0.066924
25%       0.068971
50%       0.071675
75%       0.076447
max       0.084309
Name: 1, dtype: float64
category 2
删除了: 48 个数据
剩余: 1000 个数据
小于下边缘线的数据详细:
count    21.000000
mean     -0.075440
std       0.014680
min      -0.115040
25%      -0.078099
50%      -0.070667
75%      -0.064982
max      -0.063122
Name: 2, dtype: float64
大于上边缘线的数据详细:
count    27.000000
mean      0.067204
std       0.007891
min       0.059763
25%       0.061541
50%       0.065973
75%       0.069225
max       0.091979
Name: 2, dtype: float64
category 3
删除了: 29 个数据
剩余: 1000 个数据
小于下边缘线的数据详细:
count    14.000000
mean     -0.074974
std       0.012584
min      -0.101569
25%      -0.078545
50%      -0.068299
75%      -0.067407
max      -0.062018
Name: 3, dtype: float64
大于上边缘线的数据详细:
count    15.000000
mean      0.073013
std       0.008230
min       0.063926
25%       0.065803
50%       0.070959
75%       0.077719
max       0.088520
Name: 3, dtype: float64
category 4
删除了: 37 个数据
剩余: 1000 个数据
小于下边缘线的数据详细:
count    19.000000
mean     -0.080624
std       0.008203
min      -0.099154
25%      -0.084477
50%      -0.078274
75%      -0.074661
max      -0.069339
Name: 4, dtype: float64
大于上边缘线的数据详细:
count    18.000000
mean      0.073144
std       0.007860
min       0.062123
25%       0.068213
50%       0.071288
75%       0.078326
max       0.090503
Name: 4, dtype: float64

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我想的是让每组数据统计和相应的表进行对应, 但无法实现,判断理由:
执行:

outliers(df_txt, 0, scale=1)

outliers(df_txt, 1, scale=1.5)

执行完成之后,是同样的结果,因此不能对应显示

2.4.2 通过模型找出异常值,并处理

同样的,我们要先定义模型寻找异常值函数

# 量化定义寻找异常值的函数find_outlier()
def find_outlier(model, X, y, sigma=3):
    # 找出 y_pred
    try:                                                           ### 用 try: 尝试执行,如果已经训练好了模型,那么就用 try后面的语句
        y_pred = pd.Series(model.predict(X), index=y.index)

    except:                                                        ### 用except: 如果try后面有误(没有训练),那么执行 except后面的语句
        model.fit(X, y)                                            ### model.fit(X, y) 固定格式:因为有监督问题--模型训练的过程中一定是:既有样本,又有标签。
        y_pred = pd.Series(model.predict(X), index=y.index)        ### 模型预测中,model.predict() 是对样本的预测,不能写标签, predict() 方法都是写样本,有的会包含一些参数

    resid = y - y_pred
    mean_resid = resid.mean()
    std_resid = resid.std()

    z = (resid - mean_resid)/std_resid    ### 这里是基于分步的异常值检测方法中的 Grubbs检验 
    outliers = z[abs(z) > sigma].index    ### 这一步是异常值的检测方法。自行搜索异常值的检测方法
    
    ### 模型性能的评估
    print("R2= ", model.score(X, y))      ### 模型的得分 model.score() Return the mean accuracy on the given test data and labels. X 为测试样本, Y为真实标签
    print("mse= ", mean_squared_error(y, y_pred))
    # 这里的mse可以换成: sk.metrics.mean_squared_error(y, y_pred)
    # from sklearn.metrics import mean_squared_error   -->   mean_squared_error(y, y_pred)
    # tf.keras.metrics.mean_squared_error(y, y_pred)

    print("-"*30)

    ### 残差的统计量
    print("mean of residuals: ", mean_resid)
    print("std of residuals: ", std_resid)
    print("-"*30)

    ### 残差的个数以及残差的值
    print(len(outliers), "outliers: ")
    print(outliers.tolist())     ### 将所有的值进行 tolist(),转换成 列表形式 

    ### 可视化操作
    ### 
    plt.figure(figsize=(15, 5))
    ax_131 = plt.subplot(1, 3, 1)
    plt.plot(y, y_pred)
    plt.plot(y.loc[outliers], y_pred.loc[outliers], "ro") 
    plt.legend(["Accepted", "Outliers"])
    plt.xlabel("y")
    plt.ylabel("y_pred")

    ### 
    ax_132 = plt.subplot(1, 3, 2)
    plt.plot(y, y_pred, ".")
    plt.plot(y.loc[outliers], y_pred.loc[outliers] - y_pred.loc[outliers], "ro")
    plt.legend(["Accepted", "Outliers"])
    plt.xlabel("y")
    plt.ylabel("y_pred")

    ### 
    ax_133 = plt.subplot(1, 3, 3)
    z.plot.hist(bins=50, ax=ax_133)
    z.loc[outliers].plot.hist(color="r", bins=50, ax=ax_133)
    plt.legend(["Accepted", "Outliers"])
    plt.xlabel("z")

    plt.savefig("outliers.png")

    return outliers


# 通过岭回归模型找出异常值
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_squared_error

X_train = df_txt.iloc[:, 0:-1]
y_train = df_txt.iloc[:, -1]
outlier = find_outlier(Ridge(), X_train, y_train)


R2=  0.003460438433444235
mse=  0.0009508699922869707
------------------------------
mean of residuals:  -9.020562075079397e-19
std of residuals:  0.030851609586876844
------------------------------
2 outliers: 
[4, 137]

在这里插入图片描述

到这里我发现了这个方法的一些问题
我们在 find_outlier() 中使用了:

model.fit(X, y)

model.predict(X)

model.score(X, y)

mean_square_error(y, y_pred)

pd.Series(model.predict(X), index=y.index)

写完之后,我才察觉到这个方法存在极大的问题,因为我们没有标签,我们没有 y , 我们无法使用 上面的 方法。

因此在没有标签值的情况下,我们不能使用基于模型的异常值检测方法

不知道自己的理解是否正确(这里先存疑),原因:

无监督学习中也是没有标签的,那无监督学习就不能进行异常值检测了吗(显然是可以的)。因为无监督学习也有自己的检测方法,那有没有基于模型的检测方法呢?这一点我相信是有的


下面我们对 基于模型检测异常值的方法进行知识点梳理:

  1. model.fit(X, y)

这条语句(训练模型)是直接书写的,因为语句是为了寻找:拟合模型,找到那个函数(拟合函数)

  1. y_pred = model.predict(X)

model.predict(X) 这是用已经找到(已经完成训练的)的拟合模型进行预测操作,并且将这种预测值(y_pred)放到规定的格式里:

y_pred = pd.Series(model.predict(X), index=y.index)

  1. model.score(X, y)

在这里插入图片描述

其中 self代表本体(对象), X, y 为数据集,score() 是这个对象的属性(方法)

这里的X是训练样本, y是X是真实标签;

评估的得分的标准是用了一些 metric 中的函数,用 y_true = y 和 y_predict = model.predict(X) 进行衡量

举例说明:这里仅仅其中一个模型( ClassifierMixin() )的评估方式,模型不同,评估方法和评估指标也是不同的
在这里插入图片描述

评估衡量( accuracy_score )的标准 :
返回值是: return accuracy_score(y, self.predict(X), sample_weight=sample_weight)

我们进一步深挖:

在这里插入图片描述
在这里插入图片描述

因此进一步确定了 基于模型的异常值检测方法无法使用到本例子中,

在有监督学习任务中,基于模型的异常检测方法可以使用

而这个任务是检测一群数据中偏离严重的值,没有标签,

以后在处理问题过程中,要先判断:

  1. 这个任务是什么任务?

  2. 有没有标签?如果有,那哪个特征代表标签。

  3. 对个标签特征影响程度较高的又是哪个?这才需要对大量数据进行筛选和处理

这些都是这一次的感悟,因此要进行回溯,回到最初(第0步)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值