主要思想:
用聚类方式划分数据为不同的簇,计算簇内每个点对于簇中心的相对距离(相对距离 = 点到簇中心的距离/这个簇所有点到簇中心距离的中位数),可视化后,检测出相对距离较大的点。
注意是每个点到簇中心的距离的中位数,不是平均值,因为异常值对中位数的影响很小,几乎可以忽略,但是对均值的影响很大。
from sklearn import preprocessing
from sklearn.cluster import KMeans
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.style.use('ggplot')
data = pd.read_excel(r'C:\Users\Administrator\Desktop\consumption_data.xls',index_col = 'Id')
data_scale = preprocessing.scale(data)#处理后需要转为dataframe,或者直接手动求均值、方差转换
model = KMeans(n_clusters = 3,max_iter = 500)#分为3类
model.fit(data_scale)
data_scale = pd.DataFrame(data_scale,index = data.index)
data_scale['labels'] = model.labels_
norm = []
for i in range(3):
norm_tmp = data_scale[['R','F',"M"]][data_scale['labels']==i]-model.cluster_centers_[i]
norm_tmp = norm_tmp.apply(np.linalg.norm,axis = 1)
norm.append(norm_tmp/norm_tmp.median())
data_scale.columns = ['R','F','M','labels']
norm = pd.concat(norm)#合并
norm.plot(style = 'ro')#可视化
可见相对距离<2的,为正常点,可以取相对距离的阈值为2
discrete_points = norm[norm>2]
discrete_points.index
>>>
Int64Index([30, 226, 670, 39, 252, 339, 484, 525, 935], dtype='int64', name='Id')
根据阈值删选出异常值,后续可以根据异常值的index删除。