Post

시계열 특징 및 분류 [tsfresh, Logistic Regression]

시계열 특징 및 분류 [tsfresh, Logistic Regression]

1. 시계열 데이터의 특징

1-1. 주요한 시계열 요약 통계 특징

  • 평균과 분산
  • 최댓값과 최솟값
  • 시작과 마지막 값의 차이
  • 국소적 최소와 최대의 개수
  • 시계열의 평활 정도
    • 평활 정도(Smoothness) : 무작위적 변화로 생기는 효과를 줄이는 방법 중 하나
      • ex. 주어진 시계열 자료에 평균을 취하는 것은 가장 단순한 평활법
  • 시계열의 주기성과 자기상관
    • 시계열 주기성(Time series cycle) : 시계열이 증가하고 감소하는 패턴이 반복적으로 나타나지만, 그 빈도가 고정되지 않았을 때 시계열의 주기가 있다고 말함.

1-2. tsfresh

  • 시계열의 feature를 자동으로 추출한다.
    • 기술 통계학 지표, 비선형성과 복잡도 지표, 기록 압축 지표 등등 각종 지표를 자동으로 추출
  • 논문에 따르면 63개의 시계열 특징 추출 방법론을 활용해 794개의 특징을 포착할 수 있다.
  • 현재는 1200개 이상의 특징을 지원한다.
1
2
# 1. tsfresh 라이브러리 설치
!pip install tsfresh
1
2
3
# 2. 라이브러리 버전 충돌을 피하기 위해 런타임을 재시작합니다.
import os
os.kill(os.getpid(), 9)
1
2
3
# 3. robot execution 데이터셋 다운로드 및 불러오기
from tsfresh.examples.robot_execution_failures import download_robot_execution_failures, load_robot_execution_failures
download_robot_execution_failures()
  1. 불러온 데이터 확인
  • timeseries : 데이터셋의 feature. (독립변수)
  • y : True, False로 되어있는 binary classification (종속변수)
1
2
# 4. 불러온 데이터 확인
timeseries, y = load_robot_execution_failures()
1
timeseries
idtimeF_xF_yF_zT_xT_yT_z
010-1-163-3-10
1110062-3-10
212-1-161-300
313-1-163-2-10
414-1-163-3-10
...........................
13158810-10239-21-245
13168811-11238-24-226
13178812-12323-24-245
13188813-13426-29-275
13198814-13215-25-256

1320 rows × 8 columns

1
y
1
2
3
4
5
6
7
8
9
10
11
12
1      True
2      True
3      True
4      True
5      True
      ...  
84    False
85    False
86    False
87    False
88    False
Length: 88, dtype: bool
  1. 특징 추출(feature extraction)
  • 그룹화 및 정렬 기준에 맞게 추출할 수 있다.
