1. 程式人生 > >數據準備<3>:數據預處理

數據準備<3>:數據預處理

改變 lin 分享圖片 讀取 細粒度 .com ssi rand 簡單的

數據預處理是指因為算法或者分析需要,對經過數據質量檢查後的數據進行轉換、衍生、規約等操作的過程。整個數據預處理工作主要包括五個方面內容:簡單函數變換、標準化、衍生虛擬變量、離散化、降維。本文將作展開介紹,並提供基於Python的代碼實現。

1. 簡單函數變換

簡單函數變換是指對原始數據直接使用某些數學函數進行轉換,主要用於將不具有正態分布的數據變換成具有正態分布,同時也可以用於對數據進行壓縮,比如\(10^8和10^9\)更關註的是相對差距而不是絕對差距,可以通過取對數變換實現。
常用的函數包括:\(log(x)、x^k、e^x、\frac {1}{x}、\sqrt{x}、sinx\)等。
簡單函數變換會改變的原始數據的分布特征,因此使用前必須深入了解數據特征變化是否會影響到後續的分析。

## 導入庫
import pandas as pd
import numpy as np
## 讀取數據
dataset = pd.read_excel("/labcenter/python/dataset2.xlsx")

## 簡單函數變換
dataset[‘new_col2‘] = np.log10(dataset[‘col2‘])      #取10為底的對數
dataset[‘new_col2‘] = np.exp(dataset[‘col2‘],2)      #取平方
dataset[‘new_col2‘] = np.exp(dataset[‘col2‘])        #取e為的底的指數
dataset[‘new_col2‘] = 1 / dataset[‘col2‘]            #取倒數
dataset[‘new_col2‘] = np.sqrt(dataset[‘col2‘])       #開方
dataset[‘new_col2‘] = np.sin(dataset[‘col2‘])        #取正弦


2. 標準化

標準化,是為了處理不同規模和量綱的數據,使其縮放到相同的數據區間和範圍,以減少規模、量綱、分布差異等對分析建模的影響。常用的標準化方法有以下三種

2.1 離差標準化

離差標準化,又稱最大值最小值標準化(Max-Min),即基於原始數據的最大值、最小值對數據進行線性變換,變換後,數據完全落入[0,1]區間內
公式:
\[x‘= \frac {(x-min)}{(max-min)}\]
其中,原始數據x,其最大值、最小值分別為max、min,轉換後數據為x‘。
優點:能夠將數據歸一化,同時能較好的保持原始數據的分布結構;
缺點:容易受極端值的影響,極端值會使大部分數據接近於0並且差距很小,同時在出現最值範圍以外的數據時變換結果會產生錯誤;
適用場景

:適合數據比較集中的情況。

2.2 標準差標準化

標準差標準化,即Z-Score標準化,即基於原始數據的均值和標準差對數據進行標準化,標準化後,數據呈正態分布
公式:
\[x‘= \frac {(x-μ)}{σ}\]
其中,原始數據x,其均值、標準差分別為μ、σ,轉換後數據為x‘。
缺點:是一種中心化方法,會改變原始數據的分布結構。
適用場景:適合數據的最值未知,且可能出現離群點的情況。

2.3 絕對值最大標準化

絕對值最大標準化,即MaxAbs標準化,即基於原始數據絕對值的最大值對數據進行標準化,變換後,數據完全落入[-1,1]區間內
公式:
\[x‘= \frac {x}{maxAbs}\]
其中,原始數據x,其絕對值的最大值為maxAbs,轉換後數據為x‘。
優點:不會破壞原始數據的分布結構;
適用場景:可用於稀疏矩陣、稀疏數據。

## 標準化處理
## 方法1:使用numpy和pandas
### 離差標準化
dataset[‘new_col2‘] = (dataset[‘col2‘] - dataset[‘col2‘].min()) / (dataset[‘col2‘].max() - dataset[‘col2‘].min())
### 標準差標準化
dataset[‘new_col2‘] = (dataset[‘col2‘] - dataset[‘col2‘].mean()) / dataset[‘col2‘].std()
### 絕對值最大標準化
dataset[‘new_col2‘] = dataset[‘col2‘] / np.abs(dataset[‘col2‘]).max()

## 方法2:使用sklearn
from sklearn import preprocessing
### 離差標準化
minmax_scaler = preprocessing.MinMaxScaler()
dataset[‘new_col2‘] = minmax_scaler.fit_transform(dataset[‘col2‘])
### 標準差標準化
zsocre_scaler = preprocessing.StandardScaler()
dataset[‘new_col2‘] = zsocre_scaler.fit_transform(dataset[‘col2‘])
### 絕對值最大標準化
maxabs_scaler = preprocessing.MaxAbsScaler()
dataset[‘new_col2‘] = maxabs_scaler.fit_transform(dataset[‘col2‘])


3. 衍生虛擬變量

