数据分析--数据预处理
本文主要是個人的學習筆記總結,數據預處理的基本思路和方法,包括一些方法的使用示例和參數解釋,具體的數據預處理案例case詳見其他文章。如有錯誤之處還請指正!
目錄- 數據的質量評定
-
數據處理步驟
-
缺失值的處理
- 標記缺失值
- 刪除缺失值
- 填充缺失值
- 重復值處理
- 異常值的處理
-
數據集合并
pandas.DataFrame.concat()方法合并:pandas.DataFrame.merge()方法合并:pandas.DataFrame.join()方法:- 數據映射
map()方法完成
- 分組聚合
-
數據轉換
- Z-Score 標準化
- Min-Max 標準化
- 獨熱編碼
- 數據離散化
-
數據規約
- 主成成分分析(Principal Components Analysis)
- 線性判別分析
- 皮爾遜相關系數
- 卡方檢驗
- 數據抽樣
-
缺失值的處理
數據在進行建模和分析前,對其進行數據處理是必不可少的,這樣做能幫助我們從根本上保證數據質量,提高數據的準確性和可靠性。主要包括數據清洗、數據轉換、數據集成、數據降維等過程。
數據的質量評定
從五個維度來對數據質量進行評定
| 維度 | 說明 |
|---|---|
| 有效性 Validity |
數據的有效性源于統計學概念,即符合數據收集時所制定的規則及約束條件的數據。 |
| 精確度 Accuracy |
精確度是衡量數據質量的另一個重要條件。 一般情況下,通過數據清理很難改善數據的準確度,這就對數據源質量提出了較高的要求。 |
| 完整度 Completeness |
如果在采集數據的過程中造成了數據丟失,也就影響了其完整程度。 不完整的數據,勢必會對分析結論造成影響,這需要進一步采取措施來改善這種情況。 |
| 一致性 Consistency |
原始數據中,數據可能會存在不一致性。 例如:客戶在兩個不同的系統中提供了兩個不一樣的家庭地址,而正確的地址只有一個。 那么,就需要我們來判斷并消除這種不一致性。 |
| 均勻度 Uniformity |
數據的均勻度可能來源于度量單位的不一致,這就需要我們通過換算來解決,使得最終數據統一均勻。 |
數據處理步驟
數據處理的常見四個步驟:
| 序號 | 步驟 | 說明 |
|---|---|---|
| 1 | 數據清理 Data Cleansing |
數據清理大致包括對空缺鍵值進行填充操作, 對噪聲數據進行相應的平滑處理,對孤立點和異常點進行刪除處理等。 |
| 2 | 數據集成 Data Integration |
將多個數據庫或者數據文件里面包含的數據進行集成處理。 |
| 3 | 數據轉換 Data Transformation |
將數據進行聚集或者規范化處理,從一種形式轉換成另外一種我們需要的形式。 |
| 4 | 數據規約 Data Reduction |
對龐大的數據集進行壓縮處理,且盡量保證最終預測結果的一致性。 |
下面將詳細介紹常用的數據處理方法:
缺失值的處理
標記缺失值
# 生成包含缺數據的示例
import numpy as np
import pandas as pd
null_data = {'A': [10, np.nan, 25, np.nan, 42, np.nan],
'B': [12, 15, np.nan, 14, 17, np.nan],
'C': [10, 13, 27, 13, 19, 40]}
df = pd.DataFrame(null_data)
-
空值也有不同類型
數值型空值 :NaN (not a number)
空字符串 :None
-
定位缺失數據:
- 使用 isnUll() 返回 True 代表缺失值
- notnull()則與之相反
刪除缺失值
- 直接刪除
- 缺失數據占全部數據比例非常低,可忽略不計且刪除后不會對整體數據分布產生影響
- 缺失數據因為本身特性無法填充,比如對于某些檢測指標,填充數值會對結果產生影響的寧愿刪除也不要進行處理
# 刪除缺失值
import pandas as pd
# 創建一個示例數據框
data = {'A': [1, 2, None, 4],
'B': [5, None, 7, 8],
'C': [None, 10, None, 12]}
df = pd.DataFrame(data)
# 刪除包含缺失值的行
cleaned_df1 = df.dropna() # 默認刪除包含缺失值的行
cleaned_df2 = df.dropna(axis=1) # 刪除包含缺失值的列
cleaned_df3 = df.dropna(how='all') # 當所有值為缺失值時刪除行
cleaned_df4 = df.dropna(thresh=2) # 至少要有 2 個非缺失值才保留行
cleaned_df5 = df.dropna(subset=['B', 'C']) # 只有在 'B' 和 'C' 列中同時存在空值的情況下,對應的行才會被刪除
print(cleaned_df1)
print(cleaned_df2)
print(cleaned_df3)
print(cleaned_df4)
print(cleaned_df5)
填充缺失值
-
固定值填充:人為指定,使用行/列均值、中位數等
# Pandas 提供的 replace t填充固定值 print(df.replace(np.nan,0)) # 缺失值填充為0 # 專門用于填充缺失值的函數 fillna() print(df.fillna(0)) # 使用各列的平均值填充 print(df.fillna(df.mean())) # 使用格列中位數填充 print(df.fillna(df.median())) -
臨近值填充:使用缺失值相臨近的數值填充
# 使用后一個臨近的數據向前填充 print(df.fillna(method='bfill')) # 使用前一個臨近的數據向后填充 print(df.fillna(method='ffill')) -
數字填充:使用函數插值填充
數據缺失但能看出數據的變化趨勢,更好的缺失值填充方法時是使用數據方法進行插值Pandas中的
interpolate()可以快速應用一些常用的插值函數sample_data = {'A': [1, np.nan, 3, np.nan, 5, 6], 'B': [1, 4, np.nan, np.nan, 25, 36]} df = pd.DataFrame(sample_data) # 線性插值 print(df.interpolate(method='linear')) # 2次函數插值 print(df.interpolate(method='polynomial', order=2))
重復值處理
# 示例數據
df = pd.DataFrame({'name': ['amy', 'david'] * 3 +
['jam'], 'class': [2, 2, 2, 4, 3, 2, 4]})
-
duplicated()判斷是否存在重復值print(df.duplicated()) # 判斷重復值 存在則返回True print(df.duplicated().sum()) # 統計判斷重復值 -
dropduplicates()去除重復值
df.drop_duplicatep() #去除全部重復值
df.drop_duplicates(['name']) #去除name列的重復值
df.drop_duplicates(keep='last') # 默認保留重復項前面的值,而去除后面的值,‘last’則為保留最后一個
異常值的處理
當涉及 Pandas 應用數學與統計學領域中的異常值檢測時,有一些比較深入的方法,包括概率方法,矩陣分解,以及神經網絡等。下面是一些具體示例展示:
-
概率方法 - 一元正態分布檢測異常值:
import pandas as pd import numpy as np # 創建一個示例數據集 data = pd.DataFrame({'value': [1, 2, 3, 4, 5, 1000]}) # 計算均值和標準差 mean = data['value'].mean() std = data['value'].std() # 設置異常值閾值,例如均值加減3倍標準差 threshold = 3 * std # 使用一元正態分布方法檢測異常值 data['is_outlier'] = np.abs(data['value'] - mean) > threshold print(data) -
概率方法 - 多元高斯方法檢測異常值:
from scipy import stats # 創建一個示例數據集 data = pd.DataFrame({ 'feature1': [1, 2, 3, 4, 5], 'feature2': [2, 4, 6, 8, 10] }) # 計算多元高斯分布概率密度 multivariate_dist = stats.multivariate_normal(mean=data.mean(), cov=data.cov()) # 設置異常值閾值 threshold = 0.01 # 例如設置一個較小的閾值 # 使用多元高斯方法檢測異常值 data['is_outlier'] = multivariate_dist.pdf(data) < threshold print(data) -
矩陣分解方法檢測異常值:
from sklearn.decomposition import PCA # 創建一個示例數據集 data = pd.DataFrame({ 'feature1': [1, 2, 3, 4, 5], 'feature2': [2, 4, 6, 8, 100] }) # 使用主成分分析(PCA)進行矩陣分解 pca = PCA(n_components=2) pca.fit(data) # 計算重構誤差 reconstruction_error = np.sum((data - pca.inverse_transform(pca.transform(data))) ** 2, axis=1) # 設置異常值閾值 threshold = 20 # 例如設置一個閾值 # 使用矩陣分解方法檢測異常值 data['is_outlier'] = reconstruction_error > threshold print(data) -
神經網絡方法檢測異常值:
from sklearn.neighbors import LocalOutlierFactor # 創建一個示例數據集 data = pd.DataFrame({'value': [1, 2, 3, 4, 5, 1000]}) # 使用局部異常因子(Local Outlier Factor)進行異常值檢測 lof = LocalOutlierFactor(n_neighbors=2, contamination=0.1) # 設置參數 data['is_outlier'] = lof.fit_predict(data[['value']]) print(data)
數據集合并
這里主要是用pandas中的常見方法進行數據集的連接合并。
pandas.DataFrame.concat()方法合并:
pandas.concat(
objs, # 接受一個列表或字典,表示要連接的 pandas 對象(Series 或 DataFrame)
axis=0, # 沿指定軸進行連接,0 表示沿第一個軸(行方向)連接,1 表示沿第二個軸(列方向)連接
join='outer', # 指定連接的方式,'outer'表示并集(union),'inner'表示交集(intersection)
ignore_index=False,# 如果為 True,將忽略原始索引并生成一個新的整數索引
keys=None, # 創建層次化索引,用于識別每個片段
levels=None, # 指定多級索引的級別(通常自動推斷)
names=None, # 指定多級索引的級別名稱
verify_integrity=False, # 如果為 True,在連接操作之前驗證軸是否包含重復項
sort=False # 如果為 True,對非連接軸上的索引進行排序
)
以下是對各個參數的詳細解釋:
-
objs:要連接的 pandas 對象列表。可接受一個列表(或字典),其中包含要連接的 DataFrame 或 Series 對象。 -
axis:指定連接的軸方向。0 表示在行方向上連接,1 表示在列方向上連接。 -
join:指定連接的方式。默認為 'outer',表示取并集進行連接,也可以選擇 'inner',表示取交集進行連接。 -
ignore_index:如果為 True,將忽略原始索引并生成一個新的整數索引。 -
keys:當數組沿著連接軸堆疊時,可以用 keys 參數創建一個層次化索引(MultiIndex),以便識別每個片段。 -
levels:指定鍵的層次化級別,通常不需要手動指定,會根據 keys 推斷。 -
names:指定多級索引的級別名稱。 -
verify_integrity:如果為 True,在連接操作之前驗證軸是否包含重復項,如果包含重復項則會拋出 ValueError 異常。 -
sort:如果為 True,在連接操作之后對非連接軸上的索引進行排序。
?
pandas.DataFrame.merge() 方法合并:
pandas.merge(
left, # 左側的 DataFrame 對象
right, # 右側的 DataFrame 對象
how='inner', # 合并方式,默認為 'inner',表示取兩個 DataFrame 的交集
on=None, # 指定列名或索引級別作為合并的鍵,默認為 None,表示自動根據列名的交集進行合并
left_on=None, # 指定左側 DataFrame 中的列名或索引級別作為合并的鍵
right_on=None, # 指定右側 DataFrame 中的列名或索引級別作為合并的鍵
left_index=False, # 如果為 True,在左側 DataFrame 中使用索引作為合并鍵
right_index=False, # 如果為 True,在右側 DataFrame 中使用索引作為合并鍵
sort=False, # 如果為 True,根據合并鍵對結果進行排序
suffixes=('_left', '_right'), # 如果列名沖突,為列名添加后綴來區分,默認為 '_left' 和 '_right'
copy=True # 如果為 True,在執行合并操作時復制數據
)
以下是對各個參數的詳細解釋:
-
left:左側的 DataFrame 對象。 -
right:右側的 DataFrame 對象。 -
how:指定合并的方式,默認為'inner',即取兩個 DataFrame 的交集。還可以選擇'outer',表示取兩個 DataFrame 的并集;'left',表示以左側 DataFrame 的鍵為基準進行合并;'right',表示以右側 DataFrame 的鍵為基準進行合并。 -
on:指定列名或索引級別作為合并的鍵。默認為 None,表示自動根據列名的交集進行合并。 -
left_on:指定左側 DataFrame 中的列名或索引級別作為合并的鍵。 -
right_on:指定右側 DataFrame 中的列名或索引級別作為合并的鍵。 -
left_index:如果為 True,在左側 DataFrame 中使用索引作為合并鍵。 -
right_index:如果為 True,在右側 DataFrame 中使用索引作為合并鍵。 -
sort:如果為 True,根據合并鍵對結果進行排序。 -
suffixes:如果列名沖突,為列名添加后綴來區分,默認為('_left', '_right')。 -
copy:如果為 True,在執行合并操作時復制數據。
pandas.DataFrame.join() 方法:
DataFrame.join(
other, # 合并的另一個 DataFrame 對象
on=None, # 指定列名或索引級別作為合并的鍵,默認為 None,表示根據索引進行合并
how='left', # 合并方式,默認為 'left',表示以左側 DataFrame 為基準進行左外連接
lsuffix='', # 左側 DataFrame 列名相同時的后綴,默認為 '',不添加任何后綴
rsuffix='', # 右側 DataFrame 列名相同時的后綴,默認為 '',不添加任何后綴
sort=False # 如果為 True,根據合并鍵對結果進行排序
)
以下是對各個參數的詳細解釋:
-
other:合并的另一個 DataFrame 對象。 -
on:指定列名或索引級別作為合并的鍵。默認為 None,表示根據索引進行合并。 -
how:指定合并的方式,默認為'left',即以左側 DataFrame 為基準進行左外連接。還可以選擇'inner',表示取兩個 DataFrame 的交集;'outer',表示取兩個 DataFrame 的并集;'right',表示以右側 DataFrame 為基準進行右外連接。 -
lsuffix:表示左側 DataFrame 中列名相同時的后綴,默認為 '',即不添加任何后綴。 -
rsuffix:表示右側 DataFrame 中列名相同時的后綴,默認為 '',即不添加任何后綴。 -
sort:如果為 True,根據合并鍵對結果進行排序。
數據映射 map()方法完成
df = pd.DataFrame({'name': ['amy', 'david', 'jam'], 'age': [14, 13, 12]})
name_to_gender = {'amy': 'girl', 'david': 'boy', 'jam': 'boy'} # 建立映射字典
df['gender'] = df['name'].map(name_to_gender)
分組聚合
pandas.DataFrame.groupby()對數據集進行分組聚合
df = pd.DataFrame({'key1': ['A', 'B', 'C', 'A', 'B', 'C'],
'key2': ['X', 'Y', 'X', 'Y', 'X', 'Y'],
'data': [1, 2, 3, 4, 5, 6]})
df.groupby(by='key1').sum()
df.groupby(by=['key1', 'key2']).mean() # 替換為count().mean()等其它函數
數據轉換
不僅是數據格式或類型的轉換,更多的是通過一些統計學方法對數據進行標準化或離散化處理。
特征工程:需要去設計數據特征,以幫助訓練得到性能更加優異的模型。
標準化 Normalization(無量綱化)是數據預處理中的常用手段。標準化的目的主要是消除不同特征之間的量綱和取值范圍不同造成的差異。這些差異,不僅會造成數據偏重不均,還會在可視化方面造成困擾
import numpy as np
import pandas as pd
%matplotlib inline
np.random.seed(10) # 隨機數種子
df = pd.DataFrame({'A': np.random.random(
20), 'B': np.random.random(20) * 10000})
print(df.plot()) # 繪圖
此時,B列數據太大,A列已經無法看出趨勢,近似一條直線.
Z-Score 標準化
Z-Score 標準化 是常用的標準化手段之一,其公式為:
\[z = \frac{x - \mu}{\sigma} \]其中, ??
為樣本數據的均值, ??
為樣本數據的標準差。Z-Score 標準化之后的數據的均值為 0,方差為 1。
通過Z-Score 標準化,可以使不同數據集之間的數據具有可比性,同時可以減小異常值對數據分析和模型建立的影響。
# 使用Z-Score標準化對上面的DataFrame進行標準化處理并繪圖
df_z_score = (df - df.mean()) / df.std() # Z-Score 標準化
df_z_score.plot()
Z-Score 標準化方法在 Scipy 中有一個對應的APIscipy.stats.zscore 可以使用
from scipy import stats
stats.zscore(df)
也可以將 DataFrame 處理從 NumPy 數組再運算
(df.values - df.values.mean(axis=0)) / df.values.std(axis=0) # NumPy 數組運算
除了 SciPy,scikit-learn 也提供了 Z-Score 標準化API sklearn.preprocessing.StandardScaler()
Min-Max 標準化
該方法可以將數據轉化到一個特定的區間范圍內,通常是[0, 1]或者[-1, 1]之間。這種標準化方法適用于以下場景:
-
數據需要落入特定區間范圍內:例如神經網絡的輸入層,很多情況下都要求輸入數據的范圍在[0, 1]或者[-1, 1]之間。
-
需要保留原始數據的相對性質:Min-Max 標準化會保持原始數據中不同數值之間的相對大小關系,不會改變數據的分布形態。
-
異常值較少:Min-Max 標準化對異常值比較敏感,如果數據中存在較多的異常值,可能會導致標準化后的數據集不夠均衡。
公式為:
\[\hat x=\frac{x-x_{min}}{x_{max}-x_{min}} \]其中, ????????為樣本數據的最大值, ????????為樣本數據的最小值, ?????????????????為極差。
# 使用Min-Max標準化對上面的DataFrame進行標準化處理
df_min_max = (df - df.min()) / (df.max() - df.min()) # Min-Max 標準化
df_min_max.plot()
同樣,scikit-learn 也提供了 Min-Max 標準化的 API sklearn.preprocessing.MinMaxScaler(),使用方法如下:
from sklearn.preprocessing import MinMaxScaler
MinMaxScaler().fit_transform(df)
獨熱編碼
在對數據的預處理過程中,我們會遇到有一些特征列中的樣本并不是連續存在的,而是以分類形式存在的情況。例如,某一裝置的狀態有三種情況,分別為:正常、機械故障、電路故障。如果我們要將這些數據運用到后續的預測分析中,就需要對文字狀態進行轉換。一般情況下,可以用 0 表示正常,1 代表機械故障,2 代表電路故障。
所以,對于以分類形式存在的特征變量,我們會采用一種叫 獨熱編碼 One-Hot Encoding 的方式將其轉換成二元特征編碼,進一步對特征進行了稀疏處理。獨熱編碼采用位狀態寄存器來對個狀態進行編碼,每個狀態都由它獨立的寄存器位,并且在任意時候只有一位有效。
# Pandas 中,可以使用 get_dummies 很方便地完成獨熱編碼。
df = pd.DataFrame({'fruits': ['apple', 'banana', 'pineapple']*2}) # 示例裝置狀態表
pd.get_dummies(df) # 獨熱編碼
數據離散化
數據離散化有時候是為了算法實施需要,也有可能離散數據更適合數據的信息表達。當我們對連續數據進行按區間離散化時,你可以通過編寫代碼實現。不過,這里介紹 Pandas 中一個非常方便的區間離散化方法 pd.cut(適用于等寬離散化)
# 將數組等間距分割為3部分
pd.cut(np.array([1, 2, 7, 8, 5, 4, 12, 6, 3]), bins=3) # bins 指定劃分數量
此時,如果我們按照 3 個區間對數據添加類別標簽 "small", "medium", "large",只需要指定 labels= 參數即可
pd.cut(np.array([1, 2, 7, 8, 5, 4, 12, 6, 3]),
bins=3, labels=["small", "medium", "large"])
一般情況下,區間返回會以最大值為準,向最小值方向擴展 0.1% 以保證元素被有效分割。所以上面的區間不是以最小值 1 開始,而是 0.989。其中
\[1 - 0.989 = (12 - 1) * 0.1\% \]當然,也可以自行指定劃分區間:
pd.cut(np.array([1, 2, 7, 8, 5, 4, 12, 6, 3]),
bins=[0, 5, 10, 15], labels=["small", "medium", "large"])
數據規約
主成成分分析(Principal Components Analysis)
通過對協方差矩陣進行特征分解,從而得出主成分(特征向量)與對應的權值(特征值)。然后剔除那些較小特征值(較小權值)對應的特征,從而達到降低數據維數的目的。
PCA最便捷方式通過scikit-learn完成
下面以常見的鳶尾花示例數據集作為示例:
# 加載鳶尾花實例數據集
import pandas as pd
from sklearn.datasets import load_iris
from matplotlib import pyplot as plt
%matplotlib inline
iris = load_iris() # 加載原始數據
iris_df = pd.DataFrame(iris.data, columns=iris.feature_names) # 處理為 DataFrame
數據集包含有4列,代表鳶尾花的4個特征。若想將上面的數據繪制成數據點圖(平面散點圖),就無法實現,此時就需要對數據進行降維處理
介紹以下 sklearn.decomposition.PCA 方法中的幾個參數:
-
n_components=表示需要保留主成分(特征)的數量。 -
copy=表示針對原始數據降維還是針對原始數據副本降維。當參數為 False 時,降維后的原始數據會發生改變,這里默認為 True。 -
whiten=白化表示將特征之間的相關性降低,并使得每個特征具有相同的方差。 -
svd_solver=表示奇異值分解 SVD 的方法。有 4 參數,分別是:auto,full,arpack,randomized。
# 續上段代碼, 進行PCA
iris_pca = PCA(n_components=2).fit_transform(iris_df) # PCA 降 2 維
iris_pca = pd.DataFrame(iris_pca, columns=['pca_x', 'pca_y']) # 整理 DataFrame
iris_pca.plot.scatter(x='pca_x', y='pca_y') # 繪制數據點
iris_pca.plot.scatter(x='pca_x', y='pca_y',
c=iris.target, cmap='plasma') # 數據點著色
PCA在很多情況下是非常有用的, 上述是從可視化角度進行,以下是常見使用:
-
降低數據維度:高維數據集會增加分析數據的復雜性,而PCA可以將高維數據投影到低維空間中,同時保留了大部分數據的變異性。這有助于簡化數據集、減少存儲空間和計算成本。
-
消除數據間的相關性:在許多數據集中,不同特征之間存在相關性。PCA可以消除或減輕這些特征之間的相關性,從而更好地反映數據之間的獨立性,減少重復信息。
-
提高模型的性能:在一些機器學習任務中,高維數據可能會導致過擬合,而PCA可以有效減少數據的維度,幫助改善模型的泛化能力,并提高預測的準確性。
-
數據可視化:通過PCA技術,可以將高維數據轉換為二維或三維,從而更好地將數據可視化展現,以便更好地理解數據的結構和特征。
-
去除噪聲:在某些數據集中可能會存在噪聲或不重要的信息,而PCA可以幫助排除這些噪聲,提取出數據中最重要的信號和特征。
-
特征提取:PCA可以幫助識別和提取主要的特征,從而更好地描述數據的內在結構,有助于模式識別、數據挖掘和預測任務。
線性判別分析
線性判別分析(Linear Discriminant Analysis,英文:LDA)同樣可以用于特征降維。LDA 本來是一種分類模型,它試圖找到兩類物體或事件的特征的一個線性組合,以便能夠特征化或區分它們。
LDA 和 PCA 的本質相似,都會將原始的樣本映射到維度更低的樣本空間中。不過,PCA 映射后的樣本具有更大的發散性,而 LDA 映射后的樣本具有更明顯的類別區分。
scikit-learn 同樣提供了可以用于 LDA 處理的 API:sklearn.discriminant_analysis.LinearDiscriminantAnalysis,使用方法如下:
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
iris_lda = LinearDiscriminantAnalysis(
n_components=2).fit_transform(iris_df, iris.target) # lda 降 2 維
iris_lda = pd.DataFrame(iris_lda, columns=['lda_x', 'lda_y']) # 整理 DataFrame
通過繪制子圖來對比PCA和LDA兩種方法降維之后的數據分布:
fig, axes = plt.subplots(ncols=2, nrows=1, figsize=(12, 3))
iris_lda.plot.scatter(x='lda_x', y='lda_y', c=iris.target,
cmap='plasma', ax=axes[0]) # 數據點著色
iris_pca.plot.scatter(x='pca_x', y='pca_y', c=iris.target,
cmap='plasma', ax=axes[1]) # 數據點著色
可以從上圖看出二者的區別。PCA 和 LDA 是兩種不同的降維方法,沒有方法的好壞之說。一般情況下,PCA 會使用多一些,你可以看到 LDA 需要輸入目標值,而 PCA 則無需這一點
皮爾遜相關系數
在統計學中, 皮爾遜積矩相關系數(英語:Pearson product-moment correlation coefficient)用于度量兩個變量 ?? 和 ?? 之間的相關(線性相關),其值介于 -1 與 1 之間。在自然科學領域中,該系數廣泛用于度量兩個變量之間的相關程度。它是由卡爾·皮爾遜從弗朗西斯·高爾頓在 19 世紀 80 年代提出的一個相似卻又稍有不同的想法演變而來。這個相關系數也稱作「皮爾遜相關系數」。
兩個變量之間的皮爾遜相關系數定義為兩個變量之間的協方差和標準差的商:
\[{\displaystyle \rho _{X,Y}={\mathrm {cov} (X,Y) \over \sigma _{X}\sigma _{Y}}={E[(X-\mu _{X})(Y-\mu _{Y})] \over \sigma _{X}\sigma _{Y}}} \]有了皮爾遜相關性系數,我們就可以評估不同特征與目標值直接的相關性,從而剔除那些相關性弱的特征,達到特征壓縮的目的。接下來,我們使用 SciPy 提供的皮爾遜相關性系數計算方法 scipy.stats.pearsonr 來求解 iris 示例數據集各特征與目標值之間的相關系數。
from scipy.stats import pearsonr
for i in range(4):
p = pearsonr(iris_df.iloc[:, i], iris.target)[0] # 求解每個特征與目標值的相關性
print("{}: {}".format(iris.feature_names[i], p)) # 輸出
上文說過,皮爾遜相關系數介于 -1 與 1 之間,越接近 1 則代表越正相關。所以,iris 示例數據集中與目標值更為相關的特征是 sepal length,petal length 和 petal width。
這里再補充一種計算數據集特征和目標之間皮爾遜相關性系數的方法,你可以直接在 DataFrame 后添加 corr() 屬性獲得。更為常用的是通過 Seaborn 可視化工具繪制熱圖。
import seaborn as sns
# 得到特征和目標拼合后的 DataFrame
iris_full_df = pd.concat([pd.DataFrame(iris.data, columns=iris.feature_names),
pd.DataFrame(iris.target, columns=['iris_target'])], axis=1)
sns.heatmap(iris_full_df.corr(), square=True, annot=True) # corr() 函數計算皮爾遜相關系數
區別于手動計算各特征和目標之間的相關系數,上方熱圖還計算了特征之間的相關系數。觀察熱圖最后一行,不難發現與通過 scipy.stats.pearsonr 計算的結果一致。
卡方檢驗
在 1900 年,皮爾遜發表了著名的關于 卡方檢驗( Chi-Squared Test)的文章,該文章被認為是現代統計學的基石之一。簡單來講,實際觀測值與理論推斷值之間的偏離程度就決定卡方值的大小。若卡方值越小,代表偏差越小,越趨于符合。
scikit-learn 提供了 sklearn.feature_selection.SelectKBest 可以返回 k 個最佳特征,不過我們需要使用 sklearn.feature_selection.chi2 來計算卡方值。接下來,同樣使用 iris 數據集來進行卡方檢驗。
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
kafang = SelectKBest(score_func=chi2, k=3) # 保留 3 個最佳特征,并使用卡方檢驗
kafang.fit_transform(iris_df, iris.target)
transformer 輸出了需要保留的最佳特征,與 iris_df 對比后你會發現,它保留了與皮爾遜相關系數結果一致的 sepal length,petal length 和 petal width 特征。你可以通過 scores_ 屬性輸出卡方值的計算結果。
kafang.scores_ # 各特征與目標值之間的卡方值
這里要補充一點是,實際使用中卡方檢驗和皮爾遜相關系數的評估結果并不會都像 IRIS 數據集上一致,往往會得到不同的結果。這其實也就反映出選取最好的特征往往取決于評估指標,而沒有唯一答案。
上面我們介紹依據皮爾遜相關系數和卡方檢驗進行特征選擇的方法在特征工程中又被歸類于 Filter 過濾法,它主要側重于單個特征跟目標變量的相關性。這種方法的優點在于計算速度快,且有較高的魯棒性。但是,Filter 方法的缺點在于不考慮特征之間的相關性。因為,有可能某一個特征自身不具備代表性,但是它和某些其它特征組合起來會使得模型會得到不錯的效果。這一點就是 Filter 方法無法考慮到的了。
除此之外,從特征工程的角度來講,還可以使用 Wrapper 封裝法和 Embeded 集成方法來完成特征選擇。
數據抽樣
數據抽樣是通過減少樣本而非特征的數據來達到數據規約的效果。數據抽樣通過從原始數據集中隨機采集樣本構成子集,從而降低數據規模。
最簡單的抽樣當然就是「隨機抽樣」了,我們可以生成一組隨機索引,然后從數據集中抽取到相應的數據。這里,我們使用上方的 IRIS 數據集來完成。
import numpy as np
chosen_idx = np.random.choice(
len(iris_df), replace=False, size=10) # 從 IRIS 數據集中抽取 10 條數據
iris_df.iloc[chosen_idx] # 抽取相應索引的數據
還可以直接使用 Pandas 提供的 pandas.DataFrame.sample 方法完成隨機抽樣過程,其中只需要指定抽樣數目即可。
iris_df.sample(n=10)
注意:數據抽樣雖然在這里被歸入數據規約,但實際上更多用于前面的環節中。一般情況下,會從清洗后的數據中抽樣,使用抽樣數據來完成特征工程和建模,以探索方法實施的可能性。最終再使用完整數據集進行建模分析
總結
以上是生活随笔為你收集整理的数据分析--数据预处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 原神奶酪怎么获取 奶酪有什么作用
- 下一篇: java信息管理系统总结_java实现科