[TS] 시계열 이상탐지 시각화

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

오늘의 코드

시계열 전문가로서, 시계열 데이터분석가로서 다변량 시계열 데이터를 시각화하고 이를 살펴보는 작업은 매우 중요합니다. 이에 오늘은 제가 주로 연구/업무에 사용하는 이상탐지 시각화 코드를 정리하고자 합니다.

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))  # 너비와 높이를 적절히 조정
    

이러한 방법들을 조합하여 사용하면, 제목이 그래프에 침범하는 문제를 해결할 수 있습니다. 그래프의 레이아웃과 서브플롯의 수에 따라 적절한 방법을 선택하고 조정해야 합니다.