Python數據分析與挖掘進階篇3——數據的預處理(清洗、集成、變換)附實例!

閱讀提示

本文主要介紹數據分析與挖掘中的數據預處理知識點:包括各類數據缺失值填充數據類型轉換函數值轉換貝葉斯插值法

四、數據的預處理

​    在數據挖掘中,海量的原始數據中存在着大量不完整(有缺失值)、不一致、有異常的數據,嚴重影響到數據挖掘建模的執行效率,甚至可能導致挖掘結果的偏差,所以進行數據清洗就顯得尤爲重要,數據清洗完成後接着進行或者同時進行數據集成、轉換、規約等一系列的處理,該過程就是數據預處理。數據預處理一方面是要提高數據的質量,另一方面是要讓數據更好地適應特定的挖掘技術或工具。統計發現,在數據挖掘的過程中,數據預處理工作量佔到了整個過程的60%。

數據預處理的主要內容包括:數據清洗、數據集成、數據變換和數據規約

1、數據清洗

​    數據清洗主要是刪除原始數據集中無關數據、重複數據、平滑噪聲數據篩選掉與挖掘主題無關的數據,處理缺失值、異常值等。

a、缺失值處理:

插補方法 方法描述
均值/中位數/衆數插補 根據屬性值的類型,用該屬性取值的平均數/中位數/衆數進行插補
使用固定值 將缺失的屬性值用一個常量替換。如廣州一個工廠普通外來務工人員的“基本工資”屬性的空缺值可以用2015年廣州市普通外來務工人員工資標準1895元/月,該方法就是使用固定值
最近臨插補 在記錄中找到與缺失樣本最接近的樣本的該屬性值插補
迴歸方法 對帶有缺失值的變量,根據已有數據和與其有關的其他變量(因變量)的數據建立擬合模型來預測缺失的屬性值
插值法 插值法是利用已知點建立合適的插值函數f(x),未知值由對應點x1求出的函數值f(x1)近似代替

​    如果通過簡單的刪除小部分記錄達到既定的目標,那麼刪除含有缺失值的記錄的方法是最有效的。然而,這種方法卻有很大的侷限性。它是以減少歷史數據來換取數據的完備,會造成資源的大量浪費,將丟棄了大量隱藏在這些記錄中的信息。尤其在數據集本來就包含很少記錄的情況下,刪除少量記錄可能會嚴重影響到分析結果的客觀性和正確性。一些模型可以將缺失值視作一種特殊的取值,允許直接在含有缺失值的數據上進行建模。

兩種插值法:

  • 拉格朗日插值法
  • 牛頓插值法

例子:

#拉格朗日插值代碼
import pandas as pd #導入數據分析庫Pandas
from scipy.interpolate import lagrange #導入拉格朗日插值函數

inputfile = '../data/catering_sale.xls' #銷量數據路徑
outputfile = '../tmp/sales.xls' #輸出數據路徑

data = pd.read_excel(inputfile) #讀入數據
data[u'銷量'][(data[u'銷量'] < 400) | (data[u'銷量'] > 5000)] = None #過濾異常值,將其變爲空值

#自定義列向量插值函數
#s爲列向量,n爲被插值的位置,k爲取前後的數據個數,默認爲5
def ployinterp_column(s, n, k=5):
  y = s[list(range(n-k, n)) + list(range(n+1, n+1+k))] #取數
  y = y[y.notnull()] #剔除空值
  return lagrange(y.index, list(y))(n) #插值並返回插值結果

#逐個元素判斷是否需要插值
for i in data.columns:
  for j in range(len(data)):
    if (data[i].isnull())[j]: #如果爲空即插值。
      data[i][j] = ployinterp_column(data[i], j)

data.to_excel(outputfile) #輸出結果,寫入文件

   應用拉格朗日插值法算對錶中的缺失值進行插補,使用缺失值前後各5個未缺失的數據參與建模,得插值結果如下所示。

時間 原始值 插值
2015/2/21 6607.4 4275.255
2015/2/14 空值 4156.86

