Isolation Forest - anomaly detection

Author

Nguyễn Ngọc Bình

Sử dụng thuật toán Isolation Forest cho việc phát hiện dấu hiệu bất thường (anomaly detection)

Bước 1: Chuẩn bị Dữ liệu - Bắt đầu bằng việc thu thập và tải dữ liệu mà bạn muốn phát hiện các dấu hiệu bất thường.

Bước 2: Tải và Import Thư viện - Trong Python, sử dụng các thư viện sau: numpy, pandas, và sklearn.ensemble.

import numpy as np
import pandas as pd
from sklearn.ensemble import IsolationForest

Bước 3: Chuẩn bị dữ liệu - Đảm bảo rằng dữ liệu của bạn đã được chuẩn bị và lấy ra từ các cột không mong muốn.

Bước 4: Tạo Mô hình Isolation Forest - Sử dụng IsolationForest để tạo một mô hình phát hiện dấu hiệu bất thường. Bạn có thể tuỳ chỉnh mô hình bằng cách thay đổi các tham số, chẳng hạn như contamination (tỷ lệ dấu hiệu bất thường trong dữ liệu).

model = IsolationForest(contamination=0.05)  # Tuỳ chỉnh contamination tại đây

Bước 5: Huấn luyện Mô hình - Sử dụng dữ liệu huấn luyện của bạn để huấn luyện mô hình Isolation Forest.

model.fit(X)

Bước 6: Dự đoán Dấu hiệu Bất thường - Sử dụng mô hình đã huấn luyện để dự đoán dấu hiệu bất thường trên tập dữ liệu kiểm tra.

predictions = model.predict(X)

Bước 7: Lấy Điểm Anomaly - Sử dụng phương thức decision_function để lấy điểm anomaly cho mỗi mẫu dữ liệu. Điểm càng thấp càng có khả năng là dấu hiệu bất thường.

anomaly_scores = model.decision_function(X)

Bước 8: Xác định Dấu hiệu Bất thường - Dùng ngưỡng (threshold) để xác định dấu hiệu bất thường dựa trên điểm anomaly. Bạn có thể tuỳ chỉnh ngưỡng theo ý muốn.

threshold = -0.1  # Ngưỡng ngầm định, điều chỉnh tùy theo nhu cầu
anomalies = X[anomaly_scores < threshold]

Bước 9: Xuất kết quả - Xuất các mẫu bất thường mà bạn đã xác định từ dữ liệu.

print("Dấu hiệu bất thường:")
print(anomalies)

Lưu ý rằng bạn có thể tùy chỉnh các tham số và ngưỡng để điều chỉnh độ nhạy của việc phát hiện dấu hiệu bất thường dựa trên nhu cầu của bạn.

import pandas as pd
from sklearn.ensemble import IsolationForest

data_url = "https://archive.ics.uci.edu/ml/machine-learning-databases/statlog/german/german.data"
column_names = ['existing_checking', 'duration', 'credit_history', 'purpose', 'credit_amount', 'savings',
                'employment', 'installment_rate', 'personal_status', 'other_debtors', 'residence_since',
                'property', 'age', 'other_installment_plans', 'housing', 'existing_credits', 'job', 'people_liable',
                'telephone', 'foreign_worker', 'class']
data = pd.read_csv(data_url, delimiter=' ', names=column_names)

# Preprocess the data
X = data.drop('class', axis=1)
y = data['class']
X = pd.get_dummies(X, drop_first=True)


# Create an Isolation Forest model
contamination = 0.05
model = IsolationForest(contamination=contamination)

# Fit the model to your data
model.fit(X)

# Predict anomalies (1 for inliers, -1 for outliers)
predictions = model.predict(X)

# Get the anomaly scores (the lower the score, the more likely it's an anomaly)
anomaly_scores = model.decision_function(X)

