import pandas as pd
import matplotlib.pyplot as plt

# 設(shè)置隨機(jī)種子以確保可重復(fù)性
np.random.seed(42)

# 生成一個(gè)1000個(gè)數(shù)據(jù)點(diǎn)的正態(tài)分布數(shù)據(jù)集
data = np.random.normal(loc=50, scale=5, size=1000)

# 人為地添加一些異常值
data[100] = 80
data[200] = 85
data[300] = 90

# 創(chuàng)建DataFrame
df = pd.DataFrame(data, columns=['Value'])

# 僅進(jìn)行數(shù)據(jù)的可視化,不標(biāo)注異常值索引
plt.figure(figsize=(10, 6))
plt.plot(df['Value'], 'b.', label='Data Points')
plt.title('Data Points Visualization')
plt.xlabel('Index')
plt.ylabel('Value')
plt.grid(linestyle='--', alpha=0.7)
plt.show()

生成一個(gè)包含1000個(gè)數(shù)據(jù)點(diǎn)的正態(tài)分布數(shù)據(jù)集,加入了幾個(gè)異常值,然后將數(shù)據(jù)點(diǎn)可視化為一個(gè)散點(diǎn)圖,這個(gè)數(shù)據(jù)將為接下來(lái)的實(shí)驗(yàn)數(shù)據(jù)。

箱線(xiàn)圖實(shí)現(xiàn)

# 繪制箱線(xiàn)圖
plt.figure(figsize=(10, 6))
plt.boxplot(df['Value'], vert=False)
plt.title('Boxplot of Data Values')
plt.xlabel('Value')
plt.grid(linestyle='--', alpha=0.7)
plt.show()

# 計(jì)算異常值
Q1 = df['Value'].quantile(0.25)
Q3 = df['Value'].quantile(0.75)
IQR = Q3 - Q1

# 異常值定義為低于Q1 - 1.5 * IQR或高于Q3 + 1.5 * IQR的數(shù)據(jù)點(diǎn)
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 找出異常值及其索引
outliers = df[(df['Value'] < lower_bound) | (df['Value'] > upper_bound)]

# 輸出異常值的索引及其對(duì)應(yīng)的值
outliers_indices = outliers.index.tolist()
outliers_values = outliers['Value'].tolist()

print("異常值索引: ", outliers_indices)
print("異常值對(duì)應(yīng)的值: ", outliers_values)

箱線(xiàn)圖繪制:使用plt.boxplot()函數(shù)繪制數(shù)據(jù)的箱線(xiàn)圖,可以直觀(guān)地看到異常值的位置,計(jì)算異常值:通過(guò)計(jì)算四分位數(shù)(Q1和Q3)及四分位距(IQR),設(shè)定異常值的上下限,然后通過(guò)這些上下限找出異常值,執(zhí)行代碼后,你會(huì)看到一個(gè)箱線(xiàn)圖以及異常值的索引和值,箱線(xiàn)圖展示了數(shù)據(jù)的分布情況,異常值位于圖中的“胡須”之外,然后你就可以根據(jù)索引對(duì)異常值進(jìn)行相應(yīng)處理,如果刪除后就按照缺失值的方法去填補(bǔ)數(shù)據(jù)。

標(biāo)準(zhǔn)差實(shí)現(xiàn)

# 定義函數(shù) detect_outliers,接受兩個(gè)參數(shù):DataFrame 和需要檢查的列名
def detect_outliers(df, column_names):
# 初始化一個(gè)空的 Index,用于存儲(chǔ)異常值的索引
outlier_indices = pd.Index([])

# 遍歷指定的列名列表
for column_name in column_names:
# 計(jì)算當(dāng)前列的均值和標(biāo)準(zhǔn)差
mean = df[column_name].mean()
std = df[column_name].std()

# 計(jì)算Z-score
z_scores = (df[column_name] - mean) / std

# 設(shè)置 Z-score 閾值,例如,選擇閾值為 3,即超過(guò)3個(gè)標(biāo)準(zhǔn)差的值被認(rèn)為是異常值
threshold = 3

# 找出Z-score絕對(duì)值大于閾值的行
outliers = df[abs(z_scores) > threshold]

# 將新找到的異常值索引與已有異常值索引合并
outlier_indices = outlier_indices.union(outliers.index)

# 返回所有異常值的索引列表
return outlier_indices

# 使用函數(shù)檢測(cè)異常值
outlier_indices = detect_outliers(df, ['Value'])

# 獲取異常值及其對(duì)應(yīng)的索引和值
outliers = df.loc[outlier_indices]