1
2
3
# 5. 특징 추출(feature extraction)
from tsfresh import extract_features
extracted_features = extract_features(timeseries, column_id="id", column_sort="time")
1
Feature Extraction: 100%|██████████| 528/528 [00:21<00:00, 24.03it/s]
1
extracted_features
F_x__variance_larger_than_standard_deviationF_x__has_duplicate_maxF_x__has_duplicate_minF_x__has_duplicateF_x__sum_valuesF_x__abs_energyF_x__mean_abs_changeF_x__mean_changeF_x__mean_second_derivative_centralF_x__median...T_z__fourier_entropy__bins_5T_z__fourier_entropy__bins_10T_z__fourier_entropy__bins_100T_z__permutation_entropy__dimension_3__tau_1T_z__permutation_entropy__dimension_4__tau_1T_z__permutation_entropy__dimension_5__tau_1T_z__permutation_entropy__dimension_6__tau_1T_z__permutation_entropy__dimension_7__tau_1T_z__query_similarity_count__query_None__threshold_0.0T_z__mean_n_absolute_max__number_of_maxima_7
10.00.01.01.0-14.014.00.1428570.000000-0.038462-1.0...NaNNaNNaN-0.000000-0.000000-0.000000-0.000000-0.000000NaN0.000000
20.01.01.01.0-13.025.01.0000000.000000-0.038462-1.0...1.0735431.4941752.0794420.9371561.2342681.5403061.7480671.831020NaN0.571429
30.00.01.01.0-10.012.00.7142860.000000-0.038462-1.0...1.3862941.7328682.0794421.2658571.7045512.0198152.1639562.197225NaN0.571429
40.01.01.01.0-6.016.01.214286-0.071429-0.0384620.0...1.0735431.4941752.0794421.1569881.9072842.3978952.3025852.197225NaN1.000000
50.00.00.01.0-9.017.00.928571-0.0714290.038462-1.0...0.9002561.3208882.0794421.1569881.8636802.2718692.3025852.197225NaN0.857143
..................................................................
841.01.00.01.0-1073.096833.07.142857-5.428571-0.038462-98.0...0.7356220.7356221.3862941.5857712.2538582.3978952.3025852.197225NaN24.285714
851.00.01.01.0143.01683.01.3571431.0714290.0769238.0...0.7356220.7356221.6674621.3322451.5890271.8937882.1639562.197225NaN5.571429
861.00.00.00.0961.083497.09.0714299.0714290.80769252.0...0.7356221.0735431.7328680.6870920.9830881.1595891.2275291.303092NaN9.285714
871.01.00.01.04509.01405437.012.92857112.214286-1.038462338.0...0.7356220.7356221.3862940.5359610.8369881.1595891.4978661.581094NaN40.285714
881.00.01.01.0-143.01427.00.785714-0.5000000.038462-9.0...1.2554821.4941752.0794420.8305181.2424531.4142791.6094381.831020NaN5.428571

88 rows × 4698 columns

  1. impute
  • 특징 추출된 모든 값을 동일한 열의 중앙/극단값으로 바꿉니다.
    • -inf -> min
    • +inf -> max
    • NaN -> median
  1. select_features(X, y)
  • 특징 행렬 X의 모든 특징(열)의 중요성을 확인하고 관련 특징만 포함하는 축소된 특징 행렬을 반환한다.(필터링)
1
2
3
4
5
6
7
8
from tsfresh import select_features
from tsfresh.utilities.dataframe_functions import impute

# 6. impute
impute(extracted_features)

# 7. select_features(X, y)
features_filtered = select_features(extracted_features, y)
1
2
# 8. 필터링된 값 확인
features_filtered
F_x__value_count__value_-1F_x__abs_energyF_x__root_mean_squareT_y__absolute_maximumF_x__mean_n_absolute_max__number_of_maxima_7F_x__range_count__max_1__min_-1F_y__abs_energyF_y__root_mean_squareF_y__mean_n_absolute_max__number_of_maxima_7T_y__variance...T_x__change_quantiles__f_agg_"var"__isabs_True__qh_0.2__ql_0.0F_z__change_quantiles__f_agg_"mean"__isabs_True__qh_1.0__ql_0.8T_x__quantile__q_0.1F_y__has_duplicate_maxT_y__lempel_ziv_complexity__bins_3T_y__quantile__q_0.1F_z__time_reversal_asymmetry_statistic__lag_1F_x__quantile__q_0.2F_y__quantile__q_0.7T_x__change_quantiles__f_agg_"var"__isabs_False__qh_0.2__ql_0.0
114.014.00.9660921.01.00000015.013.00.9309491.0000000.222222...0.0000000.0-3.01.00.400000-1.0-5.960000e+02-1.0-1.00.000000
27.025.01.2909945.01.57142913.076.02.2509263.0000004.222222...0.0000001.0-9.21.00.533333-3.6-6.803846e+02-1.0-1.00.000000
311.012.00.8944275.01.00000014.040.01.6329932.1428573.128889...0.0000003.0-6.60.00.533333-4.0-6.170000e+02-1.00.00.000000
45.016.01.0327966.01.28571410.060.02.0000002.4285717.128889...0.0000000.0-9.00.00.533333-4.63.426308e+03-1.01.00.000000
59.017.01.0645815.01.28571413.046.01.7511902.2857144.160000...0.0000000.0-9.60.00.466667-5.0-2.609000e+03-1.00.80.000000
..................................................................
840.096833.080.346334167.0105.2857140.042780.053.40412071.4285711563.528889...64.00000046.0203.20.00.53333336.4-7.700628e+07-105.066.864.000000
850.01683.010.59245014.013.7142860.01523.010.07637512.14285714.755556...4.6666674.5-41.60.00.4666671.0-1.050785e+045.810.613.555556
860.083497.074.608757191.098.1428570.021064.037.47354647.7142862788.595556...0.2500007.0-84.80.00.46666719.6-5.544922e+0630.438.40.250000
870.01405437.0306.097697471.0340.0000000.0308658.0143.447551157.2857146415.715556...0.00000090.5-139.20.00.466667272.6-9.881845e+07246.8154.80.000000
880.01427.09.75363227.011.4285710.0113.02.7446923.4285716.906667...4.6666670.0-24.60.00.533333-26.2-1.340477e+04-11.23.013.555556

