python用箱型圖進行異常值檢測

shuaishuai3409發表於2016-05-16

異常值檢測:資料探勘工作中的第一步就是異常值檢測,異常值的存在會影響實驗結果。異常值是指樣本中的個別值,也稱為離群點,其數值明顯偏離其餘的觀測值。常用檢測方法3σ

\sigma
原則和箱型圖。其中,3σ
\sigma
原則只適用服從正態分佈的資料。在3σ
\sigma
原則下,異常值被定義為觀察值和平均值的偏差超過3倍標準差的值。P(|xμ|>3σ)0.003
P(|x-\mu|>3\sigma)\leq 0.003
,在正太分佈假設下,大於3σ
\sigma
的值出現的概率小於0.003,屬於小概率事件,故可認定其為異常值。

  • 3σ

    \sigma
    原則對資料分佈有一定限制,而箱型圖並不限制資料分佈,只是直觀表現出資料分佈的本來面貌。其識別異常值的結果比較客觀,而且判斷標準以四分位數和四分位間距為標準,多達25%的資料可以變得任意遠而不會擾動這個標準,魯棒性更強,所以更受大家親睞。

  • 箱型圖識別異常值標準: 異常值被定義為大於QU+1.5IQR

    Q_U+1.5IQR
    或小於QL1.5IQR
    Q_L-1.5IQR
    的值。QU
    Q_U
    是上四分位數,表示全部觀察值中有1/4的資料比他大,QL
    Q_L
    是下四分位數,表示全部資料中有1/4的資料比他小。IQR是四分位間距,是QU
    Q_U
    QL
    Q_L
    的差,其間包含了觀察值的一半。
    這裡寫圖片描述


箱型圖檢測異常值實戰:
對10位歌手近6個月的播放量資料集進行異常值檢測. 資料集每一列表示歌手6個月的播放量,共10列.每一行表示每一天的播放量,共183天.
音樂播放量資料.

#-*- coding: utf-8 -*-
import pandas as pd
number = '../data/all_musicers.xlsx' #設定播放資料路徑,該路徑為程式碼所在路徑的上一個目錄data中.
data = pd.read_excel(number)

data1=data.iloc[:,0:10]#10位歌手的183天音樂播放量
#data2=data.iloc[:,10:20]
#data3=data.iloc[:,20:30]
#data4=data.iloc[:,30:40]
#data5=data.iloc[:,40:50]
import matplotlib.pyplot as plt #匯入影象庫
plt.rcParams['font.sans-serif'] = ['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus'] = False #用來正常顯示負號
plt.figure(1, figsize=(13, 26))#可設定影象大小
#plt.figure() #建立影象
p = data1.boxplot() #畫箱線圖,直接使用DataFrame的方法.程式碼到這為止,就已經可以顯示帶有異常值的箱型圖了,但為了標註出異常值的數值,還需要以下程式碼進行標註.
#for i in range(0,4):
x = p['fliers'][0].get_xdata() # 'flies'即為異常值的標籤.[0]是用來標註第1位歌手的異常值數值,同理[i]標註第i+1位歌手的異常值.
y = p['fliers'][0].get_ydata()
y.sort() #從小到大排序

for i in range(len(x)): 
  if i>0:
    plt.annotate(y[i], xy = (x[i],y[i]), xytext=(x[i]+0.05 -0.8/(y[i]-y[i-1]),y[i]))
  else:
    plt.annotate(y[i], xy = (x[i],y[i]), xytext=(x[i]+0.08,y[i]))

plt.show() #展示箱線圖

若想同時在一張圖上標註所有的歌手異常值的數值, 可以這樣做:
x0 = p[‘fliers’][0].get_xdata() # ‘flies’即為異常值的標籤.
y0= p[‘fliers’][0].get_ydata()
y0.sort() #從小到大排序
for i in range(len(x0)):
if i>0:
plt.annotate(y0[i], xy = (0x[i],y0[i]), xytext=(x0[i]+0.05 -0.8/(y0[i]-y0[i-1]),y0[i]))
else:
plt.annotate(y0[i], xy = (x0[i],y0[i]), xytext=(x0[i]+0.08,y0[i]))
上述程式碼將x0換成xi就表示給第i+1位歌手新增異常值標註. 在所有的歌手異常值都標註完後,執行plt.show() #展示所有異常值標註的箱型圖.

輸出結果如下:其中,+所表示的均是(統計學認為的)異常值.工作中,要結合資料應用背景, 距離箱型圖上下界很近的可歸為正常值.
這裡寫圖片描述


異常值處理:

  • 刪除:對於資料量比較小的資料,刪除會造成樣本不足,減少有用資訊。
  • 視為缺失值:用均值、插值等方法進行填補
  • 不處理:將缺失值視為一種特徵,統計其缺失個數等資訊作為缺失特徵。

本文將異常值視為缺失值,並用前後值的均值來填補.程式碼如下:

for i in range(0,182):
    if data1.iloc[:,1][i]>125:
        data1.iloc[:,1][i]=(data1.iloc[:,1][i+1]+data1.iloc[:,1][i-1])/2
for i in range(0,182):
    if data1.iloc[:,2][i]>600:
        data1.iloc[:,2][i]=(data1.iloc[:,2][i+1]+data1.iloc[:,1][i-1])/2        
for i in range(0,182):
    if data1.iloc[:,4][i]>225:
        data1.iloc[:,4][i]=(data1.iloc[:,4][i+1]+data1.iloc[:,4][i-1])/2
for i in range(0,182):
    if data1.iloc[:,7][i]>60:
        data1.iloc[:,7][i]=(data1.iloc[:,7][i+1]+data1.iloc[:,7][i-1])/2
for i in range(0,182):
    if data1.iloc[:,8][i]>2500:
        data1.iloc[:,8][i]=(data1.iloc[:,8][i+1]+data1.iloc[:,8][i-1])/2

處理完異常值後,匯出資料,儲存:

#datan=pd.concat([data1,data2,data3,data4,data5],axis=1)    
data1.to_csv("train_innoraml.csv") 

儲存時有時會出現這種問題:
UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-1: ordinal not in range(128)

解決方法,輸入以下程式碼:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

相關文章