images
12/10/2020 08:16 am

Gấu mèo đi làm Data Scientist - Phần 8: Outlier - Anomaly Detection - Part 3

Tóm tắt phần trước: Gấu Mèo đang tìm Outlier theo phân phối chuẩn thì tắc tị vì dataset không phân bố theo Normal Distribution. Và nó đang tìm cách biến dataset đó thành phân phối chuẩn.

Bí quá, Gấu Mèo sort, rồi lấy 1% các giá trị thấp nhất và 1% các giá trị cao nhất để xem xét thì vẫn dùng được cho biz. 


Tuy nhiên nó không chỉ muốn dừng ở đấy, với kiểu làm fast food này thì nhiều trường hợp bị bỏ sót, quan trọng nhất là không mở rộng thành hệ thống được.


Việc khó thì có cao nhân. Gấu Mèo sau một hồi nghiên cứu mà không ăn thua thì nó chạy qua hỏi sư phụ Gấu Chó. Gấu Chó mừng thầm vì thằng đệ tự hỏi đúng chỗ mình biết:


“Nếu muốn transform thành phân phối chuẩn thì có vài cách. Con có thể log, exp hoặc dùng box-cox. Tuy nhiên bản chất mục đích của con là muốn tìm ra được hàm distribution để tìm ra ngoại lệ chứ ko phải là làm thế nào để transform sang được phân phối chuẩn. Ngoài ra có những trường hợp không thể dùng phương pháp thông qua distribution, lúc đấy có thể dựa trên một phương pháp khác là Cluster-based Local Outlier Factor (CBLOF)”


Trước hết đề tìm distribution, con hãy dùng đoạn code này để dò ra distribution nào phù hợp với dữ liệu nhất (Dữ liệu mọi người xem và load ở Part 2 nhé): 


import warnings

import numpy as np

import pandas as pd

import scipy.stats as st

import statsmodels as sm



# Create models from data

def best_fit_distribution(data, bins=200, ax=None):

    """Model data by finding best fit distribution to data"""

    # Get histogram of original data

    y, x = np.histogram(data, bins=bins, density=True)

    x = (x + np.roll(x, -1))[:-1] / 2.0


    # Distributions to check

    DISTRIBUTIONS = [        

        st.alpha,st.anglit,st.arcsine,st.beta,st.betaprime,st.bradford,st.burr,st.cauchy,st.chi,st.chi2,st.cosine,

        st.dgamma,st.dweibull,st.erlang,st.expon,st.exponnorm,st.exponweib,st.exponpow,st.f,st.fatiguelife,st.fisk,

        st.foldcauchy,st.foldnorm,st.frechet_r,st.frechet_l,st.genlogistic,st.genpareto,st.gennorm,st.genexpon,

        st.genextreme,st.gausshyper,st.gamma,st.gengamma,st.genhalflogistic,st.gilbrat,st.gompertz,st.gumbel_r,

        st.gumbel_l,st.halfcauchy,st.halflogistic,st.halfnorm,st.halfgennorm,st.hypsecant,st.invgamma,st.invgauss,

        st.invweibull,st.johnsonsb,st.johnsonsu,st.ksone,st.kstwobign,st.laplace,st.levy,st.levy_l,st.levy_stable,

        st.logistic,st.loggamma,st.loglaplace,st.lognorm,st.lomax,st.maxwell,st.mielke,st.nakagami,st.ncx2,st.ncf,

        st.nct,st.norm,st.pareto,st.pearson3,st.powerlaw,st.powerlognorm,st.powernorm,st.rdist,st.reciprocal,

        st.rayleigh,st.rice,st.recipinvgauss,st.semicircular,st.t,st.triang,st.truncexpon,st.truncnorm,st.tukeylambda,

        st.uniform,st.vonmises,st.vonmises_line,st.wald,st.weibull_min,st.weibull_max,st.wrapcauchy

    ]


    # Best holders

    best_distribution = st.norm

    best_params = (0.0, 1.0)

    best_sse = np.inf


    # Estimate distribution parameters from data

    for distribution in DISTRIBUTIONS:


        # Try to fit the distribution

        try:

            # Ignore warnings from data that can't be fit

            with warnings.catch_warnings():

                warnings.filterwarnings('ignore')


                # fit dist to data

                params = distribution.fit(data)


                # Separate parts of parameters

                arg = params[:-2]

                loc = params[-2]

                scale = params[-1]


                # Calculate fitted PDF and error with fit in distribution

                pdf = distribution.pdf(x, loc=loc, scale=scale, *arg)

                sse = np.sum(np.power(y - pdf, 2.0))


                # identify if this distribution is better

                if best_sse > sse > 0:

                    best_distribution = distribution

                    best_params = params

                    best_sse = sse


        except Exception:

            pass


    return (best_distribution.name, best_params)


