數據離散化的意義
數據離散化是指將連續的數據進行分段,使其變為一段段離散化的區間。分段的原則有基於等距離、等頻率或優化的方法。
離散化的原因
1.模型限制
比如決策樹、樸素貝葉斯等算法,都是基於離散型的數據展開的。如果要使用該類算法,必須將離散型的數據進行。有效的離散化能減小算法的時間和空間開銷,提高系統對樣本的分類聚類能力和抗噪聲能力。
2. 離散化的特徵更易理解
比如工資收入,月薪2000和月薪20000,從連續型特徵來看高低薪的差異還要通過數值層面才能理解,但將其轉換為離散型數據(底薪、高薪),則可以更加直觀的表達出了我們心中所想的高薪和底薪。
3. 使模型結果更加穩定
比如如果對用戶年齡離散化,20-30作為一個區間,不會因為一個用戶年齡長了一歲就變成一個完全不同的人。當然處於區間相鄰處的樣本會剛好相反,所以怎麼劃分區間是門學問,如果按區間離散化,劃分區間是非常關鍵的。
4. 調高計算效率
離散特徵的增加和減少都很容易,易於模型的快速迭代。(離散特徵的增加和減少,模型也不需要調整,重新訓練是必須的,相比貝葉斯推斷方法或者樹模型方法迭代快)。稀疏向量內積乘法運算速度快,計算結果方便存儲,容易擴展。
5. 圖像處理中的二值化處理
將256個亮度等級的灰度圖像通過適當的閾值選取而獲得仍然可以反映圖像整體和局部特徵的二值化圖像。這樣有利於圖像的進一步處理,使圖像變得簡單,而且數據量減小,能凸顯出感興趣的目標的輪廓。
連續數據離散化方法
- 等寬離散法:等距區間或自定義區間進行離散,有點是靈活,保持原有數據分佈
- 等頻離散法:根據數據的頻率分佈進行排序,然後按照頻率進行離散,好處是數據變為均勻分佈,但是會更改原有的數據結構
- 聚類離散法:使用k-means將樣本進行離散處理
- 分位數法:使用四分位、五分位、十分位等進行離散
- 卡方:通過使用基於卡方的離散方法,找出數據的最佳臨近區間併合並,形成較大的區間
- 二值化:數據跟閾值比較,大於閾值設置為某一固定值(例如1),小於設置為另一值(例如0),然後得到一個只擁有兩個值域的二值化數據集。
注意: 卡方檢驗就是統計樣本的實際觀測值與理論推斷值之間的偏離程度,實際觀測值與理論推斷值之間的偏離程度就決定卡方值的大小,卡方值越大,越不符合;卡方值越小,偏差越小,越趨於符合,若兩個值完全相等時,卡方值就為0,表明理論值完全符合。
具體講解
1. 等寬法
將屬性的值域從最小值到最大值分成具有相同寬度的n個區間,n由數據特點決定,往往是需要有業務經驗的人進行評估。比如屬性值在[0,60]之間,最小值為0,最大值為60,我們要將其分為3等分,則區間被劃分為[0,20] 、[21,40] 、[41,60],每個屬性值對應屬於它的那個區間。
我們隨機產生200個人的年齡數據,然後通過等寬離散化,並進行可視化。這裡主要使用的是pandas庫中的 cut函數。其定義如下:
cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False)
【案例代碼】
可視化部分代碼
# 可視化 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=(12, 4)) 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
等寬離散化代碼
data = np.random.randint(1, 100, 200) k = 5 # 分為5個等寬區間 # 等寬離散 d1 = pd.cut(data, k, labels=range(k)) cluster_plot(d1, k).show()
【效果】
自定義寬度區間
data = np.random.randint(1, 100, 200) k = 6 bins = [0, 10, 18, 30, 60, 100] # 自定義區間 d2 = pd.cut(data, bins=bins, labels=range(k-1)) cluster_plot(d2, k).show()
【效果】
2.等頻法
等頻法是將相同數量的記錄放在每個區間,保證每個區間的數量基本一致。即將屬性值分為具有相同寬度的區間,區間的個數k根據實際情況來決定。比如有60個樣本,我們要將其分為k=3部分,則每部分的長度為20個樣本。
我們隨機產生200個人的年齡數據,然後通過等寬離散化,並進行可視化。這裡主要使用的是pandas庫中的 qcut函數。其缺點是邊界易出現重複值,如果為了刪除重複值可以設置 duplicates=‘drop’,但易出現於分片個數少於指定個數的問題。其函數定義如下:
qcut(x, q, labels=None, retbins=False, precision=3, duplicates='raise')
【案例代碼】
data = np.random.randint(1, 100, 200) k = 6 d3=pd.qcut(data,k) print(d3.value_counts())
【效果】
根據上面可以看出,每個區間數量大致相同,但是區間位置的意義卻不清楚。
【自己實現的等頻離散化】
data = np.random.randint(1, 100, 200) data = pd.Series(data) k = 6 # 等頻率離散化 w = [1.0 * i / k for i in range(k + 1)] w = data.describe(percentiles=w)[4:4 + k + 1] w[0] = w[0] * (1 - 1e-10) d4 = pd.cut(data, w, labels=range(k)) cluster_plot(d4, k).show()
【效果】
3.基於聚類
一維聚類離散包括兩個過程:選取聚類算法(K-Means算法)將連續屬性值進行聚類;處理聚類之後的到的k個簇,得到每個簇對應的分類值(類似這個簇的標記),將在同一個簇內的屬性值做為統一標記。
【案例代碼】
# 聚類離散 from sklearn.cluster import KMeans data = np.random.randint(1, 100, 200) data = pd.Series(data) k=5 kmodel = KMeans(n_clusters=k) kmodel.fit(data.reshape((len(data), 1))) c = pd.DataFrame(kmodel.cluster_centers_, columns=list('a')).sort_values(by='a') # rolling_mean表示移動平均,即用當前值和前2個數值取平均數, # 由於通過移動平均,會使得第一個數變為空值,因此需要使用.iloc[1:]過濾掉空值。 w = pd.rolling_mean(c, 2).iloc[1:] w = [0] + list(w['a']) + [data.max()] d5 = pd.cut(data, w, labels=range(k)) cluster_plot(d5, k).show()
【效果】
總結
由等寬離散結果我們可以直觀的看出等寬離散的缺點,其缺點在於對噪點過於敏感,傾向於不均勻的把屬性值分佈到各個區間,導致有些區間的數值極多,而有些區間極少,嚴重損壞離散化之後建立的數據模型。等頻離散不會像等寬離散一樣,出現某些區間極多或者極少的情況。但是根據等頻離散的原理,為了保證每個區間的數據一致,很有可能將原本是相同的兩個數值卻被分進了不同的區間,這對最終模型的損壞程度一點都不亞於等寬離散。聚類離散當然好,但是前提是依據聚類,聚類的好壞很影響離散化,還是需要經驗決定。
歡迎關注微信公眾號:Python學習社