​    在進行插值之前會對數據進行異常值檢測,發現2015/2/21日的數據是異常的(數據大於5000),所以也把此日期數據定義爲空缺值,進行補數。利用拉格朗日插值對這2015/2/21和2015/2/14的數據進行插補,結果是4275.255和4156.86,這兩天都是週末,而週末的銷售額一般要比周一到週五要多,所以插值結果比較符合實際情況。

b、異常值處理

異常值的常見處理方法如下:

異常值處理方法 方法描述
刪除含有異常值的記錄 直接將含有異常值的記錄刪除
視爲缺失值 將異常值視爲缺失值,利用缺失值處理的方法進行處理
平均值修正 可用前後兩個觀測的平均值修正該異常值
不處理 直接具有異常的數據集上進行挖掘建模

​    將含有異常值的記錄直接刪除的方法簡單易行,但缺點也很明顯,在觀測值很少的情況下,這種刪除會造成樣本量不足,可能會改變變量的原有分佈,從而造成分析結果的不準確。視爲缺失值處理的好處是可以利用現有變量的信息,對異常值(缺失值)進行填補。
​    在很多情況下,要先分析異常值出現的可能原因,再判斷異常值是否應該捨棄,如果是正確的數據,可以直接在具有異常值的數據集上進行挖掘建模。

2、數據集成

​    數據挖掘需要的數據往往分佈在不同的數據源中,數據集成就是將多個數據源合併存放在一個一致的數據存儲(如數據倉庫)中的過程。
​    在數據集成時,來自多個數據源的現實世界實體的表達形式是不一樣的,有可能不匹配,要考慮實體識別問題和屬性冗餘問題,從而將源數據在最低層上加以轉換、提煉和集成。

a、實體識別

是指從不同數據源識別出現實世界的實體,他的任務是統一不同源數據的矛盾之處

  • 同名異義:

       數據源A中的屬性ID和數據源B中的屬性ID分別描述的是菜品編號和訂單編號,即描述的是不同的實體。

  • 異名同義:

       數據源A中的sales_dt 和數據源B中的sales_ date 都是描述銷售日期的,即A. sales_dt = B. sales_ date。

  • 單位不統一:

       描述同一個實體分別用的是國際單位和中國傳統的計量單位,檢測和解決這些衝突就是實體識別的任務。

b、冗餘屬性識別

數據集成往往導致數據冗餘,例如:
1) 同一屬性多次出現。
2) 同一屬性命名不一致導致重複。
   仔細整合不同源數據能減少甚至避免數據冗餘與不一致,從而提高數據挖掘的速度和質量。對於冗餘屬性要先分析,檢測到後再將其刪除。

3、數據變換

​    主要是對數據進行規範化處理,將數據轉換成 適當的 形式,以適用於挖掘任務以及算法的需要。

a、簡單函數變換

​    簡單函數變換是對原始數據進行某些數學函數變換,常用的變換包括平方、開方、取對數、差分運算等

b、規範化

​    數據規範化(歸一化)處理是數據挖掘的一項 基礎工作。不同評價指標往往具有不同的量綱,數值間的差別可能很大,不進行處理可能會影響到數據分析的結果。爲了消除指標之間的量綱和取值範圍差異的影響,需要進行標準化處理,將數據按照比例進行縮放,使之落入一個特定的區域,便於進行綜合分析。如將工資收入屬性值映射到[-1,1]或者[0,1]內。
​ 數據規範化對於基於距離的挖掘算法尤爲重要。

(1)最小 — 最大規範化

​ 最   小—最大規範化也稱爲離差標準化,是對原始數據的線性變換,將數值值映射到[0,1]之間。
​       轉換公式如下:
x=xminmaxmin x^* = \frac{x - min}{max - min}
   其中,max爲樣本數據的最大值,min 爲樣本數據的最小值。max-min 爲極差。離差標準化保留了原來數據中存在的關係,是消除量綱和數據取值範圍影響的最簡單方法。這種處理方法的缺點是若數值集中且某個數值很大,則規範化後各值會接近於0,並且將會相差不大。若將來遇到超過目前屬性[min, max]取值範圍的時候,會引起系統出錯,需要重新確定min和max。