# Find best fit distribution

best_fit_name, best_fit_params = best_fit_distribution(data, 200)

best_dist = getattr(st, best_fit_name)

  

Kết quả nhận được như hình phía dưới:


Giải thích một chút về đoạn code trên đã làm nhé:


- Đầu tiên Gấu Mèo lấy ra rất nhiều các loại distribution, thực tế các bạn chỉ cần lấy vài loại thôi, chạy cho nhanh. Các loại phổ biến như norm, lognorm, exponnorm… đều có trong đấy cả (Thế nên khi làm thế này bạn cũng đã bao gồm được các cách chuyển thành normal distribution bằng log, exp..). Cụ thể lý thuyết các loại phân phối bạn có thể xem ở https://docs.scipy.org/doc/scipy/reference/tutorial/stats/continuous.html

- Sau đấy lấy từng loại distribution và fit vào data set.

- Bước tiếp theo tính pdf, từ đấy tính được error with fit in distribution, và chọn ra loại có error thấp nhất. Vì dữ liệu là một biến dạng số liên tục, nên khi tính sẽ chia ra từng khoảng (dựa trên số bins truyền vào). Như trong đoạn code thì chia ra 200 khoảng, sau đấy tính chênh lệch xác suất của thực tế và distribution giả thuyết (tích phân hàm pdf) để ra được error


Kết quả với dataset trong ví dụ chúng ta chọn được distribution johnsonsb


Sau khi đã tìm được distribution rồi làm thế nào để tìm được các outlier values. Lúc đấy hãy dùng hàm ppf - percent point function (Hàm ngược của cdf).

Chẳng hạn:  distribution.ppf(0.01) và disrtibution.ppf(0.99) 


# Get sane start and end points of distribution

    start = dist.ppf(0.01, *arg, loc=loc, scale=scale) if arg else dist.ppf(0.01, loc=loc, scale=scale)

    end = dist.ppf(0.99, *arg, loc=loc, scale=scale) if arg else dist.ppf(0.99, loc=loc, scale=scale)


sẽ cho bạn giá trị thấp nhất và cao nhất trong khoảng bình thường (Ngoài khoảng đấy sẽ là bất thường).


Đoạn code này khá dài, nhưng sẽ có thể dùng đi dùng lại rất nhiều lần, nên bạn cố gắng hiểu và chạy thử. Như mọi khi nếu có thắc mắc hay gặp vấn đề về code nhớ comment hoặc inbox cho Gấu Mèo nhé.


Yeah, vậy là đã có thể tìm được các điểm outlier của một trường dữ liệu dựa trên lý thuyết về distribution. Bạn có thể mở rộng bằng cách tính thêm tính bất thường của sự biến thiên một trường (bất thường về tốc độ)... 


Từ đấy bạn có thể dùng nó để phát hiện gian lận thẻ tín dụng, một mặt hàng đang sốt đặc biệt, hay thậm chí là hiểu hiện khác thường trong nhịp tim của “crush”. 


Bật mí thêm một chút là Dải bollinger band mà dân chứng khoán hay dùng cũng dựa trên lý thuyết này đấy bạn. 


Gấu Mèo thoả mãn với cái kết quả mà nó đạt được, tuy nhiên nó chợt nhớ lúc nãy sư phụ nó có nhắc tới Cluster-based Local Outlier Factor (CBLOF). Thế là lại một đêm mất ngủ...


Mời các bạn đọc lại bài Gấu mèo đi làm Data Scientist - Phần 8: Outlier - Anomaly Detection - Part 2.


- Tech Zone -

Thư giãn chút nào!!!

Bài viết liên quan