異常值

異常值是數(shù)據(jù)集中與其他觀測(cè)值顯著不同的數(shù)據(jù)點(diǎn)。它們可能是由測(cè)量誤差、罕見(jiàn)事件或僅僅是數(shù)據(jù)自然變化的一部分引起的。識(shí)別和處理異常值是至關(guān)重要的,因?yàn)樗鼈儠?huì)扭曲統(tǒng)計(jì)分析并對(duì)模型性能產(chǎn)生負(fù)面影響。

有幾種方法可以檢測(cè)異常值:

1、視覺(jué)方法:箱形圖、散點(diǎn)圖、直方圖

2、統(tǒng)計(jì)方法:

Z-score: Z-score > 3或< -3的點(diǎn)通常被認(rèn)為是異常值。

四分位間距(IQR):低于Q1-1.5 * IQR或高于Q3 + 1.5 *IQR的數(shù)據(jù)點(diǎn)通常被視為異常值。

3、機(jī)器學(xué)習(xí)方法:孤立森林、單類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

該函數(shù)計(jì)算IQR并將異常值定義為低于Q1-1.5 * IQR或高于Q3 + 1.5 * IQR的數(shù)據(jù)點(diǎn)。這個(gè)方法簡(jiǎn)單快速,效果也很好。

異常值處理

1、刪除離群值

刪除異常值是一種直截了當(dāng)?shù)姆椒ǎ珣?yīng)該謹(jǐn)慎行事。只有在以下情況下才考慮刪除:

刪除方法也很簡(jiǎn)單:

 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、帶閾值的重新分配

可以將這些值限制在某個(gè)閾值,而不是刪除。這種方法也被稱為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點(diǎn)比其鄰近點(diǎn)的密度更稀疏,距離更遠(yuǎn)。在這種情況下,可以說(shuō)點(diǎn)A是一個(gè)異常值。

LOF是一種通過(guò)測(cè)量數(shù)據(jù)點(diǎn)相對(duì)于其鄰居的局部偏差來(lái)識(shí)別異常值的算法。LOF將一個(gè)點(diǎn)的局部密度與其相鄰點(diǎn)的局部密度進(jìn)行比較,從而識(shí)別出密度明顯低于相鄰點(diǎn)的樣本。

以下是多元離群分析的代碼示例:

 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

缺失值

缺失值是現(xiàn)實(shí)世界數(shù)據(jù)集中常見(jiàn)的問(wèn)題,處理丟失數(shù)據(jù)時(shí)要考慮的一個(gè)重要問(wèn)題是丟失數(shù)據(jù)的隨機(jī)性。

Python中,你可以使用pandas輕松檢測(cè)缺失值:

 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、刪除缺失值:如果缺失值的數(shù)量相對(duì)于數(shù)據(jù)集大小較小,則刪除可能是一種有效的策略。

 def remove_missing(df, threshold=0.7):
return df.dropna(thresh=int(threshold*len(df)), axis=1).dropna()

2、用簡(jiǎn)單的方法填充

簡(jiǎn)單的插值方法包括用均值、中位數(shù)或眾數(shù)填充:

 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、分類變量分解中的值

對(duì)于數(shù)值變量,可以根據(jù)相關(guān)分類變量的平均值或中位數(shù)填充缺失值:

 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、預(yù)測(cè)賦值填充

KNN Imputer (K-Nearest Neighbors Imputer)是一種處理數(shù)據(jù)集中缺失數(shù)據(jù)的方法:

它基于k近鄰算法。對(duì)于每個(gè)缺失值的樣本,它找到K個(gè)最相似的完整樣本。然后使用這些鄰居的值來(lái)估計(jì)和填充缺失的數(shù)據(jù)。輸入值通常是相鄰值的平均值或中值。當(dāng)丟失的數(shù)據(jù)不是隨機(jī)的并且依賴于其他特征時(shí),它特別有用。