(2) 零—均值規範化

   零—均值規範化也稱標準差標準化,經處理的數據的均值爲0,標準差爲1。
x=xx10k x^* = \frac{x-\overline{x}}{10^k}
其中x的平均數爲原始數據的均值,σ爲原始數據的標準差。

(3) 小數定標規範化

​    通過移動屬性值的小數位數,將屬性值映射到[-1,1]之間,移動的小數位數取決於屬性值絕對值的最大值。

轉化公式爲:
x=x10k x^* = \frac{x}{10^k}
實例:

對一個矩陣使用上面三種規範化的方法進行處理,對比結果。

#-*- coding: utf-8 -*-
#數據規範化
import pandas as pd
import numpy as np

datafile = '../data/normalization_data.xls' #參數初始化
data = pd.read_excel(datafile, header = None) #讀取數據

a = (data - data.min())/(data.max() - data.min()) #最小-最大規範化
b = (data - data.mean())/data.std() #零-均值規範化
c = data/10**np.ceil(np.log10(data.abs().max())) #小數定標規範化
print(a)
print("*"*30)
print(b)
print("*"*30)
print(c)

結果:

          0         1         2         3
0  0.074380  0.937291  0.923520  1.000000
1  0.619835  0.000000  0.000000  0.850941
2  0.214876  0.119565  0.813322  0.000000
3  0.000000  1.000000  1.000000  0.563676
4  1.000000  0.942308  0.996711  0.804149
5  0.264463  0.838629  0.814967  0.909310
6  0.636364  0.846990  0.786184  0.929571
******************************
          0         1         2         3
0 -0.905383  0.635863  0.464531  0.798149
1  0.604678 -1.587675 -2.193167  0.369390
2 -0.516428 -1.304030  0.147406 -2.078279
3 -1.111301  0.784628  0.684625 -0.456906
4  1.657146  0.647765  0.675159  0.234796
5 -0.379150  0.401807  0.152139  0.537286
6  0.650438  0.421642  0.069308  0.595564
******************************
       0      1      2       3
0  0.078  0.521  0.602  0.2863
1  0.144 -0.600 -0.521  0.2245
2  0.095 -0.457  0.468 -0.1283
3  0.069  0.596  0.695  0.1054
4  0.190  0.527  0.691  0.2051
5  0.101  0.403  0.470  0.2487
6  0.146  0.413  0.435  0.2571

Process finished with exit code 0

c、連續屬性離散化

(1)離散化的過程

​    連續屬性的離散化就是在數據的取值範圍內設定若千個離散的劃分點,將取值範圍劃分爲一些離散化的區間,最後用不同的符號或整數值代表落在每個子區間中的數據值。所以,離散化涉及兩個子任務:確定分類數以及如何將連續屬性值映射到這些分類值。

(2)常用的離散化方法

  1. 等寬法

    將屬性的值域分成具有相同寬度的區間,區間的個數由數據本身的特點決定,或者由用戶指定,類似於製作頻率分佈表。

  2. 等頻法

    將相同數量的記錄放進每個區間。

  3. 基於聚類分析的方法

    維聚類的方法包括兩個步驟,首先將連續屬性的值用聚類算法(如K-Means算法)進行聚類,然後再將聚類得到的簇進行處理,合併到一個簇的連續屬性值並做同一標記。聚類分析的離散化方法也需要用戶指定簇的個數,從而決定產生的區間數。

實例:

   使用上述三種離散化方法對“醫學中中醫證型的相關數據”進行連續屬性離散化的對比。

#-*- coding: utf-8 -*-
#數據規範化
import pandas as pd

datafile = '../data/discretization_data.xls' #參數初始化
data = pd.read_excel(datafile) #讀取數據
data = data[u'肝氣鬱結證型係數'].copy()
k = 4

