[TS] μ‹œκ³„μ—΄ 이상탐지 μ‹œκ°ν™”

Posted by Euisuk's Dev Log on November 13, 2023

[TS] μ‹œκ³„μ—΄ 이상탐지 μ‹œκ°ν™”

원본 κ²Œμ‹œκΈ€: https://velog.io/@euisuk-chung/TS-μ‹œκ³„μ—΄-이상탐지-μ‹œκ°ν™”

였늘의 μ½”λ“œ

μ‹œκ³„μ—΄ μ „λ¬Έκ°€λ‘œμ„œ, μ‹œκ³„μ—΄ λ°μ΄ν„°λΆ„μ„κ°€λ‘œμ„œ λ‹€λ³€λŸ‰ μ‹œκ³„μ—΄ 데이터λ₯Ό μ‹œκ°ν™”ν•˜κ³  이λ₯Ό μ‚΄νŽ΄λ³΄λŠ” μž‘μ—…μ€ 맀우 μ€‘μš”ν•©λ‹ˆλ‹€. 이에 μ˜€λŠ˜μ€ μ œκ°€ 주둜 연ꡬ/업무에 μ‚¬μš©ν•˜λŠ” 이상탐지 μ‹œκ°ν™” μ½”λ“œλ₯Ό μ •λ¦¬ν•˜κ³ μž ν•©λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np

def plot_mul_ad(df, df_w_result, model_name='IForest'):
    # Define a color palette with enough colors
    colors = plt.cm.viridis(np.linspace(0, 1, df.shape[1]))

    # Create a figure with GridSpec
    fig = plt.figure(figsize=(12, 2 * df.shape[1]))  # Adjust the figure size
    gs = gridspec.GridSpec(df.shape[1], 1, fig, 0, 0, 1, 1, hspace=0.5)

    for i, (col, color) in enumerate(zip(df.columns, colors)):
        ax = fig.add_subplot(gs[i, 0])

        ax.plot(df.index.values, df[col].values, label=col, color=color)

        # Mark anomalies with red dots
        anomalies = df[df_w_result[f'{model_name}'] == -1]
        ax.scatter(anomalies.index, anomalies[col], color='red', label='Anomaly', zorder=5)

        ax.set_ylabel(col)
        ax.legend()

    # Set common labels
    plt.xlabel('Time (Index)')
    plt.xticks(rotation=45)
    fig.suptitle('Feature Values Over Time With Anomalies (Unique Colors)', fontsize=16, y=1.05)

    plt.show()

μ£Όμš”κΈ°λŠ₯1. cm.viridis

matplotlibμ—μ„œ plt.cm.viridis(np.linspace(0, 1, df.shape[1])) μ½”λ“œλŠ” viridis μ»¬λŸ¬λ§΅μ„ μ‚¬μš©ν•˜μ—¬ 데이터 ν”„λ ˆμž„(df)의 μ—΄ μˆ˜μ— 따라 색상 배열을 μƒμ„±ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€. 이 μ½”λ“œλ₯Ό λΆ„ν•΄ν•˜μ—¬ 각 λΆ€λΆ„μ˜ 의미λ₯Ό 이해해 λ³΄κ² μŠ΅λ‹ˆλ‹€.

1. plt.cm.viridis

  • plt.cm은 matplotlib.pyplot의 컬러맡 λͺ¨λ“ˆμ„ μ˜λ―Έν•©λ‹ˆλ‹€. μ»¬λŸ¬λ§΅μ€ 연속적인 μƒ‰μƒμ˜ λ²”μœ„λ₯Ό μ œκ³΅ν•˜λ©°, λ‹€μ–‘ν•œ 데이터λ₯Ό μ‹œκ°ν™”ν•  λ•Œ μœ μš©ν•˜κ²Œ μ‚¬μš©λ©λ‹ˆλ‹€.
  • viridisλŠ” matplotlibμ—μ„œ μ œκ³΅ν•˜λŠ” κΈ°λ³Έ 컬러맡 쀑 ν•˜λ‚˜μž…λ‹ˆλ‹€. 이 μ»¬λŸ¬λ§΅μ€ 밝은 λ…Έλž€μƒ‰μ—μ„œ μ‹œμž‘ν•˜μ—¬, 밝은 녹색을 거쳐 μ–΄λ‘μš΄ νŒŒλž€μƒ‰μœΌλ‘œ λλ‚˜λŠ” 색상 λ²”μœ„λ₯Ό κ°€μ§‘λ‹ˆλ‹€.
  • viridis μ»¬λŸ¬λ§΅μ€ 높은 가독성과 색맹 접근성을 μœ„ν•΄ μ„€κ³„λ˜μ—ˆμœΌλ©°, λ°μ΄ν„°μ˜ μ„Έλ°€ν•œ λΆ€λΆ„κΉŒμ§€ κ΅¬λ³„ν•˜κΈ° μ‰½κ²Œ λ§Œλ“€μ–΄μ Έ μžˆμŠ΅λ‹ˆλ‹€.