# 輸出異常值的索引及其對(duì)應(yīng)的值
print("異常值索引: ", outlier_indices.tolist())
print("異常值對(duì)應(yīng)的值: ", outliers['Value'].tolist())

# 繪制數(shù)據(jù)的散點(diǎn)圖,并在圖中標(biāo)注異常值
plt.figure(figsize=(10, 6))
plt.plot(df.index, df['Value'], 'b.', label='Data Points')
plt.plot(outliers.index, outliers['Value'], 'ro', label='Outliers')

# 在異常值點(diǎn)上標(biāo)注其索引和值
for index, value in outliers.iterrows():
plt.text(index, value['Value'] + 0.5, f'{index}',
horizontalalignment='center', color='red', fontsize=10)

# 設(shè)置圖表標(biāo)題和軸標(biāo)簽
plt.title('Scatter Plot with Outliers Highlighted', fontsize=16)
plt.xlabel('Index', fontsize=14)
plt.ylabel('Value', fontsize=14)
plt.grid(linestyle='--', alpha=0.7)
plt.legend()
plt.show()

檢測(cè)異常值函數(shù) detect_outliers:使用Z-score方法來(lái)檢測(cè)異常值,Z-score超過(guò)3的值被認(rèn)為是異常值,輸出異常值:打印出檢測(cè)到的異常值的索引和對(duì)應(yīng)的值,可視化:使用散點(diǎn)圖(plt.plot)繪制所有數(shù)據(jù)點(diǎn),將異常值用紅色圓點(diǎn)標(biāo)出,并在其上方標(biāo)注對(duì)應(yīng)的索引。

Grubbs假設(shè)檢驗(yàn)實(shí)現(xiàn)

from scipy.stats import t

# 定義 Grubbs 檢驗(yàn)的函數(shù) detect_outliers_grubbs
def detect_outliers_grubbs(df, column_names, alpha=0.05):
# 初始化一個(gè)空的 Index,用于存儲(chǔ)異常值的索引
outlier_indices = pd.Index([])

# 遍歷指定的列名列表
for column_name in column_names:
# 獲取當(dāng)前列的數(shù)據(jù)
data = df[column_name]

# 計(jì)算均值和標(biāo)準(zhǔn)差
mean = np.mean(data)
std = np.std(data, ddof=1) # 使用樣本標(biāo)準(zhǔn)差,自由度為1

# 計(jì)算 Grubbs 檢驗(yàn)的統(tǒng)計(jì)量
n = len(data)
t_critical = t.ppf(1 - alpha / (2 * n), n - 2)
g = (np.max(data) - mean) / std

# 設(shè)置 Grubbs 檢驗(yàn)的閾值
threshold = ((n - 1) / np.sqrt(n)) * np.sqrt(t_critical**2 / (n - 2 + t_critical**2))

# 找出 Grubbs 檢驗(yàn)的異常值
outliers = df[np.abs((data - mean) / std) > threshold]

# 將新找到的異常值索引與已有異常值索引合并
outlier_indices = outlier_indices.union(outliers.index)

# 返回所有異常值的索引列表
return outlier_indices

# 使用 Grubbs 檢驗(yàn)檢測(cè)異常值
outlier_indices = detect_outliers_grubbs(df, ['Value'])

# 獲取異常值及其對(duì)應(yīng)的索引和值
outliers = df.loc[outlier_indices]

# 輸出異常值的索引及其對(duì)應(yīng)的值
print("異常值索引: ", outlier_indices.tolist())
print("異常值對(duì)應(yīng)的值: ", outliers['Value'].tolist())

# 繪制數(shù)據(jù)的散點(diǎn)圖,并在圖中標(biāo)注異常值
plt.figure(figsize=(10, 6))
plt.plot(df.index, df['Value'], 'b.', label='Data Points')
plt.plot(outliers.index, outliers['Value'], 'ro', label='Outliers')

# 在異常值點(diǎn)上標(biāo)注其索引和值
for index, value in outliers.iterrows():
plt.text(index, value['Value'] + 0.5, f'{index}',
horizontalalignment='center', color='red', fontsize=10)

# 設(shè)置圖表標(biāo)題和軸標(biāo)簽
plt.title('Scatter Plot with Grubbs Outliers Highlighted', fontsize=16)
plt.xlabel('Index', fontsize=14)
plt.ylabel('Value', fontsize=14)
plt.grid(linestyle='--', alpha=0.7)
plt.legend()
plt.show()