d1 = pd.cut(data, k, labels = range(k)) #等寬離散化,各個類比依次命名爲0,1,2,3

#等頻率離散化
w = [1.0*i/k for i in range(k+1)]
w = data.describe(percentiles = w)[4:4+k+1] #使用describe函數自動計算分位數
w[0] = w[0]*(1-1e-10)
d2 = pd.cut(data, w, labels = range(k))

from sklearn.cluster import KMeans #引入KMeans
kmodel = KMeans(n_clusters = k, n_jobs = 4) #建立模型,n_jobs是並行數,一般等於CPU數較好
kmodel.fit(data.values.reshape((len(data), 1))) #訓練模型
c = pd.DataFrame(kmodel.cluster_centers_).sort_values(0) #輸出聚類中心,並且排序(默認是隨機序的)
w = pd.rolling_mean(c, 2).iloc[1:] #相鄰兩項求中點,作爲邊界點
w = [0] + list(w[0]) + [data.max()] #把首末邊界點加上
d3 = pd.cut(data, w, labels = range(k))
def cluster_plot(d, k): #自定義作圖函數來顯示聚類結果
  import matplotlib.pyplot as plt
  plt.rcParams['font.sans-serif'] = ['SimHei'] #用來正常顯示中文標籤
  plt.rcParams['axes.unicode_minus'] = False #用來正常顯示負號
  
  plt.figure(figsize = (8, 3))
  for j in range(0, k):
    plt.plot(data[d==j], [j for i in d[d==j]], 'o')
  
  plt.ylim(-0.5, k-0.5)
  return plt

cluster_plot(d1, k).show()
cluster_plot(d2, k).show()
cluster_plot(d3, k).show()

d、屬性改造

​    在數據挖掘的過程中,爲了提取更有用的信息,挖掘更深層次的模式,提高挖掘結果的精度,我們需要利用已有的屬性集構造出新的屬性,並加人到現有的屬性集合中。

   爲了判斷是否有大用戶存在竊漏電行爲,可以構造一個新的指標——線損率,在過程就是構造屬性。
=100% 線損率 = \frac{供入電量 - 供出電量}{供入電量} * 100\%
​    線損率的正常範圍一般在3% ~ 15%,如果遠遠超過該範圍,就可以認爲該條線路的大用戶很可能存在竊漏電等用電異常行爲。

實例:

線損率屬性構造

#-*- coding: utf-8 -*-
#線損率屬性構造
import pandas as pd

#參數初始化
inputfile= '../data/electricity_data.xls' #供入供出電量數據
outputfile = '../tmp/electricity_data.xls' #屬性構造後數據文件

data = pd.read_excel(inputfile) #讀入數據
data[u'線損率'] = (data[u'供入電量'] - data[u'供出電量'])/data[u'供入電量']

data.to_excel(outputfile, index = False) #保存結果

e、小波變換

​    小波變換是一種新型的數據分析 工具,是近年來興起的信號分析手段。小波分析的理論和方法在信號處理、圖像處理、語音處理、模式識別、量子物理等領域得到越來越廣泛的應用,它被認爲是近年來在工具及方法上的重大突破。小波變換具有多分辨率的特點,在時域和頻域都具有表徵信號局部特徵的能力,通過伸縮和平移等運算過程對信號進行多尺度聚焦分析,提供了一種非平穩信號的時頻分析手段,可以由粗及細地逐步觀察信號,從中提取有用信息。

實例:

小波變換特徵提取

#-*- coding: utf-8 -*-
#利用小波分析進行特徵分析

#參數初始化
inputfile= '../data/leleccum.mat' #提取自Matlab的信號文件

from scipy.io import loadmat #mat是MATLAB專用格式,需要用loadmat讀取它
mat = loadmat(inputfile)
signal = mat['leleccum'][0]

import pywt #導入PyWavelets
coeffs = pywt.wavedec(signal, 'bior3.7', level = 5)
#返回結果爲level+1個數字,第一個數組爲逼近係數數組,後面的依次是細節係數數組



★如有不足或錯誤請指出,謝謝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章