在數據建模過程中,很多算法都不能處理非數值型數據,必須首先將這些數據轉化為數值型。但是,即使轉化為數值型數據,也不能直接應用到算法計算中,為什麽?這需要從離散型數據的分類說起。
離散型數據也就是分類數據,主要分為兩類,一類是無序分類,一類是有序分類。
無序分類,是指各個類別之間沒有明顯的高、低、大、小等包含等級、順序、優劣、好壞等邏輯的劃分,只是用來區分兩個或多個具有相同或相當價值的屬性。例如性別的男和女,顏色的紅、黃、藍等等。
有序分類,是指各個類別之間有一定的順序關系。例如用戶價值的高、中、低,學歷的博士、碩士、學士等。
對於無序分類來說,無論用什麽數值來表示都無法表達出價值相等但有區分的屬性,比如性別的男和女,如果分別用1和2表示,那麽1和2本身就已經帶有距離為1的差異,但實際上二者之間是沒有這種差異的,同樣,不論用任何數據都無法到達這種區分的目的。
而對於有序分類來說,無論用什麽有序的數字序列都無法準確表達出有序類別之間的差異性,比如學歷的博士、碩士、學士,如果用3-2-1來表示這種順序關系,那這種差異為什麽不能用30-20-10來表示呢?
所以,非數值型的離散型數據要想參與到算法計算中,不能簡單的認為轉化成用數值就表示就可以,而是必須使用其他的方法,這種方法就是衍生虛擬變量,也叫做創建虛擬變量(dummy variable)、創建啞變量、創建名義變量、one-hot編碼(one-hot encoding)、N取一編碼(one-out-of encoding)。它是指,將一個離散型變量衍生出多個真值變量(用0和1,或者True和False表示的變量),比如性別這一變量取值有男、女兩個,那麽將衍生出性別是否男、性別是否女兩個變量;然後使用這些衍生出來的真值變量替換原始變量參與後續的計算。
技術分享圖片

## 衍生虛擬變量
## 方法1:自定義函數
def dummyCreate(ser):
    valueSet = ser.unique()
    resDf = pd.DataFrame()
    colName = ser.name
    for value in valueSet:
        colNameNew = colName + ‘_‘ + value
        colDataTmp = ser.values
        colData = (colDataTmp == value)
        resDf[colNameNew] = colData
    return resDf
    
dummyCreate(dataset[‘col3‘])

## 方法2:使用sklearn
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import LabelEncoder
labelEnc = LabelEncoder()   ##標準標簽化
ohEnc = OneHotEncoder()     ##one-hot編碼
dataset[‘new_col3‘] = labelEnc.fit_transform(dataset[‘col3‘])   ##將類別值用0.1.2……編碼
ohEncRes = ohEnc.fit_transform(dataset[‘new_col3‘].reshape(-1,1)).toarray()     ##one-hot編碼
newDf = pd.concat((dataset, pd.DataFrame(ohEncRes)), axis=1)    ##合並結果
dataset = newDf.rename(columns={0:‘col3_aaa‘,1:‘col3_bbb‘,2:‘col3_ccc‘})    ##重命名列名

註意:創建虛擬變量和虛擬變量編碼(dummy encoding)是不同的概念,前者如上所述,如果一個離散變量有N個取值,就會衍生出N個真值變量,而後者——虛擬變量編碼,則是衍生出N-1個變量,它認為這個N-1個變量都為0時即表示原始數據取第N個值。
技術分享圖片


4. 離散化

離散化就是將一份數據從細粒度轉化為粗粒度,實質就是數據的集中化。主要包括兩方面:將連續型數據轉化成離散型數據、將離散型數據進行類別合並,具體又分為以下幾點:

4.1 針對時間數據的離散化

針對時間數據的離散化主要是指對時間數據進行粒度上的上卷(反之是下鉆):
時間戳——>小時——>上午\下午
日期型——>星期——>周數——>季度——>年份

## 離散化
### 針對時間數據的離散化
colList = list(dataset.columns)
colList.extend([‘weekday_col5‘,‘week_col5‘,‘year_col5‘,‘month_col5‘,‘day_col5‘,‘hour_col5‘])
dataset = dataset.reindex(columns = colList)
for index,value in enumerate(dataset[‘col5‘]):
    newValue = pd.to_datetime(value)
    dataset[‘weekday_col5‘][index] = newValue.weekday()
    dataset[‘week_col5‘][index] = newValue.week
    dataset[‘year_col5‘][index] = newValue.year
    dataset[‘month_col5‘][index] = newValue.month
    dataset[‘day_col5‘][index] = newValue.day
    dataset[‘hour_col5‘][index] = newValue.hour

4.2 針對類別數據的離散化

針對類別數據的離散化主要是指將多個類別進行合並而產生新的類別劃分。
比如將年齡區間(小於18,18-35,35-50,50-70,70以上)合並為年齡區間(小於18,18-35,35-50,50以上)。