通過(guò)計(jì)算Grubbs統(tǒng)計(jì)量G和臨界值,將超過(guò)臨界值的點(diǎn)視為異常值,t_critical 使用Student t分布的臨界值來(lái)計(jì)算Grubbs檢驗(yàn)的閾值,這個(gè)方法提供了一種基于假設(shè)檢驗(yàn)的統(tǒng)計(jì)方法來(lái)識(shí)別異常值,適用于更嚴(yán)格的異常值檢測(cè)場(chǎng)景,在實(shí)際應(yīng)用中,盡管不同異常值檢測(cè)方法的輸出結(jié)果可能有所不同(可以和前面的方法對(duì)比),但Grubbs檢驗(yàn)在實(shí)驗(yàn)數(shù)據(jù)中成功地識(shí)別出了所有人為添加的異常值,顯示了其在異常值檢測(cè)方面的有效性和精準(zhǔn)性。

集成學(xué)習(xí)(孤立森林)實(shí)現(xiàn)

from sklearn.ensemble import IsolationForest

# 使用孤立森林進(jìn)行異常值檢測(cè)
iso_forest = IsolationForest(contamination=0.01, random_state=42)
df['Anomaly'] = iso_forest.fit_predict(df[['Value']])

# 獲取異常值的索引及其對(duì)應(yīng)的值
anomalies = df[df['Anomaly'] == -1]
anomaly_indices = anomalies.index
anomaly_values = anomalies['Value']

# 打印異常值的索引和對(duì)應(yīng)的值
print("異常值索引: ", list(anomaly_indices))
print("異常值對(duì)應(yīng)的值: ", list(anomaly_values))

# 數(shù)據(jù)可視化
plt.figure(figsize=(10, 6))
plt.plot(df['Value'], 'b.', label='Data Points')
plt.plot(anomaly_indices, anomaly_values, 'ro', label='Outliers')
plt.title('Data Points with Anomalies Visualization')
plt.xlabel('Index')
plt.ylabel('Value')
plt.grid(linestyle='--', alpha=0.7)

# 標(biāo)注異常值索引
for i, index in enumerate(anomaly_indices):
plt.text(index, anomaly_values.iloc[i] + 1, f'{index}', color='red', fontsize=9)

plt.legend()
plt.show()

孤立森林檢測(cè): 使用 IsolationForest 進(jìn)行異常值檢測(cè),標(biāo)記異常值為 -1,可視化: 使用 matplotlib 可視化數(shù)據(jù),并在圖中標(biāo)注異常值的索引,異常值以紅色散點(diǎn)顯示,并在旁邊標(biāo)注其索引。

DBSCAN聚類(lèi)實(shí)現(xiàn)

對(duì)于如何使用 DBSCAN 進(jìn)行異常值檢測(cè),我之前已經(jīng)撰寫(xiě)了一篇詳細(xì)的文章,了解更多關(guān)于 DBSCAN 聚類(lèi)和異常值檢測(cè)的內(nèi)容:密度聚類(lèi)DBSCAN詳解。

總結(jié)

在這里可以發(fā)現(xiàn)每種方法的檢測(cè)結(jié)果都不完全一致,但是每種異常值檢測(cè)方法的檢測(cè)結(jié)果不一致是正常的,這是因?yàn)樗鼈兊脑砗瓦m用場(chǎng)景不同,箱線(xiàn)圖和標(biāo)準(zhǔn)差方法依賴(lài)于數(shù)據(jù)的分布特征,適合于簡(jiǎn)單和對(duì)稱(chēng)分布的數(shù)據(jù);Grubbs 假設(shè)檢驗(yàn)適合檢測(cè)單個(gè)異常值;而孤立森林則擅長(zhǎng)處理高維和復(fù)雜的數(shù)據(jù),選擇哪種方法取決于具體的數(shù)據(jù)特征和分析需求,建議在實(shí)際應(yīng)用中結(jié)合多種方法進(jìn)行對(duì)比,以確保檢測(cè)到的異常值更加準(zhǔn)確和全面。

文章轉(zhuǎn)自微信公眾號(hào)@Python機(jī)器學(xué)習(xí)AI

上一篇:

提升機(jī)器學(xué)習(xí)精度:利用SHAP值與蒙特卡洛模擬優(yōu)化特征選擇

下一篇:

理解 SHAP 值:如何根據(jù)模型性質(zhì)正確解釋 XGBoost 與隨機(jī)森林的結(jié)果

我們有何不同?

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

多API并行試用

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

查看全部API→
??

熱門(mén)場(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)