KNN Imputer比mean或median imputation等簡(jiǎn)單的imputation方法更準(zhǔn)確,特別是對(duì)于特征之間的關(guān)系很重要的數(shù)據(jù)集。但是對(duì)于大型數(shù)據(jù)集來(lái)說(shuō),它的計(jì)算成本很高。

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)

編碼

編碼是將分類變量轉(zhuǎn)換為可以提供給機(jī)器學(xué)習(xí)算法使用的格式的過(guò)程。一般包括

標(biāo)簽編碼:為類別分配唯一的數(shù)字標(biāo)簽。

獨(dú)熱編碼:將分類變量轉(zhuǎn)換為二進(jìn)制向量。

稀有編碼:當(dāng)一個(gè)分類變量有一些在數(shù)據(jù)集中很少出現(xiàn)的類別時(shí),使用這種技術(shù)。

這些編碼有助于將各種數(shù)據(jù)類型轉(zhuǎn)換為數(shù)字格式,使機(jī)器學(xué)習(xí)模型能夠提取模式并更準(zhǔn)確地進(jìn)行預(yù)測(cè)。

標(biāo)簽編碼:

標(biāo)簽編碼用于將分類數(shù)據(jù)轉(zhuǎn)換為算法可以處理的數(shù)字格式。它的工作原理是為分類變量中的每個(gè)類別分配一個(gè)唯一的整數(shù)。此方法對(duì)于類別有自然順序的有序數(shù)據(jù)特別有用,例如評(píng)級(jí)。但是標(biāo)簽編碼可能會(huì)在不存在的類別之間引入人為的順序關(guān)系,這對(duì)于某些算法來(lái)說(shuō)可能是有問(wèn)題的。

 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)

獨(dú)熱編碼:

獨(dú)熱編碼是一種用于數(shù)字表示分類數(shù)據(jù)的技術(shù),適用于需要數(shù)字輸入的機(jī)器學(xué)習(xí)算法。在這種方法中,特征中的每個(gè)唯一類別成為一個(gè)新的二進(jìn)制列。對(duì)于給定的類別,相應(yīng)的列被設(shè)置為1(或“hot”),而所有其他列都被設(shè)置為0。這種方法允許在不暗示類別之間的任何順序關(guān)系的情況下表示類別變量。它在處理標(biāo)稱數(shù)據(jù)時(shí)特別有用,因?yàn)轭悇e沒(méi)有固有的順序或?qū)哟谓Y(jié)構(gòu)。但是如果分類數(shù)據(jù)中的類別較多會(huì)增加稀疏性。

 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()

稀有編碼:

機(jī)器學(xué)習(xí)中的稀有編碼通常是指用于處理分類變量中罕見(jiàn)或不常見(jiàn)類別的技術(shù)。

當(dāng)一個(gè)分類變量有一些在數(shù)據(jù)集中很少出現(xiàn)的類別時(shí),使用這種技術(shù)可以防止過(guò)擬合,降低這些罕見(jiàn)類別給模型帶來(lái)的噪聲。

設(shè)置頻率閾值(例如,少于1%的出現(xiàn))來(lái)定義什么構(gòu)成“罕見(jiàn)”類別。這樣有助于降低模型的復(fù)雜性,改進(jìn)泛化,并處理測(cè)試數(shù)據(jù)中未見(jiàn)過(guò)的類別。

 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)

特征縮放

特征縮放是一種用于機(jī)器學(xué)習(xí)的預(yù)處理技術(shù),用于標(biāo)準(zhǔn)化數(shù)據(jù)的自變量或特征的范圍。因?yàn)樘卣髟谙嗤瑮l件下可以減少算法的訓(xùn)練時(shí)間。當(dāng)變量被標(biāo)準(zhǔn)化時(shí),減少由縮放特征產(chǎn)生的誤差的努力會(huì)更容易。因?yàn)樵谕粭l件下可以確保所有特征對(duì)模型的性能貢獻(xiàn)相同,防止較大的特征主導(dǎo)學(xué)習(xí)過(guò)程。