88 rows × 671 columns

2. 시계열 데이터 분류

계열 데이터의 특징을 추출하고 시각화해보며, Logistic Regression을 사용하여 모델이 잘 학습(train)되었는지 score를 확인하자.

마지막으로 classification report를 통해 classification 평가지표를 만들어보자.

1
2
3
4
5
from tsfresh.examples.robot_execution_failures import download_robot_execution_failures, load_robot_execution_failures


download_robot_execution_failures()
timeseries, y = load_robot_execution_failures()
1
2
3
4
5
# 추가로 필요한 라이브러리 불러오기
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report

2-1. 데이터셋 가공

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def custom_classification_split(x, y, test_size=0.3):
    num_true = int(y.sum()*test_size)           # int(21 * 0.3) = 6
    num_false = int((len(y)-y.sum())*test_size) # int((88 - 21)*0.3) = 20

    id_list = y[y==False].head(num_false).index.to_list() + y[y==True].head(num_true).index.to_list()
    # y==False인것과 y==True인것의 인덱스값을 리스트로 변환하여 더해줍니다.
    # y[y==False].head(num_false).index.to_list()는 19~38까지의 값이 리스트로
    # y[y==True].head(num_true).index.to_list()는 1~6까지의 값이 리스트로 
    # id_list는 19~38 + 1~6이 더해진 리스트입니다.

    y_train = y.drop(id_list)                            # y에서 id_list를 drop합니다.  
    y_test = y.iloc[id_list].sort_index()                # 19~38, 1~6이 합쳐진 리스트를 정렬합니다.
    X_train = x[~x['id'].isin(id_list)] # 대괄호 안에 있는 timeseries의 id와 id_list가 일치하는 것만 사용하고 물결표시는 안에 조건이 포함되어 있지 않는것만 사용하는 것입니다.
    X_test = x[x['id'].isin(id_list)]   # timeseries의 id와 id_list가 일치하는 것만 사용해서 timeseries에 적용

    return X_train, y_train, X_test, y_test
1
2
3
4
5
6
7
8
9
# 커스텀한 함수를 적용한 데이터셋이 어떤 차이가 있는지 확인해봅시다.
X_train, y_train, X_test, y_test = custom_classification_split(timeseries, y)
print(X_train)
print('-'*50)
print(y_train)
print('-'*50)
print(X_test)
print('-'*50)
print(y_test)
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
      id  time  F_x  F_y  F_z  T_x  T_y  T_z
