在機器學習和數據科學的世界里,數據的質量是建模成功與否的關鍵所在。這就是特征工程和數據預處理發揮作用的地方。本文總結的這些關鍵步驟可以顯著提高模型的性能,獲得更準確的預測,我們將深入研究處理異常值、缺失值、編碼、特征縮放和特征提取的各種技術。
異常值異常值是數據集中與其他觀測值顯著不同的數據點。它們可能是由測量誤差、罕見事件或僅僅是數據自然變化的一部分引起的。識別和處理異常值是至關重要的,因為它們會扭曲統計分析并對模型性能產生負面影響。
有幾種方法可以檢測異常值:1、視覺方法:箱形圖、散點圖、直方圖2、統計方法:Z-score: Z-score > 3或< -3的點通常被認為是異常值。四分位間距(IQR):低于Q1-1.5 * IQR或高于Q3 + 1.5 *IQR的數據點通常被視為異常值。3、機器學習方法:孤立森林、單類SVM、局部離群因子(LOF)而最常用的方法之一是使用四分位間距(IQR)方法
def outlier_thresholds(dataframe, col_name, q1=0.25, q3=0.75): quartile1 = dataframe[col_name].quantile(q1) quartile3 = dataframe[col_name].quantile(q3) interquantile_range = quartile3 - quartile1 up_limit = quartile3 + 1.5 * interquantile_range low_limit = quartile1 - 1.5 * interquantile_range return low_limit, up_limit
def check_outlier(dataframe, col_name): low_limit, up_limit = outlier_thresholds(dataframe, col_name) if dataframe[(dataframe[col_name] > up_limit) | (dataframe[col_name] < low_limit)].any(axis=None): return True else: return False
該函數計算IQR并將異常值定義為低于Q1-1.5 * IQR或高于Q3 + 1.5 * IQR的數據點。這個方法簡單快速,效果也很好。
異常值處理
1、刪除離群值
刪除異常值是一種直截了當的方法,但應該謹慎行事。只有在以下情況下才考慮刪除:
確定異常值是由于數據錯誤造成的。
數據集足夠大,刪除幾個點不會顯著影響你的分析。
- 異常值不能代表正在研究的人群。
刪除方法也很簡單:
def remove_outlier(dataframe, col_name): low_limit, up_limit = outlier_thresholds(dataframe, col_name) df_without_outliers = dataframe[~((dataframe[col_name] < low_limit) | (dataframe[col_name] > up_limit))] return df_without_outliers
2、帶閾值的重新分配可以將這些值限制在某個閾值,而不是刪除。這種方法也被稱為winsorization。以下是使用threshold重新賦值的代碼示例:
def replace_with_thresholds(dataframe, variable): low_limit, up_limit = outlier_thresholds(dataframe, variable) dataframe.loc[(dataframe[variable] < low_limit), variable] = low_limit dataframe.loc[(dataframe[variable] > up_limit), variable] = up_limit
多元離群分析:局部離群因子
LOF算法:圖像中的A點比其鄰近點的密度更稀疏,距離更遠。在這種情況下,可以說點A是一個異常值。LOF是一種通過測量數據點相對于其鄰居的局部偏差來識別異常值的算法。LOF將一個點的局部密度與其相鄰點的局部密度進行比較,從而識別出密度明顯低于相鄰點的樣本。以下是多元離群分析的代碼示例:
from sklearn.neighbors import LocalOutlierFactor
def detect_outliers_lof(data, n_neighbors=20): lof = LocalOutlierFactor(n_neighbors=n_neighbors, contamination='auto') outlier_labels = lof.fit_predict(data) return outlier_labels == -1 # True for outliers, False for inliers
缺失值缺失值是現實世界數據集中常見的問題,處理丟失數據時要考慮的一個重要問題是丟失數據的隨機性。在Python中,你可以使用pandas輕松檢測缺失值:
def missing_values_table(dataframe, na_name=False): na_columns = [col for col in dataframe.columns if dataframe[col].isnull().sum() > 0]
n_miss = dataframe[na_columns].isnull().sum().sort_values(ascending=False) ratio = (dataframe[na_columns].isnull().sum() / dataframe.shape[0] * 100).sort_values(ascending=False) missing_df = pd.concat([n_miss, np.round(ratio, 2)], axis=1, keys=['n_miss', 'ratio']) print(missing_df, end="\n")
if na_name: return na_columns
缺失值處理
1、刪除缺失值:如果缺失值的數量相對于數據集大小較小,則刪除可能是一種有效的策略。
def remove_missing(df, threshold=0.7): return df.dropna(thresh=int(threshold*len(df)), axis=1).dropna()
2、用簡單的方法填充簡單的插值方法包括用均值、中位數或眾數填充:
def simple_impute(dataframe):
cat_cols = [col for col in dataframe.columns if dataframe[col].dtypes == "O"] num_but_cat = [col for col in dataframe.columns if dataframe[col].nunique() < cat_th and dataframe[col].dtypes != "O"] cat_but_car = [col for col in dataframe.columns if dataframe[col].nunique() > car_th and dataframe[col].dtypes == "O"] cat_cols = cat_cols + num_but_cat cat_cols = [col for col in cat_cols if col not in cat_but_car]
num_cols = [col for col in dataframe.columns if dataframe[col].dtypes != "O"] num_cols = [col for col in num_cols if col not in num_but_cat]
df[num_cols] = df[num_cols].fillna(df[num_cols].median()) df[cat_cols] = df[cat_cols].fillna(df[cat_cols].mode().iloc[0])
return df
3、分類變量分解中的值對于數值變量,可以根據相關分類變量的平均值或中位數填充缺失值:
def categorical_impute(df, col_1, col_2, method="mean"): df[col_1].fillna(df.groupby(col_2)[col_1].transform(method)) return df
4、預測賦值填充KNN Imputer (K-Nearest Neighbors Imputer)是一種處理數據集中缺失數據的方法:它基于k近鄰算法。對于每個缺失值的樣本,它找到K個最相似的完整樣本。然后使用這些鄰居的值來估計和填充缺失的數據。輸入值通常是相鄰值的平均值或中值。當丟失的數據不是隨機的并且依賴于其他特征時,它特別有用。KNN Imputer比mean或median imputation等簡單的imputation方法更準確,特別是對于特征之間的關系很重要的數據集。但是對于大型數據集來說,它的計算成本很高。
from sklearn.impute import KNNImputer
def knn_impute(dataframe, n_neighbors=5):
cat_cols = [col for col in dataframe.columns if dataframe[col].dtypes == "O"] num_but_cat = [col for col in dataframe.columns if dataframe[col].nunique() < cat_th and dataframe[col].dtypes != "O"] cat_but_car = [col for col in dataframe.columns if dataframe[col].nunique() > car_th and dataframe[col].dtypes == "O"] cat_cols = cat_cols + num_but_cat cat_cols = [col for col in cat_cols if col not in cat_but_car]
num_cols = [col for col in dataframe.columns if dataframe[col].dtypes != "O"] num_cols = [col for col in num_cols if col not in num_but_cat]
df = pd.get_dummies(dataframe[cat_cols + num_cols], drop_first=True)
# Standardization of Variables scaler = MinMaxScaler() df = pd.DataFrame(scaler.fit_transform(df), columns=df.columns) df.head()
# Implementation of KNN
imputer = KNNImputer(n_neighbors=n_neighbors)
return pd.DataFrame(imputer.fit_transform(df), columns=df.columns)
編碼
編碼是將分類變量轉換為可以提供給機器學習算法使用的格式的過程。一般包括標簽編碼:為類別分配唯一的數字標簽。獨熱編碼:將分類變量轉換為二進制向量。稀有編碼:當一個分類變量有一些在數據集中很少出現的類別時,使用這種技術。這些編碼有助于將各種數據類型轉換為數字格式,使機器學習模型能夠提取模式并更準確地進行預測。標簽編碼:標簽編碼用于將分類數據轉換為算法可以處理的數字格式。它的工作原理是為分類變量中的每個類別分配一個唯一的整數。此方法對于類別有自然順序的有序數據特別有用,例如評級。但是標簽編碼可能會在不存在的類別之間引入人為的順序關系,這對于某些算法來說可能是有問題的。
from sklearn.preprocessing import LabelEncoder
def label_encoder(dataframe, binary_col): labelencoder = LabelEncoder() dataframe[binary_col] = labelencoder.fit_transform(dataframe[binary_col]) return dataframe
binary_cols = [col for col in df.columns if df[col].dtype not in [int, float] and df[col].nunique() == 2]
for col in binary_cols: label_encoder(df, col)
獨熱編碼:獨熱編碼是一種用于數字表示分類數據的技術,適用于需要數字輸入的機器學習算法。在這種方法中,特征中的每個唯一類別成為一個新的二進制列。對于給定的類別,相應的列被設置為1(或“hot”),而所有其他列都被設置為0。這種方法允許在不暗示類別之間的任何順序關系的情況下表示類別變量。它在處理標稱數據時特別有用,因為類別沒有固有的順序或層次結構。但是如果分類數據中的類別較多會增加稀疏性。
def one_hot_encoder(dataframe, categorical_cols, drop_first=True): dataframe = pd.get_dummies(dataframe, columns=categorical_cols, drop_first=drop_first) return dataframe
ohe_cols = [col for col in df.columns if 10 >= df[col].nunique() > 2]
one_hot_encoder(df, ohe_cols).head()
稀有編碼:機器學習中的稀有編碼通常是指用于處理分類變量中罕見或不常見類別的技術。當一個分類變量有一些在數據集中很少出現的類別時,使用這種技術可以防止過擬合,降低這些罕見類別給模型帶來的噪聲。
- 將不常見的類別分組:將不常見的類別合并到一個“其他”類別中。
- 基于頻率的編碼:用數據集中的頻率替換稀有類別。
- 基于相似性的編碼:根據與更常見的類別的相似性對罕見類別進行分組。
設置頻率閾值(例如,少于1%的出現)來定義什么構成“罕見”類別。這樣有助于降低模型的復雜性,改進泛化,并處理測試數據中未見過的類別。
cat_cols = [col for col in dataframe.columns if dataframe[col].dtypes == "O"] num_but_cat = [col for col in dataframe.columns if dataframe[col].nunique() < cat_th and dataframe[col].dtypes != "O"] cat_but_car = [col for col in dataframe.columns if dataframe[col].nunique() > car_th and dataframe[col].dtypes == "O"] cat_cols = cat_cols + num_but_cat cat_cols = [col for col in cat_cols if col not in cat_but_car]
def rare_analyser(dataframe, target, cat_cols): for col in cat_cols: print(col, ":", len(dataframe[col].value_counts())) print(pd.DataFrame({"COUNT": dataframe[col].value_counts(), "RATIO": dataframe[col].value_counts() / len(dataframe), "TARGET_MEAN": dataframe.groupby(col)[target].mean()}), end="\n\n\n")
rare_analyser(df, "TARGET", cat_cols)
def rare_encoder(dataframe, rare_perc): temp_df = dataframe.copy()
rare_columns = [col for col in temp_df.columns if temp_df[col].dtypes == 'O' and (temp_df[col].value_counts() / len(temp_df) < rare_perc).any(axis=None)]
for var in rare_columns: tmp = temp_df[var].value_counts() / len(temp_df) rare_labels = tmp[tmp < rare_perc].index temp_df[var] = np.where(temp_df[var].isin(rare_labels), 'Rare', temp_df[var])
return temp_df
new_df = rare_encoder(df, 0.01)
特征縮放
特征縮放是一種用于機器學習的預處理技術,用于標準化數據的自變量或特征的范圍。因為特征在相同條件下可以減少算法的訓練時間。當變量被標準化時,減少由縮放特征產生的誤差的努力會更容易。因為在同一條件下可以確保所有特征對模型的性能貢獻相同,防止較大的特征主導學習過程。這對輸入特征的尺度敏感的算法尤其重要,例如基于梯度下降的算法和基于距離的算法。當特征處于相似規模時,許多機器學習算法表現更好或收斂更快。但是應分別應用于訓練集和測試集,以避免數據泄漏。Standard Scaling標準化對特征進行縮放,使它們的均值為0,方差為1。
from sklearn.preprocessing import StandardScaler
def standard_scale(df, columns): scaler = StandardScaler() df[columns] = scaler.fit_transform(df[columns]) return df
Robust ScalingRobust Scaling使用對異常值具有魯棒性的統計信息。
from sklearn.preprocessing import RobustScaler
def robust_scale(df, columns): scaler = RobustScaler() df[columns] = scaler.fit_transform(df[columns]) return df
Min-Max ScalingMinMax Scaling將特征縮放到一個固定的范圍,通常在0到1之間。
from sklearn.preprocessing import MinMaxScaler
def minmax_scale(df, columns): scaler = MinMaxScaler() df[columns] = scaler.fit_transform(df[columns]) return df
分箱分箱是通過創建一組區間將連續變量轉換為分類變量的過程。
import numpy as np
def binning(df, column, bins, labels=None): df[f'{column}_binned'] = pd.qcut(df[column], bins=bins, labels=labels) return df
特征提取
特征提取是機器學習和數據分析中的一項重要技術。它包括選擇原始數據并將其轉換為一組更有用的特征,這些特征可用于進一步處理或分析。特征提取的目的是,降低數據的維數,這樣可以簡化模型,提高性能。文本統計特征創建二進制特征可以突出顯示數據中的重要特征。
def create_binary_feature(df, column, condition): df[f'{column}_flag'] = np.where(condition(df[column]), 1, 0) return df
例如對于下面的文本文本數據通常包含有價值的信息,這些信息可以提取為數字特征。
# Letter Count
df["NEW_NAME_COUNT"] = df["Name"].str.len()
# Word Count
df["NEW_NAME_WORD_COUNT"] = df["Name"].apply(lambda x: len(str(x).split(" ")))
# Capturing Special Structures
df["NEW_NAME_DR"] = df["Name"].apply(lambda x: len([x for x in x.split() if x.startswith("Dr")]))
df.groupby("NEW_NAME_DR").agg({"Survived": ["mean","count"]})
# Deriving Variables with Regex
df['NEW_TITLE'] = df.Name.str.extract(' ([A-Za-z]+)\.', expand=False)
df[["NEW_TITLE", "Survived", "AGE"]].groupby(["NEW_TITLE"]).agg({"Survived": "mean", "AGE": ["count", "mean"]})
時間序列變量對于時間序列可以將日期變量分解為與分析相關的各種子組件。
def date_features(df, date_column): df[f'{date_column}_year'] = df[date_column].dt.year df[f'{date_column}_month'] = df[date_column].dt.month df[f'{date_column}_day'] = df[date_column].dt.day df[f'{date_column}_dayofweek'] = df[date_column].dt.dayofweek return df
這樣就可以針對不同的時間進行處理。
總結特征工程和數據預處理是任何機器學習中的關鍵步驟。它們可以通過確保數據干凈、結構良好和信息豐富來顯著提高模型的性能。本文介紹了如何處理異常值和缺失值、編碼分類變量、縮放數值特征和創建新特征——為準備機器學習任務的數據奠定了堅實的基礎。
我們這里也只是介紹一些簡單常見的技術,使用更復雜和更具體技術將取決于數據集和試圖解決的問題。
作者:Kursat Dinc
本文來源:DeepHub IMBA
-
檢測
+關注
關注
5文章
4480瀏覽量
91443 -
機器學習
+關注
關注
66文章
8406瀏覽量
132562 -
數據預處理
+關注
關注
1文章
20瀏覽量
2756
發布評論請先 登錄
相關推薦
評論