# Identify anomalies
anomalies = data[predictions == -1]
c:\Users\binhnn2\anaconda3\envs\env_pycaret\lib\site-packages\sklearn\base.py:439: UserWarning: X does not have valid feature names, but IsolationForest was fitted with feature names
  warnings.warn(
anomalies
existing_checking duration credit_history purpose credit_amount savings employment installment_rate personal_status other_debtors ... property age other_installment_plans housing existing_credits job people_liable telephone foreign_worker class
44 A11 48 A34 A41 6143 A61 A75 4 A92 A101 ... A124 58 A142 A153 2 A172 1 A191 A201 2
55 A14 6 A31 A40 783 A65 A73 1 A93 A103 ... A121 26 A142 A152 1 A172 2 A191 A201 1
87 A12 36 A32 A46 12612 A62 A73 1 A93 A101 ... A124 47 A143 A153 1 A173 2 A192 A201 2
99 A12 20 A33 A41 7057 A65 A74 3 A93 A101 ... A122 36 A141 A151 2 A174 2 A192 A201 1
105 A12 24 A34 A410 11938 A61 A73 2 A93 A102 ... A123 39 A143 A152 2 A174 2 A192 A201 2
110 A12 6 A33 A49 1449 A62 A75 1 A91 A101 ... A123 31 A141 A152 2 A173 2 A191 A201 1
154 A12 24 A33 A49 6967 A62 A74 4 A93 A101 ... A123 36 A143 A151 1 A174 1 A192 A201 1
157 A11 12 A31 A48 339 A61 A75 4 A94 A101 ... A123 45 A141 A152 1 A172 1 A191 A201 1
175 A14 30 A31 A41 7485 A65 A71 4 A92 A101 ... A121 53 A141 A152 1 A174 1 A192 A201 2
181 A12 36 A33 A49 4455 A61 A73 2 A91 A101 ... A121 30 A142 A152 2 A174 1 A192 A201 2
186 A12 9 A31 A41 5129 A61 A75 2 A92 A101 ... A124 74 A141 A153 1 A174 2 A192 A201 2
191 A12 48 A30 A49 3844 A62 A74 4 A93 A101 ... A124 34 A143 A153 1 A172 2 A191 A201 2
226 A12 48 A32 A43 10961 A64 A74 1 A93 A102 ... A124 27 A141 A152 2 A173 1 A192 A201 2
263 A14 12 A34 A46 2748 A61 A75 2 A92 A101 ... A124 57 A141 A153 3 A172 1 A191 A201 1
272 A12 48 A31 A40 12169 A65 A71 4 A93 A102 ... A124 36 A143 A153 1 A174 1 A192 A201 1
287 A12 48 A33 A410 7582 A62 A71 2 A93 A101 ... A124 31 A143 A153 1 A174 1 A192 A201 1
304 A14 48 A34 A40 10127 A63 A73 2 A93 A101 ... A124 44 A141 A153 1 A173 1 A191 A201 2
306 A14 30 A32 A41 4811 A65 A74 2 A92 A101 ... A122 24 A142 A151 1 A172 1 A191 A201 1
333 A14 48 A34 A41 11590 A62 A73 2 A92 A101 ... A123 24 A141 A151 2 A172 1 A191 A201 2
343 A12 18 A32 A49 4439 A61 A75 1 A93 A102 ... A121 33 A141 A152 1 A174 1 A192 A201 1
373 A14 60 A34 A40 13756 A65 A75 2 A93 A101 ... A124 63 A141 A153 1 A174 1 A192 A201 1
374 A12 60 A31 A410 14782 A62 A75 3 A92 A101 ... A124 60 A141 A153 2 A174 1 A192 A201 2
395 A12 39 A33 A46 11760 A62 A74 2 A93 A101 ... A124 32 A143 A151 1 A173 1 A192 A201 1
449 A12 15 A33 A45 1512 A64 A73 3 A94 A101 ... A122 61 A142 A152 2 A173 1 A191 A201 2
496 A12 36 A32 A42 9034 A62 A72 4 A93 A102 ... A124 29 A143 A151 1 A174 1 A192 A201 2
539 A13 18 A32 A42 3049 A61 A72 1 A92 A101 ... A122 45 A142 A152 1 A172 1 A191 A201 1
549 A14 48 A34 A41 8858 A65 A74 2 A93 A101 ... A124 35 A143 A153 2 A173 1 A192 A201 1
551 A14 6 A31 A43 1750 A63 A75 2 A93 A101 ... A122 45 A141 A152 1 A172 2 A191 A201 1
595 A12 6 A31 A40 931 A62 A72 1 A92 A101 ... A122 32 A142 A152 1 A172 1 A191 A201 2
602 A12 24 A31 A46 1837 A61 A74 4 A92 A101 ... A124 34 A141 A153 1 A172 1 A191 A201 2
607 A12 36 A32 A43 2671 A62 A73 4 A92 A102 ... A124 50 A143 A153 1 A173 1 A191 A201 2
611 A13 10 A32 A40 1240 A62 A75 1 A92 A101 ... A124 48 A143 A153 1 A172 2 A191 A201 2
613 A11 24 A31 A41 3632 A61 A73 1 A92 A103 ... A123 22 A141 A151 1 A173 1 A191 A202 1
616 A12 60 A33 A43 9157 A65 A73 2 A93 A101 ... A124 27 A143 A153 1 A174 1 A191 A201 1
663 A12 6 A33 A42 1050 A61 A71 4 A93 A101 ... A122 35 A142 A152 2 A174 1 A192 A201 1
666 A12 30 A31 A42 3496 A64 A73 4 A93 A101 ... A123 34 A142 A152 1 A173 2 A192 A201 1
667 A14 48 A31 A49 3609 A61 A73 1 A92 A101 ... A121 27 A142 A152 1 A173 1 A191 A201 1
684 A12 36 A33 A49 9857 A62 A74 1 A93 A101 ... A122 31 A143 A152 2 A172 2 A192 A201 1
703 A12 30 A33 A49 2503 A62 A75 4 A93 A101 ... A122 41 A142 A152 2 A173 1 A191 A201 1
721 A12 6 A31 A46 433 A64 A72 4 A92 A101 ... A122 24 A141 A151 1 A173 2 A191 A201 2
754 A14 12 A33 A45 1555 A64 A75 4 A93 A101 ... A124 55 A143 A153 2 A173 2 A191 A201 2
774 A13 12 A34 A40 1480 A63 A71 2 A93 A101 ... A124 66 A141 A153 3 A171 1 A191 A201 1
808 A12 42 A31 A41 9283 A61 A71 1 A93 A101 ... A124 55 A141 A153 1 A174 1 A192 A201 1
829 A12 48 A33 A49 6681 A65 A73 4 A93 A101 ... A124 38 A143 A153 1 A173 2 A192 A201 1
876 A11 18 A31 A43 1940 A61 A72 3 A93 A102 ... A124 36 A141 A153 1 A174 1 A192 A201 1
889 A14 28 A31 A41 7824 A65 A72 3 A93 A103 ... A121 40 A141 A151 2 A173 2 A192 A201 1
895 A14 36 A33 A41 8947 A65 A74 3 A93 A101 ... A123 31 A142 A152 1 A174 2 A192 A201 1
915 A12 48 A30 A410 18424 A61 A73 1 A92 A101 ... A122 32 A141 A152 1 A174 1 A192 A202 2
927 A11 48 A32 A41 10297 A61 A74 4 A93 A101 ... A124 39 A142 A153 3 A173 2 A192 A201 2
935 A12 30 A33 A43 1919 A62 A72 4 A93 A101 ... A124 30 A142 A152 2 A174 1 A191 A201 2

50 rows × 21 columns

Ở trên đã sử dụng tỷ lệ 5% mẫu để xác định anomaly. Ngoài ra có thể điều chỉnh ngưỡng anomaly scores phù hợp thay vì đưa ra tỷ lệ.

# Identify anomalies based on anomaly scores (you can set a threshold)
threshold = -0.01  # Adjust the threshold as needed
anomalies = X[anomaly_scores < threshold]
anomalies
duration credit_amount installment_rate residence_since age existing_credits people_liable existing_checking_A12 existing_checking_A13 existing_checking_A14 ... property_A124 other_installment_plans_A142 other_installment_plans_A143 housing_A152 housing_A153 job_A172 job_A173 job_A174 telephone_A192 foreign_worker_A202
44 48 6143 4 4 58 2 1 0 0 0 ... 1 1 0 0 1 1 0 0 0 0
55 6 783 1 2 26 1 2 0 0 1 ... 0 1 0 1 0 1 0 0 0 0
87 36 12612 1 4 47 1 2 1 0 0 ... 1 0 1 0 1 0 1 0 1 0
99 20 7057 3 4 36 2 2 1 0 0 ... 0 0 0 0 0 0 0 1 1 0
175 30 7485 4 1 53 1 1 0 0 1 ... 0 0 0 1 0 0 0 1 1 0
186 9 5129 2 4 74 1 2 1 0 0 ... 1 0 0 0 1 0 0 1 1 0
191 48 3844 4 4 34 1 2 1 0 0 ... 1 0 1 0 1 1 0 0 0 0
263 12 2748 2 4 57 3 1 0 0 1 ... 1 0 0 0 1 1 0 0 0 0
272 48 12169 4 4 36 1 1 1 0 0 ... 1 0 1 0 1 0 0 1 1 0
287 48 7582 2 4 31 1 1 1 0 0 ... 1 0 1 0 1 0 0 1 1 0
304 48 10127 2 2 44 1 1 0 0 1 ... 1 0 0 0 1 0 1 0 0 0
306 30 4811 2 4 24 1 1 0 0 1 ... 0 1 0 0 0 1 0 0 0 0
374 60 14782 3 4 60 2 1 1 0 0 ... 1 0 0 0 1 0 0 1 1 0
449 15 1512 3 3 61 2 1 1 0 0 ... 0 1 0 1 0 0 1 0 0 0
496 36 9034 4 1 29 1 1 1 0 0 ... 1 0 1 0 0 0 0 1 1 0
549 48 8858 2 1 35 2 1 0 0 1 ... 1 0 1 0 1 0 1 0 1 0
595 6 931 1 1 32 1 1 1 0 0 ... 0 1 0 1 0 1 0 0 0 0
602 24 1837 4 4 34 1 1 1 0 0 ... 1 0 0 0 1 1 0 0 0 0
613 24 3632 1 4 22 1 1 0 0 0 ... 0 0 0 0 0 0 1 0 0 1
616 60 9157 2 2 27 1 1 1 0 0 ... 1 0 1 0 1 0 0 1 0 0
663 6 1050 4 1 35 2 1 1 0 0 ... 0 1 0 1 0 0 0 1 1 0
667 48 3609 1 1 27 1 1 0 0 1 ... 0 1 0 1 0 0 1 0 0 0
754 12 1555 4 4 55 2 2 0 0 1 ... 1 0 1 0 1 0 1 0 0 0
808 42 9283 1 2 55 1 1 1 0 0 ... 1 0 0 0 1 0 0 1 1 0
889 28 7824 3 4 40 2 2 0 0 1 ... 0 0 0 0 0 0 1 0 1 0
895 36 8947 3 2 31 1 2 0 0 1 ... 0 1 0 1 0 0 0 1 1 0
915 48 18424 1 2 32 1 1 1 0 0 ... 0 0 0 1 0 0 0 1 1 1
927 48 10297 4 4 39 3 2 0 0 0 ... 1 1 0 0 1 0 1 0 1 0
935 30 1919 4 3 30 2 1 1 0 0 ... 1 1 0 1 0 0 0 1 0 0

29 rows × 48 columns

Nhược điểm của Isolation Forest

Isolation Forest là một thuật toán mạnh mẽ cho phát hiện dấu hiệu bất thường trong dữ liệu. Tuy nhiên, nó cũng có nhược điểm và hạn chế của riêng nó. Dưới đây là một số nhược điểm của Isolation Forest cùng với ví dụ:

Nhược Điểm:

  1. Không hiệu quả đối với dấu hiệu bất thường gần nhau: Isolation Forest không hoạt động tốt trong việc phát hiện dấu hiệu bất thường nằm gần nhau hoặc trải dài dọc theo một đường.

  2. Độ nhạy với giá trị ngưỡng: Việc đặt ngưỡng quyết định dấu hiệu bất thường có thể khá khó và phụ thuộc vào kiểu dữ liệu và phân phối của dữ liệu. Nếu bạn đặt ngưỡng quá thấp, có thể dẫn đến nhiều dấu hiệu giả mạo; ngược lại, nếu đặt ngưỡng quá cao, có thể bỏ lỡ nhiều dấu hiệu thực sự bất thường.

  3. Khả năng đối mặt với dữ liệu nhiều chiều: Isolation Forest có thể gặp khó khăn khi xử lý dữ liệu có số chiều rất lớn. Trong các không gian nhiều chiều, việc tạo ra các phân nhánh ngẫu nhiên có thể dẫn đến các cây con có chiều sâu quá thấp, làm giảm khả năng phát hiện dấu hiệu bất thường.

Ví dụ về Nhược Điểm của Isolation Forest:

Giả sử bạn có dữ liệu về giao dịch tài chính trong một ngân hàng và bạn muốn phát hiện gian lận trong các giao dịch. Một số gian lận xảy ra với các mẫu tương tự với các giao dịch thông thường, nhưng với số lượng nhỏ và gần nhau trong không gian đặc trưng. Isolation Forest có thể không hiệu quả trong việc phát hiện các gian lận như vậy vì nó có thể đánh giá chúng là dấu hiệu thông thường do chúng không được cô lập.

Nhược điểm này có thể được khắc phục bằng cách sử dụng các kỹ thuật phát hiện gian lận cơ bản hơn và phù hợp hơn cho loại tình huống này hoặc bằng việc sử dụng các thuật toán khác như Local Outlier Factor (LOF) hoặc One-Class SVM.

import numpy as np
import matplotlib.pyplot as plt

# Set a random seed for reproducibility
np.random.seed(0)

# Generate random data for the first blob (normal data)
mean1 = [2, 2]
cov1 = [[1, 0.5], [0.5, 1]]
data1 = np.random.multivariate_normal(mean1, cov1, 100)

# Generate random data for the second blob (abnormal data)
mean2 = [7, 7]
cov2 = [[1, -0.5], [-0.5, 1]]
data2 = np.random.multivariate_normal(mean2, cov2, 100)

# Combine the two sets of data
data = np.vstack((data1, data2))

# Create a scatter plot of the data
plt.scatter(data1[:, 0], data1[:, 1], marker='o', c='b', label='Normal Data')
plt.scatter(data2[:, 0], data2[:, 1], marker='x', c='r', label='Abnormal Data')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.title("Can't distinct normal and abnormal")
plt.legend()

plt.grid()
plt.show()