90     7     0   -3    1   53  -10   -4    0
91     7     1    0   -2   65   -4   -1    0
92     7     2   -1   -1   56   -7   -3    0
93     7     3    0   -2   60   -6    0    0
94     7     4   -1   -1   57   -7   -4    0
...   ..   ...  ...  ...  ...  ...  ...  ...
1315  88    10  -10    2   39  -21  -24    5
1316  88    11  -11    2   38  -24  -22    6
1317  88    12  -12    3   23  -24  -24    5
1318  88    13  -13    4   26  -29  -27    5
1319  88    14  -13    2   15  -25  -25    6

[930 rows x 8 columns]
--------------------------------------------------
7      True
8      True
9      True
10     True
11     True
      ...  
84    False
85    False
86    False
87    False
88    False
Length: 62, dtype: bool
--------------------------------------------------
     id  time  F_x  F_y  F_z  T_x  T_y  T_z
0     1     0   -1   -1   63   -3   -1    0
1     1     1    0    0   62   -3   -1    0
2     1     2   -1   -1   61   -3    0    0
3     1     3   -1   -1   63   -2   -1    0
4     1     4   -1   -1   63   -3   -1    0
..   ..   ...  ...  ...  ...  ...  ...  ...
565  38    10   -2   -1   58   -7   -6   -2
566  38    11   -4    0   60   -8   -9   -1
567  38    12   -3    0   59   -9   -6   -1
568  38    13   -1    1   61   -8   -4   -1
569  38    14    1    0   60   -8   -2   -1

[390 rows x 8 columns]
--------------------------------------------------
2      True
3      True
4      True
5      True
6      True
7      True
20    False
21    False
22    False
23    False
24    False
25    False
26    False
27    False
28    False
29    False
30    False
31    False
32    False
33    False
34    False
35    False
36    False
37    False
38    False
39    False
dtype: bool

2-2. 특징 추출하기

  • MinimalFCParameters : feature를 최소(minimal)로 하여 계산을 수행합니다. 데이터셋 크기가 큰 경우 모든 feature를 계산하기 전에 설정을 minimal로 변경하여 빠르게 테스트하기 위해 사용합니다.
    • train과 test 데이터셋을 minimal하게 계산한 값으로 변경해줍니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from tsfresh import extract_features
from tsfresh.feature_extraction import MinimalFCParameters

settings = MinimalFCParameters() # 계산 효율을 위해 minimal 셋팅
minimal_features_train = extract_features(
                                X_train,
                                column_id="id",
                                column_sort="time",
                                default_fc_parameters=settings # minimal 적용
                           )

minimal_features_test = extract_features(
                                X_test,
                                column_id="id",
                                column_sort="time",
                                default_fc_parameters=settings # minimal 적용
                           )
1
2
Feature Extraction: 100%|██████████| 372/372 [00:00<00:00, 2655.24it/s]
Feature Extraction: 100%|██████████| 156/156 [00:00<00:00, 2072.65it/s]

2-3. 추출된 특징 확인