2. np.linspace(0, 1, df.shape[1])

  • np.linspaceλŠ” NumPy 라이브러리의 ν•¨μˆ˜λ‘œ, μ§€μ •λœ λ²”μœ„ λ‚΄μ—μ„œ κ· λ“±ν•œ κ°„κ²©μ˜ μˆ«μžλ“€μ„ μƒμ„±ν•©λ‹ˆλ‹€.
  • 이 경우 np.linspace(0, 1, df.shape[1])λŠ” 0κ³Ό 1 μ‚¬μ΄μ˜ 값을 df.shape[1] (데이터 ν”„λ ˆμž„μ˜ μ—΄ 수)만큼 κ· λ“±ν•˜κ²Œ λΆ„ν• ν•©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ 각 열에 λŒ€ν•΄ κ³ μœ ν•œ 색상을 ν• λ‹Ήν•  수 μžˆλŠ” κ°’μ˜ 배열이 μƒμ„±λ©λ‹ˆλ‹€.

κ²°ν•©λœ μ‚¬μš©

이 μ½”λ“œμ˜ κ²°ν•©λœ μ‚¬μš©μ€ 데이터 ν”„λ ˆμž„μ˜ 각 열에 λŒ€ν•΄ κ³ μœ ν•˜κ³  ꡬ별 κ°€λŠ₯ν•œ 색상을 ν• λ‹Ήν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€. viridis μ»¬λŸ¬λ§΅μ— np.linspaceλ₯Ό μ μš©ν•¨μœΌλ‘œμ¨, 데이터 ν”„λ ˆμž„μ˜ 각 열에 ν•΄λ‹Ήν•˜λŠ” κ³ μœ ν•œ 색상을 얻을 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” λ³΅μž‘ν•œ 데이터 μ„ΈνŠΈλ₯Ό μ‹œκ°ν™”ν•  λ•Œ μœ μš©ν•˜λ©°, 각 μ—΄μ΄λ‚˜ 데이터 μ‹œλ¦¬μ¦ˆλ₯Ό μ‰½κ²Œ ꡬ별할 수 μžˆλ„λ‘ λ„μ™€μ€λ‹ˆλ‹€.

μ£Όμš”κΈ°λŠ₯2. GridSpec

GridSpec은 matplotlibμ—μ„œ κ³ κΈ‰ κ·Έλ¦¬λ“œ λ ˆμ΄μ•„μ›ƒμ„ λ§Œλ“œλŠ” 데 μ‚¬μš©λ˜λŠ” ν΄λž˜μŠ€μž…λ‹ˆλ‹€. 이 ν΄λž˜μŠ€λŠ” λ³΅μž‘ν•œ 차트 λ ˆμ΄μ•„μ›ƒμ„ μƒμ„±ν•˜κ³  κ΄€λ¦¬ν•˜λŠ” 데 μœ μš©ν•˜λ©°, 일반적인 μ„œλΈŒν”Œλ‘― λ ˆμ΄μ•„μ›ƒλ³΄λ‹€ 더 λ§Žμ€ μœ μ—°μ„±κ³Ό μ„Έλ°€ν•œ μ œμ–΄λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.