這對(duì)輸入特征的尺度敏感的算法尤其重要,例如基于梯度下降的算法和基于距離的算法。當(dāng)特征處于相似規(guī)模時(shí),許多機(jī)器學(xué)習(xí)算法表現(xiàn)更好或收斂更快。但是應(yīng)分別應(yīng)用于訓(xùn)練集和測(cè)試集,以避免數(shù)據(jù)泄漏。

Standard Scaling

標(biāo)準(zhǔn)化對(duì)特征進(jìn)行縮放,使它們的均值為0,方差為1。

 from sklearn.preprocessing import StandardScaler

def standard_scale(df, columns):
scaler = StandardScaler()
df[columns] = scaler.fit_transform(df[columns])
return df

Robust Scaling

Robust Scaling使用對(duì)異常值具有魯棒性的統(tǒng)計(jì)信息。

 from sklearn.preprocessing import RobustScaler

def robust_scale(df, columns):
scaler = RobustScaler()
df[columns] = scaler.fit_transform(df[columns])
return df

Min-Max Scaling

MinMax Scaling將特征縮放到一個(gè)固定的范圍,通常在0到1之間。

 from sklearn.preprocessing import MinMaxScaler

def minmax_scale(df, columns):
scaler = MinMaxScaler()
df[columns] = scaler.fit_transform(df[columns])
return df

分箱

分箱是通過(guò)創(chuàng)建一組區(qū)間將連續(xù)變量轉(zhuǎn)換為分類變量的過(guò)程。

 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

特征提取

特征提取是機(jī)器學(xué)習(xí)和數(shù)據(jù)分析中的一項(xiàng)重要技術(shù)。它包括選擇原始數(shù)據(jù)并將其轉(zhuǎn)換為一組更有用的特征,這些特征可用于進(jìn)一步處理或分析。特征提取的目的是,降低數(shù)據(jù)的維數(shù),這樣可以簡(jiǎn)化模型,提高性能。

文本統(tǒng)計(jì)特征

創(chuàng)建二進(jìn)制特征可以突出顯示數(shù)據(jù)中的重要特征。

 def create_binary_feature(df, column, condition):
df[f'{column}_flag'] = np.where(condition(df[column]), 1, 0)
return df

例如對(duì)于下面的文本

文本數(shù)據(jù)通常包含有價(jià)值的信息,這些信息可以提取為數(shù)字特征。

 # 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"]})

時(shí)間序列變量

對(duì)于時(shí)間序列可以將日期變量分解為與分析相關(guān)的各種子組件。

 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

這樣就可以針對(duì)不同的時(shí)間進(jìn)行處理。

總結(jié)

特征工程和數(shù)據(jù)預(yù)處理是任何機(jī)器學(xué)習(xí)中的關(guān)鍵步驟。它們可以通過(guò)確保數(shù)據(jù)干凈、結(jié)構(gòu)良好和信息豐富來(lái)顯著提高模型的性能。本文介紹了如何處理異常值和缺失值、編碼分類變量、縮放數(shù)值特征和創(chuàng)建新特征——為準(zhǔn)備機(jī)器學(xué)習(xí)任務(wù)的數(shù)據(jù)奠定了堅(jiān)實(shí)的基礎(chǔ)。

我們這里也只是介紹一些簡(jiǎn)單常見(jiàn)的技術(shù),使用更復(fù)雜和更具體技術(shù)將取決于數(shù)據(jù)集和試圖解決的問(wèn)題。

文章轉(zhuǎn)自微信公眾號(hào)@

上一篇:

徹底搞懂分類預(yù)測(cè)算法!

下一篇:

幾何圖神經(jīng)網(wǎng)絡(luò)GNN:數(shù)據(jù)結(jié)構(gòu)、模型與應(yīng)用
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)