1
minimal_features_train
F_x__sum_valuesF_x__medianF_x__meanF_x__lengthF_x__standard_deviationF_x__varianceF_x__root_mean_squareF_x__maximumF_x__absolute_maximumF_x__minimum...T_z__sum_valuesT_z__medianT_z__meanT_z__lengthT_z__standard_deviationT_z__varianceT_z__root_mean_squareT_z__maximumT_z__absolute_maximumT_z__minimum
7-13.0-1.0-0.86666715.00.8055360.6488891.1832160.03.0-3.0...-1.00.0-0.06666715.00.4422170.1955560.4472141.01.0-1.0
8-10.0-1.0-0.66666715.01.1352921.2888891.3165612.02.0-2.0...0.00.00.00000015.01.0327961.0666671.0327963.03.0-1.0
9-10.0-1.0-0.66666715.01.0749681.1555561.2649112.03.0-3.0...3.00.00.20000015.01.0456261.0933331.0645813.03.0-1.0
10-14.0-1.0-0.93333315.00.2494440.0622220.9660920.01.0-1.0...0.00.00.00000015.00.0000000.0000000.0000000.00.00.0
11-13.0-1.0-0.86666715.00.9568470.9155561.2909941.03.0-3.0...-3.00.0-0.20000015.00.4000000.1600000.4472140.01.0-1.0
..................................................................
84-1073.0-98.0-71.53333315.036.5857291338.51555680.346334-25.0110.0-110.0...-232.0-21.0-15.46666715.09.65999893.31555618.2354970.028.0-28.0
85143.08.09.53333315.04.61687721.31555610.59245019.019.04.0...-52.0-2.0-3.46666715.02.1561284.6488894.0824830.07.0-7.0
86961.052.064.06666715.038.2351791461.92888974.608757148.0148.021.0...-81.0-8.0-5.40000015.05.46260029.8400007.6811468.010.0-10.0
874509.0338.0300.60000015.057.7532683335.440000306.097697342.0342.0171.0...475.035.031.66666715.09.90398398.08888933.17931144.044.013.0
88-143.0-9.0-9.53333315.02.0612834.2488899.753632-6.013.0-13.0...73.05.04.86666715.00.8844330.7822224.9463796.06.03.0

62 rows × 60 columns

1
minimal_features_train.columns
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Index(['F_x__sum_values', 'F_x__median', 'F_x__mean', 'F_x__length',
       'F_x__standard_deviation', 'F_x__variance', 'F_x__root_mean_square',
       'F_x__maximum', 'F_x__absolute_maximum', 'F_x__minimum',
       'F_y__sum_values', 'F_y__median', 'F_y__mean', 'F_y__length',
       'F_y__standard_deviation', 'F_y__variance', 'F_y__root_mean_square',
       'F_y__maximum', 'F_y__absolute_maximum', 'F_y__minimum',
       'F_z__sum_values', 'F_z__median', 'F_z__mean', 'F_z__length',
       'F_z__standard_deviation', 'F_z__variance', 'F_z__root_mean_square',
       'F_z__maximum', 'F_z__absolute_maximum', 'F_z__minimum',
       'T_x__sum_values', 'T_x__median', 'T_x__mean', 'T_x__length',
       'T_x__standard_deviation', 'T_x__variance', 'T_x__root_mean_square',
       'T_x__maximum', 'T_x__absolute_maximum', 'T_x__minimum',
       'T_y__sum_values', 'T_y__median', 'T_y__mean', 'T_y__length',
       'T_y__standard_deviation', 'T_y__variance', 'T_y__root_mean_square',
       'T_y__maximum', 'T_y__absolute_maximum', 'T_y__minimum',
       'T_z__sum_values', 'T_z__median', 'T_z__mean', 'T_z__length',
       'T_z__standard_deviation', 'T_z__variance', 'T_z__root_mean_square',
       'T_z__maximum', 'T_z__absolute_maximum', 'T_z__minimum'],
      dtype='object')

2-4. 추출된 특징 시각화하기

1
2
plt.plot(minimal_features_train['F_x__sum_values'])
plt.show()

20250523_output_32_0

1
2
plt.plot(minimal_features_train['T_z__maximum'])
plt.show()

20250523_output_33_0

2-5. Logistic Regression 사용

  • 회귀분석이라는 명칭과는 다르게 분류(Classification)를 할 때도 사용할 수 있다.
  • 현재 사용중인 robot_execution_failures 데이터셋에서 y가 True와 False로 이루어져 있다.
    • 이진 분류(binary classification) 문제이며 Logistic Regression을 사용할 수 있음.
  • Logistic Regression은 어떤 범주에 속할 확률을 0(False)에서 1(True) 사이의 값으로 예측할 수 있다.
  • x가 0.5보다 높거나 같은 경우 1, x가 0.5보다 낮은 경우는 0으로 분류함.
    • 여기서 x는 독립변수인 feature라고 생각하시면 된다.