### 針對類別數據的離散化
mapDf = pd.DataFrame([[‘0-10‘,‘0-20‘],[‘10-20‘,‘0-20‘],[‘20-30‘,‘20-30‘],[‘30-40‘,‘30-50‘],[‘40-50‘,‘30-50‘]],columns=[‘col6‘,‘new_col6‘])
dataset = dataset.merge(mapDf, left_on = ‘col6‘, right_on = ‘col6‘, how = ‘inner‘)

4.3 針對連續數據的離散化

離散化中主要的工作是針對連續數據的離散化,包括兩方面:將連續數據分成多個區間、將連續數據劃分成特定的類。前者通常被稱為分箱。具體有以下幾種實現方法:

(1)自定義分箱

自定義分箱,是指根據業務經驗或者常識等自行設定劃分的區間,然後將原始數據歸類到各個區間中。

(2)等寬分箱

等寬分箱,是指劃分的各個區間的寬度(或稱為距離)相等。

(3)等頻分箱

等頻分箱,是指劃分的各個區間包含的數據點的個數相等,也稱為等深分箱,或者是分位數分箱

(4)聚類法

聚類法,是指使用聚類算法自動將原始數據分成多個類別。

(5)二值化

二值化,是指設置一個閾值,將每個數據點與這個閾值進行比較,大於(或等於)閾值取某一固定值A,小於(或等於)閾值則取另一固定值B,從而將原始數據轉換為兩個取值的離散數據。

### 針對連續數據的離散化
#### (1)自定義分箱
points = [0,800,1500,2000,2500]  #定義邊界點
dataset[‘new_col7‘] = pd.cut(dataset[‘col7‘], points)
dataset[‘new_col7‘] = pd.cut(dataset[‘col7‘], points, labels = [‘a‘,‘b‘,‘c‘,‘d‘])

#### (2)等寬分箱
bins = 4   #箱數
dataset[‘new_col7‘] = pd.cut(dataset[‘col7‘], bins)
dataset[‘new_col7‘] = pd.cut(dataset[‘col7‘], bins, labels = [‘a‘,‘b‘,‘c‘,‘d‘])

#### (3)等頻分箱
bins = 4   #箱數
dataset[‘new_col7‘] = pd.qcut(dataset[‘col7‘], bins)
dataset[‘new_col7‘] = pd.qcut(dataset[‘col7‘], bins, labels = [‘a‘,‘b‘,‘c‘,‘d‘])

#### (4)聚類法
from sklearn.cluster import KMeans
data = dataset[‘col7‘]
new_data = data.reshape((data.shape[0], 1))
kmeans = KMeans(n_clusters=4, random_state=0)  # 使用K-Means聚類
keames_result = kmeans.fit_predict(new_data)
dataset[‘new_col7‘] = keames_result

#### (5)二值法
from sklearn import preprocessing
binarizer_scaler = preprocessing.Binarizer(threshold = dataset[‘col7‘].mean())  #使用均值作為分割閾值
temp = binarizer_scaler.fit_transform(dataset[‘col7‘])
temp.resize(dataset[‘col7‘].shape)
dataset[‘new_col7‘] = temp


5. 降維

降維是指降低數據集的維度數量,從而降低模型的計算工作量,減少模型的運行時間,減弱噪聲變量(無關變量)對模型結果可能產生的影響。

5.1 基於特征選擇的降維

基於特征選擇的降維,通俗的說,就是特征篩選,或者叫變量篩選。從多個變量中篩選出更有用的較少個變量,從而降低數據集的維度。特征篩選的主要方法包括:基於經驗的方法(比如專家法)、基於統計的方法(比如區分度、信息增益)和基於機器學習的方法(比如決策樹算法)。
基於特征選擇的降維的好處是,既保留了原有維度的特征,同時又完成了降維的目的。
由於特征篩選是數據準備工作的一個重要環節,因此會單獨拿出來進行總結論述,此處不做詳細討論。

5.2 基於維度轉換的降維

基於維度轉換的降維,是指按照一定的數學變換方法,把給定的一組(相關的)變量,通過數學模型從高維空間映射到低維度空間中,然後利用映射後產生的新變量來表示原有變量的總體特征,轉換後產生的新特征是多個原始特征的綜合。
具體的方法分為線性降維和非線性降維,常用的算法有主成分分析、因子分析、線性判別分析等。
關於具體的算法原理,後續將在統計學或機器學習系列中進行總結論述,此處不做討論。
基於維度轉換的降維將使用轉換後產生的新變量參與後續的建模分析,因此直接影響到模型的可解釋性和可理解性,在不要求對模型進行解釋說明時可以使用,否則,建議使用基於特征選擇的降維。


6. 參考與感謝

[1] 數據挖掘概念與技術
[2] 數據挖掘導論
[3] Python機器學習基礎教程
[4] Python數據分析與數據化運營
[5] Python數據分析與數據挖掘實戰



數據準備<3>:數據預處理