(Câu trả lời này đã trả lời một câu hỏi trùng lặp (hiện đã đóng) tại Phát hiện các sự kiện nổi bật , trong đó trình bày một số dữ liệu ở dạng đồ họa.)
Phát hiện ngoại lệ phụ thuộc vào bản chất của dữ liệu và vào những gì bạn sẵn sàng thừa nhận về chúng. Phương pháp mục đích chung dựa trên số liệu thống kê mạnh mẽ. Tinh thần của phương pháp này là đặc trưng hóa phần lớn dữ liệu theo cách không bị ảnh hưởng bởi bất kỳ ngoại lệ nào và sau đó chỉ ra bất kỳ giá trị riêng lẻ nào không phù hợp với đặc tính đó.
Bởi vì đây là một chuỗi thời gian, nó thêm vào sự phức tạp của việc cần (phát hiện lại) các ngoại lệ trên cơ sở liên tục. Nếu điều này được thực hiện khi chuỗi mở ra, thì chúng tôi chỉ được phép sử dụng dữ liệu cũ hơn để phát hiện, không phải dữ liệu trong tương lai! Hơn nữa, vì bảo vệ chống lại nhiều thử nghiệm lặp đi lặp lại, chúng tôi muốn sử dụng một phương pháp có tỷ lệ dương tính giả rất thấp.
Những cân nhắc này đề nghị chạy một cửa sổ di chuyển đơn giản, mạnh mẽ kiểm tra ngoại lệ đối với dữ liệu . Có nhiều khả năng, nhưng một khả năng đơn giản, dễ hiểu và dễ thực hiện dựa trên MAD đang chạy: độ lệch tuyệt đối trung vị so với trung vị. Đây là một thước đo mạnh mẽ của sự thay đổi trong dữ liệu, gần giống với độ lệch chuẩn. Một đỉnh cao bên ngoài sẽ là một số MAD hoặc lớn hơn trung bình.
Vẫn còn một số điều chỉnh cần thực hiện : độ lệch của phần lớn dữ liệu nên được xem là bao xa và thời gian quay ngược thời gian bao lâu? Hãy để những điều này làm tham số cho thử nghiệm. Đây là một R
triển khai được áp dụng cho dữ liệu (với để mô phỏng dữ liệu) với các giá trị tương ứng :n = 1150 yx=(1,2,…,n)n=1150y
# Parameters to tune to the circumstances:
window <- 30
threshold <- 5
# An upper threshold ("ut") calculation based on the MAD:
library(zoo) # rollapply()
ut <- function(x) {m = median(x); median(x) + threshold * median(abs(x - m))}
z <- rollapply(zoo(y), window, ut, align="right")
z <- c(rep(z[1], window-1), z) # Use z[1] throughout the initial period
outliers <- y > z
# Graph the data, show the ut() cutoffs, and mark the outliers:
plot(x, y, type="l", lwd=2, col="#E00000", ylim=c(0, 20000))
lines(x, z, col="Gray")
points(x[outliers], y[outliers], pch=19)
Áp dụng cho một tập dữ liệu như đường cong màu đỏ được minh họa trong câu hỏi, nó tạo ra kết quả này:
Dữ liệu được hiển thị bằng màu đỏ, cửa sổ 30 ngày của ngưỡng trung bình + 5 * MAD màu xám và các ngoại lệ - đơn giản là các giá trị dữ liệu trên đường cong màu xám - màu đen.
(Ngưỡng chỉ có thể được tính bắt đầu ở cuối cửa sổ ban đầu. Đối với tất cả dữ liệu trong cửa sổ ban đầu này, ngưỡng đầu tiên được sử dụng: đó là lý do tại sao đường cong màu xám nằm giữa x = 0 và x = 30.)
Tác động của việc thay đổi các tham số là (a) tăng giá trị window
sẽ có xu hướng làm phẳng đường cong màu xám và (b) tăng threshold
sẽ làm tăng đường cong màu xám. Biết được điều này, người ta có thể lấy một phân đoạn dữ liệu ban đầu và nhanh chóng xác định các giá trị của các tham số tách biệt tốt nhất các đỉnh ngoài với phần còn lại của dữ liệu. Áp dụng các giá trị tham số này để kiểm tra phần còn lại của dữ liệu. Nếu một biểu đồ cho thấy phương thức đang xấu đi theo thời gian, điều đó có nghĩa là bản chất của dữ liệu đang thay đổi và các tham số có thể cần điều chỉnh lại.
Lưu ý rằng phương pháp này ít giả định về dữ liệu: chúng không phải được phân phối bình thường; họ không cần phải thể hiện bất kỳ định kỳ; họ thậm chí không phải là không tiêu cực. Tất cả những gì nó giả định là dữ liệu hành xử theo những cách tương đối hợp lý theo thời gian và các đỉnh ngoại vi cao hơn rõ rệt so với phần còn lại của dữ liệu.
Nếu bất cứ ai muốn thử nghiệm (hoặc so sánh một số giải pháp khác với giải pháp được cung cấp ở đây), đây là mã tôi đã sử dụng để tạo dữ liệu như những gì được hiển thị trong câu hỏi.
n.length <- 1150
cycle.a <- 11
cycle.b <- 365/12
amp.a <- 800
amp.b <- 8000
set.seed(17)
x <- 1:n.length
baseline <- (1/2) * amp.a * (1 + sin(x * 2*pi / cycle.a)) * rgamma(n.length, 40, scale=1/40)
peaks <- rbinom(n.length, 1, exp(2*(-1 + sin(((1 + x/2)^(1/5) / (1 + n.length/2)^(1/5))*x * 2*pi / cycle.b))*cycle.b))
y <- peaks * rgamma(n.length, 20, scale=amp.b/20) + baseline