GridSpec의 μ£Όμš” κΈ°λŠ₯κ³Ό νŠΉμ§•

  1. μ„Έλ°€ν•œ λ ˆμ΄μ•„μ›ƒ μ œμ–΄: GridSpec을 μ‚¬μš©ν•˜λ©΄, 각 μ„œλΈŒν”Œλ‘―μ˜ 크기와 μœ„μΉ˜λ₯Ό ν–‰κ³Ό μ—΄ λ‹¨μœ„λ‘œ μ •ν™•ν•˜κ²Œ μ§€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” ν‘œμ€€ subplots ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λŠ” 것보닀 더 μ„Έλ°€ν•œ μ œμ–΄λ₯Ό κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€.
  2. 비균일 μ„œλΈŒν”Œλ‘― 크기: μ„œλΈŒν”Œλ‘―λ“€μ΄ λͺ¨λ‘ λ™μΌν•œ 크기λ₯Ό κ°€μ§ˆ ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, ν•œ 행에 큰 μ„œλΈŒν”Œλ‘― ν•˜λ‚˜μ™€ μž‘μ€ μ„œλΈŒν”Œλ‘― 두 개λ₯Ό λ°°μΉ˜ν•˜λŠ” 것과 같이, λ‹€μ–‘ν•œ 크기와 λΉ„μœ¨μ˜ μ„œλΈŒν”Œλ‘―μ„ 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.
  3. ν–‰κ³Ό μ—΄μ˜ μ‘°μ •: GridSpec을 μ‚¬μš©ν•˜λ©΄, ν–‰κ³Ό μ—΄μ˜ 수, μ„œλΈŒν”Œλ‘― κ°„μ˜ 간격(hspace, wspace), 그리고 ν”Œλ‘―μ˜ μƒλŒ€μ μΈ λ„ˆλΉ„μ™€ 높이λ₯Ό μ‘°μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

GridSpec μ‚¬μš© 방법

GridSpec은 일반적으둜 λ‹€μŒκ³Ό 같은 λ‹¨κ³„λ‘œ μ‚¬μš©λ©λ‹ˆλ‹€:

  1. GridSpec 객체 생성: λ¨Όμ € matplotlib.gridspec.GridSpec ν΄λž˜μŠ€λ‘œλΆ€ν„° 객체λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. 이 λ•Œ ν–‰κ³Ό μ—΄μ˜ 수λ₯Ό μ§€μ •ν•©λ‹ˆλ‹€.

    1
    2
    
    import matplotlib.gridspec as gridspec
    gs = gridspec.GridSpec(nrows, ncols)
    
  2. Figure 객체 생성: matplotlib의 figure 객체λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. 이 κ°μ²΄λŠ” λͺ¨λ“  μ„œλΈŒν”Œλ‘―μ„ ν¬ν•¨ν•©λ‹ˆλ‹€.

    1
    
    fig = plt.figure()
    
  3. μ„œλΈŒν”Œλ‘― μΆ”κ°€: fig.add_subplot을 μ‚¬μš©ν•˜μ—¬ 각 μ„œλΈŒν”Œλ‘―μ„ GridSpec에 따라 μΆ”κ°€ν•©λ‹ˆλ‹€. μ—¬κΈ°μ„œ μ„œλΈŒν”Œλ‘―μ˜ μœ„μΉ˜λŠ” GridSpec 객체의 μŠ¬λΌμ΄μ‹±μ„ μ‚¬μš©ν•˜μ—¬ μ§€μ •ν•©λ‹ˆλ‹€.

    1
    2
    
    ax1 = fig.add_subplot(gs[0, 0]) # 첫 번째 ν–‰, 첫 번째 μ—΄
    ax2 = fig.add_subplot(gs[1, :]) # 두 번째 ν–‰, λͺ¨λ“  μ—΄
    
  4. μ„œλΈŒν”Œλ‘― μ»€μŠ€ν„°λ§ˆμ΄μ§•: 이제 각 μ„œλΈŒν”Œλ‘―(ax1, ax2, …)에 λŒ€ν•΄ ν•„μš”ν•œ κ·Έλž˜ν”½ μž‘μ—…(ν”Œλ‘―, λ ˆμ΄λΈ” μΆ”κ°€ λ“±)을 μ§„ν–‰ν•©λ‹ˆλ‹€.
  5. λ Œλ”λ§ 및 ν‘œμ‹œ: λ§ˆμ§€λ§‰μœΌλ‘œ plt.show()λ₯Ό ν˜ΈμΆœν•˜μ—¬ μ™„μ„±λœ 그림을 ν‘œμ‹œν•©λ‹ˆλ‹€.