1
2
logistic = LogisticRegression() 
logistic.fit(minimal_features_train, y_train)
1
LogisticRegression()

2-6. Logistic Regression score 확인

1
logistic.score(minimal_features_test, y_test)
1
0.6923076923076923

2-7. 분류 성능 평가 지표 확인

  • Classification report는 scikit-learn에서 제공되는 기능
    • 모델 혹은 알고리즘은 score로만 결과를 신뢰할 수 없다.
      • 여기서 말하는 모델 혹은 알고리즘은 Logistic Regression
    • 모델을 거쳐 나온 결과값(output)을 분석하여 이유가 있고 설명 가능한 상태가 되어야 함.
  • Classification의 대표적인 검증 지표로 Precision, Recall, F1-score를 사용
  • 아래의 지표를 해석해보면 이진 분류이므로 True와 False 각각 정밀도(Precision), 재현율(Recall), 조화평균(F1-score)의 값을 보여줌.
  • 정확도(accuracy)는 score와 같다
  • 매크로 평균(macro avg)은 평균의 평균.
    • (각 클래스별 평균 / 클래스 = 매크로 평균)
      • 여기서 클래스란 minimal_feature_train의 feature
      • 특징 추출 후 나온 feature의 개수는 60개
  • 가중 산술 평균(weighted avg)은 자료의 평균을 구할 때 자료 값의 중요도나 영향 정도에 해당하는 가중치를 반영하여 구한 평균값
1
2
3
# y는 True, False는 Target으로도 표현할 수 있습니다. 
classification_report(y_test, logistic.predict(minimal_features_test), target_names=['true', 'false'], output_dict=True)
# y_test 내부에 있는 true, false와 일치
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{'true': {'precision': 1.0,
  'recall': 0.6,
  'f1-score': 0.7499999999999999,
  'support': 20},
 'false': {'precision': 0.42857142857142855,
  'recall': 1.0,
  'f1-score': 0.6,
  'support': 6},
 'accuracy': 0.6923076923076923,
 'macro avg': {'precision': 0.7142857142857143,
  'recall': 0.8,
  'f1-score': 0.6749999999999999,
  'support': 26},
 'weighted avg': {'precision': 0.868131868131868,
  'recall': 0.6923076923076923,
  'f1-score': 0.7153846153846153,
  'support': 26}}

전체 정확도(Accuracy):69.2% — 전체 예측 중 약 69%가 정답.

클래스별 성능:

  • true (총 20개 중)
    • 정밀도(Precision): 1.00 → 예측이 맞으면 항상 정답!
    • 재현율(Recall): 0.60 → 실제 true 중 60%만 맞춤
    • F1-score: 0.75 → 정밀도와 재현율 균형 지표
  • false (총 6개 중)

    • 정밀도: 0.43 → 예측이 자주 틀림
    • 재현율: 1.00 → 실제 false는 모두 잘 맞춤.
    • F1-score: 0.60

종합 요약:

  • 모델은 true를 잘 예측하지만, false는 자주 헷갈림
  • 정밀도는 높지만 재현율 불균형

+) 분류 모델 평가 지표 요약

지표설명
정확도 (Accuracy)전체 중에서 맞춘 비율. 데이터가 불균형할 때는 신뢰하기 어려움.
정밀도 (Precision)양성으로 예측한 것 중 실제로 양성인 비율. 거짓 양성 줄이는 데 중요.
재현율 (Recall)실제 양성 중에서 양성으로 예측한 비율. 놓치는 양성 줄이는 데 중요.
F1-score정밀도와 재현율의 조화 평균. 불균형 데이터에서 성능 평가에 적합.

본 문서는 Aiffel LMS 강의 내용을 바탕으로 개인 학습 목적으로 정리하였습니다.
상업적 이용 목적은 없으며, 원 저작권은 Aiffel에 있습니다.

This post is licensed under CC BY 4.0 by the author.