GridSpec은 λ³΅μž‘ν•œ λ ˆμ΄μ•„μ›ƒμ„ ν•„μš”λ‘œ ν•˜λŠ” κ³ κΈ‰ κ·Έλž˜ν”½ μž‘μ—…μ— 맀우 μœ μš©ν•˜λ©°, matplotlib의 κ°•λ ₯ν•œ μ‹œκ°ν™” κΈ°λŠ₯ 쀑 ν•˜λ‚˜μž…λ‹ˆλ‹€.

μ°Έκ³ 

πŸ₯ 제λͺ©μ΄ κ·Έλž˜ν”„λ₯Ό μΉ¨λ²”ν–ˆλ‹€κ³ μš”? λ‹€μŒκ³Ό 같이 ν•΄λ³΄μ„Έμš”.

제λͺ©μ΄ κ·Έλž˜ν”„μ— μΉ¨λ²”ν•˜λŠ” λ¬Έμ œλŠ” matplotlibμ—μ„œ μ’…μ’… λ°œμƒν•˜λŠ” λ¬Έμ œμž…λ‹ˆλ‹€. 이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ λͺ‡ κ°€μ§€ μ ‘κ·Ό 방법을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

  1. suptitle의 y λ§€κ°œλ³€μˆ˜ μ‘°μ •: fig.suptitle λ©”μ†Œλ“œμ—λŠ” 전체 κ·Έλ¦Ό 제λͺ©μ˜ μœ„μΉ˜λ₯Ό μ‘°μ •ν•˜λŠ” y λ§€κ°œλ³€μˆ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€. 이 λ§€κ°œλ³€μˆ˜μ˜ 값을 μ¦κ°€μ‹œμΌœ 제λͺ©μ„ 높이 λ°°μΉ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    1
    
    fig.suptitle('Feature Values Over Time With Anomalies (Unique Colors)', fontsize=16, y=1.05)
    
  2. μ„œλΈŒν”Œλ‘―κ³Όμ˜ μ—¬λ°± μ‘°μ •: subplots_adjust λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μ„œλΈŒν”Œλ‘―κ³Όμ˜ 상단 여백을 μ‘°μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό 톡해 제λͺ©κ³Ό μ„œλΈŒν”Œλ‘― μ‚¬μ΄μ˜ 곡간을 확보할 수 μžˆμŠ΅λ‹ˆλ‹€.

    1
    
    plt.subplots_adjust(top=0.85)
    
  3. tight_layout의 λ§€κ°œλ³€μˆ˜ μ‘°μ •: tight_layout λ©”μ†Œλ“œλŠ” μ„œλΈŒν”Œλ‘―μ˜ λ ˆμ΄μ•„μ›ƒμ„ μžλ™μœΌλ‘œ μ‘°μ •ν•˜μ§€λ§Œ, λ•Œλ•Œλ‘œ 이둜 인해 제λͺ©μ΄ μ„œλΈŒν”Œλ‘―κ³Ό κ²ΉμΉ  수 μžˆμŠ΅λ‹ˆλ‹€. pad λ§€κ°œλ³€μˆ˜λ₯Ό μ‘°μ •ν•˜μ—¬ 이 문제λ₯Ό ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    1
    
    plt.tight_layout(pad=3)
    
  4. Figure 크기 μ‘°μ •: Figure의 크기λ₯Ό λŠ˜λ €μ„œ μ„œλΈŒν”Œλ‘―κ³Ό 제λͺ© κ°„μ˜ 곡간을 확보할 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” figure ν•¨μˆ˜μ—μ„œ figsize λ§€κ°œλ³€μˆ˜λ₯Ό μ‘°μ •ν•¨μœΌλ‘œμ¨ κ°€λŠ₯ν•©λ‹ˆλ‹€.

    1
    
    fig = plt.figure(figsize=(12, 24))  # λ„ˆλΉ„μ™€ 높이λ₯Ό 적절히 μ‘°μ •
    

μ΄λŸ¬ν•œ 방법듀을 μ‘°ν•©ν•˜μ—¬ μ‚¬μš©ν•˜λ©΄, 제λͺ©μ΄ κ·Έλž˜ν”„μ— μΉ¨λ²”ν•˜λŠ” 문제λ₯Ό ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜ν”„μ˜ λ ˆμ΄μ•„μ›ƒκ³Ό μ„œλΈŒν”Œλ‘―μ˜ μˆ˜μ— 따라 μ μ ˆν•œ 방법을 μ„ νƒν•˜κ³  μ‘°μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€.



-->