[Project] Landing Delay Prediction Machine Learning Model

스크린샷 2021-09-02 04 17 27

Porject 개요

  • 직접 선택한 데이터셋을 사용해서 만든 머신러닝 예측 모델을 통한 성능 및 인사이트를 도출/공유하는 것이 목표
  • 데이터셋 전처리/EDA부터 모델을 해석하는 과정을 colab을 사용하여 작성하고, 해당 내용을 기반으로 설명하는 영상을 작성
  • 발표를 듣는 사람은 비데이터 직군

절차

  1. 데이터 선정 이유 및 문제 정의
    • 해당 데이터를 선택한 이유
    • 어떤 유형의 문제로 접근
  2. 데이터를 이용한 가설 및 평가지표, 베이스라인 선택
    • 데이터를 통해서 무엇을 해볼 수 있을지 가설을 세운다.(가설은 쓸모 있어야 함)
    • 해당 특성을 target으로 지정한 이유
    • 해당 베이스라인 모델과 평가지표를 선택한 이유
  3. EDA와 데이터 전처리
    • EDA
    • Feature Engineering
    • 데이터 정규화
    • 노이즈 제거
    • 결측치 제거 혹은 대체
    • 데이터 밸런스
    • 그 외
    • 다음 질문에 대답

      Data Leakage 여부, 방지한 방법
      만들고자 하는 모델의 유용성, 한계

  4. 머신러닝 방식 적용 및 교차검증
    • Tree-Based / Ensemble 모델 학습(다양하게 시도)
    • 평가지표 계산 후 베이스라인과 비교
    • 교차검증을 통해 일반화될 가능성 확인
    • 모델 성능 개선하기 위한 다양한 방법 적용
    • 최소 2개 이상의 모델을 만들어 validation 점수 보고
    • 최종 모델의 test 점수 보고
    • 다음 질문에 대답

      베이스라인보다 잘 나왔는지, 그렇지 않다면 그 이유는 무엇일지
      모델 성능 개선을 위해 어떤 방법을 적용한지, 그 방법을 선택한 이유는 무엇일지
      최종모델에 관한 설명

  5. 머신러닝 모델 해석
    • PDP, SHAP 활용 비전문가라도 조금 더 쉽게 이해하고 접근할 수 있도록 최종모델 설명
    • 다음 질문에 대답

      모델이 관측치를 예측하기 위해 어떤 특성을 활용했는지
      어떤 특성이 있다면 모델의 예측에 도움될 지, 해당 특성은 어떻게 구할 수 있을지

계획

  1. 전체적인 모델링
  2. ipynb 정리
  3. Keynote 작성
  4. 대본 작성
  5. 촬영

Landing Delay Prediction Machine Learning Model

  • 항공교통 수요가 지속적으로 증가함에 따라 항공기 지연으로 인한 이용자들의 불편과 피해가 늘어나고 있다.
  • 지연 발생 시 공항, 항공사, 항공교통이용자 모두에게 시간적·금전적 손해가 발생하며 공항 운영에 있어 상당한 피해를 입게 된다.
  • 지연 발생을 예측할 수 있다면 공항 및 항공사 관계자가 사전에 공항운영에 대한 적절한 조치를 취할 수 있어 소비자가 입을 추가적인 피해에 대비할 수 있다.
  • 다양한 사유를 통해 정상착륙, 지연으로의 분류 문제로 예측하고자 한다.
  • 이를 통하여 소비자의 편익이 증진될 뿐 아니라, 항공사와 공항의 효율성과 비용절감에도 기여할 수 있을 것으로 기대한다.

Data Collection

  • 해결하고자 하는 문제 : 항공기 착륙 지연 예측
  • 답을 얻기 위한 데이터 : 캐글의 ‘2015 Flight Delays and Cancellations’ 데이터
  • 선정이유
    • 항공 승무원이었던 경력을 살려 깊게 파고들 수 있는 도메인이기에 골랐다.
    • 사용할 타겟 특성은 result으로 15분 이상 지연되었는지를 확인할 수 있는 binary값이다.
    • 전체 데이터로 실험해보고 싶지만, Cost의 한계로 1월의 Small Data로 진행해보고자 한다.
    • 풀고자 하는 문제는 분류문제이며 여러가지 상황에 따라 항공기 착륙이 지연될지, 지연되지 않을지를 예측하는 모델링을 할 것이다.
    • 데이터에서 도착과 관련된 정보를 모두 제거하여 항공기가 Take-off함과 동시에 지연을 예측하는 모델링을 할 것이다.
1
2
3
4
5
6
train = pd.read_csv('/content/drive/MyDrive/flights.csv')
airlines = pd.read_csv('/content/drive/MyDrive/airlines.csv')

# Cost의 한계로 10만개의 data로 진행
train = train[0:100000]
train

스크린샷 2021-08-31 20 33 24

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
# 컬럼 확인
train.columns
'''
Index(['YEAR', 'MONTH', 'DAY', 'DAY_OF_WEEK', 'AIRLINE', 'FLIGHT_NUMBER',
       'TAIL_NUMBER', 'ORIGIN_AIRPORT', 'DESTINATION_AIRPORT',
       'SCHEDULED_DEPARTURE', 'DEPARTURE_TIME', 'DEPARTURE_DELAY', 'TAXI_OUT',
       'WHEELS_OFF', 'SCHEDULED_TIME', 'ELAPSED_TIME', 'AIR_TIME', 'DISTANCE',
       'WHEELS_ON', 'TAXI_IN', 'SCHEDULED_ARRIVAL', 'ARRIVAL_TIME',
       'ARRIVAL_DELAY', 'DIVERTED', 'CANCELLED', 'CANCELLATION_REASON',
       'AIR_SYSTEM_DELAY', 'SECURITY_DELAY', 'AIRLINE_DELAY',
       'LATE_AIRCRAFT_DELAY', 'WEATHER_DELAY'],
      dtype='object')

ㅁ데이터 컬럼 설명
    YEAR                        
    MONTH                       
    DAY                         
    DAY_OF_WEEK                 
    AIRLINE                     항공사
    FLIGHT_NUMBER               항공편
    TAIL_NUMBER                 항공기
    ORIGIN_AIRPORT              출발 공항
    DESTINATION_AIRPORT         목적지 공항
    SCHEDULED_DEPARTURE         출발 예정시간
    DEPARTURE_TIME              출발 시간
    DEPARTURE_DELAY             총 출발 지연
    TAXI_OUT                    게이트에서 출발할 때까지의 경과 시간
    WHEELS_OFF                  항공기의 바퀴가 지면을 떠나는 시점
    SCHEDULED_TIME              비행 계획 시간
    ELAPSED_TIME                경과 시간 = AIR_TIME + TAXI_IN + TAXI_OUT
    AIR_TIME                    WHEELS_OFF과 WHEELS_ON 사이의 시간
    DISTANCE                    두 공항 간의 거리
    WHEELS_ON                   항공기 바퀴가 지면에 닿는 시점
    TAXI_IN                     목적지 공항에 게이트 도착까지 경과된 시간
    SCHEDULED_ARRIVAL           예정 도착 시간
    ARRIVAL_TIME                도착 시간
    ARRIVAL_DELAY               지연 시간
    DIVERTED                    지연
    CANCELLED                   취소
    CANCELLATION_REASON         취소 사유
    AIR_SYSTEM_DELAY            에어 시스템
    SECURITY_DELAY              보안
    AIRLINE_DELAY               항공사
    LATE_AIRCRAFT_DELAY         항공기
    WEATHER_DELAY               날씨
'''

가설 및 평가지표, Baseline

  • 가설
    1. 출발 예정시간보다 출발에 지연된 시간이 클 수록 착륙 지연 확률은 늘어날 것이다.
    2. 지연이 잦은 항공사가 있으므로 지연 확률을 줄이기 위한 고려사항이 된다.
    3. 공항의 복잡도 고려 착륙지연이 잦은 출발 공항일 수록 도착 공항으로서의 지연도 잦다.
  • Target 특성으로는 15분 이상 지연 됐을 지를 표시하는 새로운 column을 생성했다.
  • Baseline Model로는 초기 최빈값 정확도 0.65에서 RandomForest의 AUC Score로 변경하였다.

EDA

  • 원하는 모델링을 위해 Feature Engineering 바로 진행
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
def engineering(df):
    # 도착 지연을 예측해야 하므로 도착정보에 관한 컬럼과 필요없는 컬럼은 제거한다.
    df = df[['AIRLINE', 'TAIL_NUMBER', 'ORIGIN_AIRPORT', 'DESTINATION_AIRPORT',
        'SCHEDULED_DEPARTURE', 'DEPARTURE_TIME', 'DEPARTURE_DELAY', 'TAXI_OUT',
        'WHEELS_OFF', 'SCHEDULED_TIME', 'DISTANCE',
        'SCHEDULED_ARRIVAL', 'ARRIVAL_DELAY']]
    # 15분 이상 지연되었다는 것을 표시하는 컬럼을 새로 만든다.
    result=[]

    for row in df['ARRIVAL_DELAY']:
        if row > 15:
            result.append(1)
        else:
            result.append(0)  

    df['result'] = result
    
    # 분류 컬럼을 만들었으니 예측을 위해 기존 컬럼 삭제
    df = df.drop(['ARRIVAL_DELAY'], axis = 1)

    # 결측치 제거
    df = df.dropna()
    return df

train = engineering(train)



# 결측치 확인
train.isnull().sum()
'''
AIRLINE                   0
TAIL_NUMBER             167
ORIGIN_AIRPORT            0
DESTINATION_AIRPORT       0
SCHEDULED_DEPARTURE       0
DEPARTURE_TIME         2298
DEPARTURE_DELAY        2298
TAXI_OUT               2371
WHEELS_OFF             2371
SCHEDULED_TIME            0
DISTANCE                  0
SCHEDULED_ARRIVAL         0
result                    0
dtype: int64
'''
  • 현재도 임의로 10만개로 줄여서 데이터를 사용중이기 때문에 3% 비율만 차지하기도 하고, 정확한 모델링을 위해서 결측치는 모두 제거한다.
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
71
72
73
74
75
76
77
78
79
80
81
82
83
train.dtypes
'''
AIRLINE                 object
TAIL_NUMBER             object
ORIGIN_AIRPORT          object
DESTINATION_AIRPORT     object
SCHEDULED_DEPARTURE      int64
DEPARTURE_TIME         float64
DEPARTURE_DELAY        float64
TAXI_OUT               float64
WHEELS_OFF             float64
SCHEDULED_TIME         float64
DISTANCE                 int64
SCHEDULED_ARRIVAL        int64
result                   int64
dtype: object
'''


# object에 대해범주 확인
unicol = ['AIRLINE', 'TAIL_NUMBER', 'ORIGIN_AIRPORT', 'DESTINATION_AIRPORT']
for i in unicol:
    print(i, train[i].unique())
'''
AIRLINE ['AS' 'AA' 'US' 'DL' 'NK' 'UA' 'HA' 'B6' 'OO' 'EV' 'F9' 'WN' 'MQ' 'VX']
TAIL_NUMBER ['N407AS' 'N3KUAA' 'N171US' ... 'N29907' 'N66051' 'N808NW']
ORIGIN_AIRPORT ['ANC' 'LAX' 'SFO' 'SEA' 'LAS' 'DEN' 'SLC' 'PDX' 'FAI' 'MSP' 'PHX' 'SJU'
 'PBG' 'IAG' 'PSE' 'BQN' 'ORD' 'GEG' 'HNL' 'ONT' 'MCO' 'BOS' 'HIB' 'ABR'
 'DFW' 'MKE' 'IAH' 'BNA' 'BRO' 'VPS' 'BOI' 'BJI' 'PHL' 'SBN' 'EUG' 'IAD'
 'BUF' 'PWM' 'JFK' 'CRP' 'PIA' 'FAT' 'SMF' 'AUS' 'MCI' 'ATL' 'JAX' 'MFR'
 'IDA' 'MSN' 'DCA' 'SAT' 'CHS' 'SBA' 'IND' 'CLE' 'GSP' 'BDL' 'RIC' 'BFL'
 'OMA' 'RDM' 'FLL' 'CID' 'TPA' 'SYR' 'ROC' 'TYR' 'LAN' 'GSO' 'EWR' 'PBI'
 'RSW' 'OAK' 'PVD' 'RNO' 'PIT' 'ABQ' 'MIA' 'BWI' 'TUL' 'LGA' 'LIT' 'MSY'
 'OKC' 'ATW' 'PNS' 'MEM' 'TYS' 'MHT' 'SAV' 'CLT' 'GRB' 'ABE' 'JAN' 'OAJ'
 'FAR' 'ERI' 'LEX' 'CWA' 'TTN' 'RDU' 'CVG' 'BHM' 'ACY' 'DTW' 'RAP' 'TUS'
 'EAU' 'DLH' 'FSD' 'INL' 'SPI' 'CLD' 'COD' 'CMH' 'PSC' 'CPR' 'ACV' 'DAL'
 'PAH' 'MRY' 'ESC' 'ISN' 'PSP' 'CAE' 'STL' 'BTV' 'MTJ' 'GCC' 'OGG' 'SJC'
 'GUC' 'ORF' 'MOT' 'MLU' 'KOA' 'HOU' 'MOB' 'SAN' 'LAW' 'PIB' 'MGM' 'SBP'
 'COS' 'LAR' 'DRO' 'BIS' 'ITO' 'BTR' 'HLN' 'BZN' 'MDW' 'MDT' 'SCE' 'LIH'
 'TWF' 'BPT' 'GPT' 'STC' 'HPN' 'MLB' 'PLN' 'CIU' 'CAK' 'DSM' 'BLI' 'SHV'
 'SNA' 'ALB' 'LNK' 'CMI' 'GTF' 'EKO' 'LGB' 'AVL' 'HSV' 'XNA' 'SUX' 'HYS'
 'MFE' 'ISP' 'BUR' 'DAB' 'DAY' 'LFT' 'LBE' 'ASE' 'GUM' 'TVC' 'ALO' 'TLH'
 'ELP' 'MHK' 'IMT' 'JNU' 'JAC' 'MEI' 'DBQ' 'GNV' 'BRD' 'DIK' 'SDF' 'LBB'
 'AVP' 'SGF' 'COU' 'BTM' 'ELM' 'RKS' 'PIH' 'SUN' 'LWS' 'VEL' 'STT' 'SAF'
 'YUM' 'FCA' 'GRR' 'HDN' 'ROA' 'CHA' 'EYW' 'MYR' 'CRW' 'MQT' 'CHO' 'GJT'
 'FWA' 'ECP' 'EVV' 'MSO' 'EGE' 'AMA' 'MLI' 'MBS' 'GFK' 'GRK' 'BIL' 'OTZ'
 'KTN' 'STX' 'ILM' 'PUB' 'RHI' 'CDC' 'HRL' 'SCC' 'FNT' 'LSE' 'MMH' 'ACT'
 'FSM' 'AGS' 'CEC' 'ICT' 'AEX' 'DHN' 'LRD' 'WRG' 'PHF' 'CNY' 'BRW' 'GGG'
 'AZO' 'CLL' 'SRQ' 'ORH' 'FLG' 'TRI' 'VLD' 'SIT' 'BQK' 'BMI' 'PSG' 'FAY'
 'MKG' 'CSG' 'MAF' 'EWN' 'OME' 'CMX' 'JMS' 'SGU' 'RST' 'GTR' 'BET' 'TOL'
 'APN' 'SMX' 'LCH' 'RDD' 'GCK' 'DVL' 'GRI' 'ABY' 'SWF' 'ILG' 'JLN' 'ADK'
 'UST' 'TXK' 'SPS' 'ABI' 'YAK' 'SJT' 'CDV' 'OTH' 'ADQ' 'PPG' 'ROW' 'HOB']
DESTINATION_AIRPORT ['SEA' 'PBI' 'CLT' 'MIA' 'ANC' 'MSP' 'DFW' 'ATL' 'IAH' 'PDX' 'MCI' 'FLL'
 'ORD' 'HNL' 'PHX' 'EWR' 'JFK' 'MCO' 'BOS' 'BDL' 'ITO' 'SFO' 'KOA' 'OGG'
 'MYR' 'DTW' 'LIH' 'DEN' 'SJU' 'LAX' 'BWI' 'IAD' 'BQN' 'BUF' 'LGA' 'HOU'
 'SLC' 'PHL' 'SJC' 'OAK' 'LGB' 'TPA' 'DCA' 'TTN' 'LAS' 'RSW' 'BRD' 'STL'
 'RKS' 'MBS' 'SNA' 'MEI' 'MDW' 'SAN' 'RIC' 'OTZ' 'PIT' 'JAX' 'MSY' 'ONT'
 'PSP' 'BUR' 'DAL' 'CVG' 'SMF' 'RDU' 'BNA' 'AUS' 'DSM' 'BOI' 'ELP' 'TUS'
 'SCC' 'HPN' 'STT' 'MDT' 'RHI' 'SBP' 'MKE' 'JNU' 'CMH' 'CLD' 'KTN' 'CAK'
 'CLE' 'GPT' 'IND' 'SAT' 'SRQ' 'BTV' 'CHS' 'DAY' 'TUL' 'SAV' 'COS' 'GJT'
 'BZN' 'PUB' 'HRL' 'HDN' 'MEM' 'GEG' 'ORH' 'SYR' 'ACY' 'LBB' 'JAC' 'BIL'
 'EUG' 'ASE' 'TVC' 'MTJ' 'OKC' 'PVD' 'HSV' 'CDC' 'GSO' 'YUM' 'ABQ' 'TLH'
 'EGE' 'BTR' 'MOB' 'FWA' 'BIS' 'MFR' 'APN' 'BHM' 'OMA' 'MMH' 'CEC' 'SBA'
 'RNO' 'LAN' 'PNS' 'DLH' 'SDF' 'FAT' 'GRR' 'VPS' 'MFE' 'AVP' 'ROA' 'MRY'
 'LFT' 'AGS' 'MGM' 'ROC' 'LRD' 'ISN' 'MLB' 'ORF' 'ICT' 'ECP' 'CRP' 'AMA'
 'BPT' 'EYW' 'FSD' 'TYS' 'WRG' 'MSN' 'FNT' 'DIK' 'CNY' 'BRW' 'GRB' 'ATW'
 'MKG' 'FLG' 'LEX' 'FCA' 'BTM' 'EVV' 'XNA' 'DRO' 'JMS' 'LNK' 'DBQ' 'FAR'
 'CAE' 'MLI' 'OME' 'GSP' 'GUC' 'SGF' 'LIT' 'MOT' 'RAP' 'ISP' 'PWM' 'GGG'
 'SBN' 'BFL' 'MHT' 'ROW' 'JAN' 'SHV' 'SIT' 'CMX' 'SAF' 'GRK' 'FAY' 'ILM'
 'CMI' 'MAF' 'ALB' 'GTF' 'BMI' 'CID' 'COU' 'GNV' 'SUN' 'SPI' 'PSG' 'AVL'
 'MHK' 'CHA' 'TOL' 'SGU' 'HLN' 'CPR' 'PIH' 'BET' 'VEL' 'RDM' 'HYS' 'PSC'
 'COD' 'INL' 'FAI' 'GCC' 'EKO' 'BJI' 'IDA' 'IMT' 'BRO' 'RST' 'HIB' 'ABR'
 'STC' 'MSO' 'ACV' 'ESC' 'CIU' 'SWF' 'DAB' 'TRI' 'AEX' 'AZO' 'CRW' 'STX'
 'CHO' 'GCK' 'PLN' 'LSE' 'SMX' 'RDD' 'PHF' 'LCH' 'CLL' 'TYR' 'GTR' 'LAR'
 'ERI' 'PAH' 'EAU' 'LBE' 'BLI' 'DVL' 'CWA' 'ILG' 'MLU' 'OAJ' 'ABE' 'ALO'
 'ABY' 'DHN' 'TWF' 'ADK' 'ELM' 'VLD' 'PIB' 'SUX' 'GUM' 'SCE' 'ACT' 'UST'
 'PIA' 'BQK' 'JLN' 'LAW' 'TXK' 'SPS' 'LWS' 'FSM' 'MQT' 'EWN' 'CSG' 'GRI'
 'PBG' 'PSE' 'IAG' 'YAK' 'ABI' 'SJT' 'CDV' 'OTH' 'ADQ' 'PPG' 'HOB' 'GFK']
'''



train.describe().T

스크린샷 2021-08-31 23 05 38

1
2
3
4
5
6
7
8
# 분포확인
print(train['result'].value_counts(normalize=True))
sns.displot(train['result'],kde=True);
'''
0    0.655758
1    0.344242
Name: result, dtype: float64
'''

스크린샷 2021-08-31 23 06 40

  • 약간은 불균형하다.
  • 최빈값인 ‘0.66’을 초기 정확도 Baseline으로 잡아둔다.
  • 나중에 scale_pos_weight를 위해 ratio를 계산해둔다.
  • Hyperparameter tuning만으로 부족하다면 smote도 고려해둔다.
1
2
3
4
5
ratio = 0.345097 / 0.654903
ratio
'''
0.5269436847899612
'''

Visualization

1
2
3
4
5
6
# 상관관계 시각화
new = train['result']
train = train.drop(['result'], axis = 1)
train = pd.concat([new, train], axis = 1)
plt.figure(figsize = (15,10))
sns.heatmap(data = train.corr(), annot=True, fmt = '.2f', linewidths=.5, cmap='Blues');

스크린샷 2021-08-31 23 13 01

  • 피쳐들간의 상관관계가 높은 경우가 종종 있으나, 분류문제이기 때문에 무시한다.
1
2
3
4
5
6
# 특성별 분포확인
delay = train[train.result == 1]
delay.shape
dp = train.columns
for i in dp:
    sns.displot(delay[i],kde=True);

스크린샷 2021-08-31 23 17 14

스크린샷 2021-08-31 23 17 38

스크린샷 2021-08-31 23 17 54

스크린샷 2021-08-31 23 18 20

가설 2 : 지연이 잦은 항공사가 있으므로 지연 확률을 줄이기 위한 고려사항이 된다.

1
2
3
4
5
6
7
8
9
10
11
# 지연 상황만 가정
delay = train[train.result == 1]
delay.shape

a_del = delay['AIRLINE'].value_counts().reset_index().rename(columns={'index':'IATA_CODE', 'AIRLINE':'count'})
a_del = pd.merge(a_del, airlines, how='left', on='IATA_CODE')

plt.figure(figsize=(10,10))
sns.barplot(x = 'AIRLINE', y = 'count', data = a_del)
plt.xticks(rotation=90)
plt.show()

스크린샷 2021-08-31 23 37 19

  • 유독 Southwest Airlines가 도착 지연이 잦은 것을 확인할 수 있다.
  • 그래프로 미루어보아 지연 확률을 줄이기 위해서 항공사를 잘 선택하는 것도 고려사항임을 알 수 있다.

가설 3 : 공학의 복잡도 고려 착륙지연이 잦은 출발 공항일 수록 도착 공항으로서의 지연도 잦다.

1
2
3
4
5
6
7
8
9
10
oa_del = delay['ORIGIN_AIRPORT'].value_counts().reset_index().rename(columns={'index':'AIRPORT', 'ORIGIN_AIRPORT':'oresult'})
da_del = delay['DESTINATION_AIRPORT'].value_counts().reset_index().rename(columns={'index':'AIRPORT', 'DESTINATION_AIRPORT':'dresult'})
oda_del = pd.merge(oa_del, da_del, how='left', on='AIRPORT')
oda_del = oda_del[:100]

for col in oda_del.columns[1:]:
    plt.figure(figsize=(30,5))
    sns.barplot(x = 'AIRPORT', y = col, data = oda_del)
    plt.xticks(rotation=90)
    plt.show()

스크린샷 2021-08-31 23 43 19

  • 출발공항일 때와 도착공항 일 때의 지연 횟수가 유의미하게 상관관계가 있음을 확인할 수 있다.
  • 그래프로 미루어보아 공항의 복잡도 고려 착륙지연이 잦은 출발 공항일 수록 도착 공항으로서의 지연도 잦음을 알 수 있다.

모델의 유용성 및 한계

  • 만들고자 하는 모델의 경우 항공기의 바퀴가 지면에서 띄워지는 순간에 착륙 지연을 예측할 수 있다.
  • 이는 이륙하자마자 전 승객에게 착륙 지연 여부를 알려줄 수 있기 때문에 유용할 뿐 아니라, 도착 공항이나 항공사에서도 대비를 할 수 있을거라 생각한다.
  • 하지만 이륙 시 통신이 두절되는 항공기의 특성 상 승객이 대비할 수 있는 여건은 마련되지 않는다.

Modeling

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 높은 cardinality를 가진 column에 유용한 Ordinal 인코딩 진행
encoder = OrdinalEncoder()
train = encoder.fit_transform(train)

# 학습/검증/테스트 타겟 생성 및 분리
target = 'result'
train, test = train_test_split(train, test_size=0.20, stratify=train[target], random_state=2)
train, val = train_test_split(train, test_size=0.20, stratify=train[target], random_state=2)

# 타겟 지정
features = train.drop(columns=[target]).columns

X_train = train[features]
y_train = train[target]
X_val = val[features]
y_val = val[target]
X_test = test[features]
y_test = test[target]

X_train.shape, X_val.shape, X_test.shape
'''
((39988, 12), (9997, 12), (12497, 12))
'''

1차 Modling(Baseline)

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
# 1차 Modeling : RandomForest
model = RandomForestClassifier(n_jobs=-1, random_state=2)

model.fit(X_train, y_train)
y_pred = model.predict(X_val)
print('훈련 정확도', model.score(X_train, y_train))
print('검증 정확도', model.score(X_val, y_val))
print('Report \n',classification_report(y_val, y_pred))
print('f1 스코어',f1_score(y_val, y_pred))
print('auc점수 : ', roc_auc_score(y_val, y_pred))
'''
훈련 정확도 1.0
검증 정확도 0.9143743122936882
Report 
               precision    recall  f1-score   support

           0       0.92      0.96      0.94      6556
           1       0.91      0.83      0.87      3441

    accuracy                           0.91      9997
   macro avg       0.91      0.90      0.90      9997
weighted avg       0.91      0.91      0.91      9997

f1 스코어 0.8700667880995749
auc점수 :  0.8950179563136914
'''
  • RandomForest를 이용하여 1차 Baseline Modeling을 진행했다.
  • Parameter없이 간단히 진행하였으며, 정확도를 보면 과적합이 확인되지만, 검증 Set에서의 정확도가 최빈값 baseline을 넘었으므로 이번 Modeling에서 유심히 볼 평가지표인 ‘AUC Score’를 Baseline으로 두고 진행한다.
  • 정확도, 정밀도와 재현율이 포함된 F1도 함께 확인하며 진행하지만 신호탐지이론에서 적중확률 대 오경보확률의 그래프를 점수화 한 AUC Score를 중점으로 두고 진행한다.

2차 Modeling

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
# 2차 Modeling : CatBoostClassfier
model = CatBoostClassifier()

model.fit(X_train, y_train)
y_pred = model.predict(X_val)
print('훈련 정확도', model.score(X_train, y_train))
print('검증 정확도', model.score(X_val, y_val))
print('Report \n',classification_report(y_val, y_pred))
print('f1 스코어',f1_score(y_val, y_pred))
print('auc점수 : ', roc_auc_score(y_val, y_pred))
'''
Learning rate set to 0.049769
0:	learn: 0.6375374	total: 23.7ms	remaining: 23.7s
1:	learn: 0.5891427	total: 46.3ms	remaining: 23.1s
2:	learn: 0.5464283	total: 69.7ms	remaining: 23.2s
3:	learn: 0.5069459	total: 92.8ms	remaining: 23.1s
.
.
.
997:	learn: 0.1565486	total: 21.3s	remaining: 42.8ms
998:	learn: 0.1565066	total: 21.4s	remaining: 21.4ms
999:	learn: 0.1564972	total: 21.4s	remaining: 0us
훈련 정확도 0.9413073922176654
검증 정확도 0.9176753025907772
Report 
               precision    recall  f1-score   support

           0       0.92      0.96      0.94      6556
           1       0.92      0.84      0.88      3441

    accuracy                           0.92      9997
   macro avg       0.92      0.90      0.91      9997
weighted avg       0.92      0.92      0.92      9997

f1 스코어 0.875094855061466
auc점수 :  0.898708424715136
'''
  • RandomForest를 사용했을 때보다 아주 조금 올랐다.
  • Threshold를 설정한다.
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
# roc_curve(타겟값, prob of 1)
y_pred_proba = model.predict_proba(X_val)[:, 1]
fpr, tpr, thresholds = roc_curve(y_val, y_pred_proba)

roc = pd.DataFrame({
    'FPR(Fall-out)': fpr, 
    'TPRate(Recall)': tpr, 
    'Threshold': thresholds
})
# print(roc)

# roc 시각화
plt.rcParams["figure.figsize"] = (10,4)
plt.subplot(121)
plt.scatter(fpr, tpr)
plt.title('ROC curve')
plt.xlabel('FPR(Fall-out)')
plt.ylabel('TPR(Recall)');

# 최적의 threshold
optimal_idx = np.argmax(tpr - fpr)
optimal_threshold = thresholds[optimal_idx]
print('idx:', optimal_idx, ', threshold:', optimal_threshold)

# auc 시각화
plt.subplot(122)
plt.plot(tpr-fpr);

# threshold 설정 및 레포트
y_pred_optimal = y_pred_proba >= optimal_threshold
print('Report \n',classification_report(y_val, y_pred_optimal))

# auc 점수
auc_score = roc_auc_score(y_val, y_pred_optimal)
print('최종 검증 정확도: ', accuracy_score(y_val, y_pred_optimal))
print('최종 f1 스코어',f1_score(y_val, y_pred_optimal))
print('최종 auc점수 : ', auc_score)
'''
idx: 512 , threshold: 0.3877775976225708
Report 
               precision    recall  f1-score   support

           0       0.93      0.94      0.94      6556
           1       0.88      0.87      0.88      3441

    accuracy                           0.92      9997
   macro avg       0.91      0.91      0.91      9997
weighted avg       0.92      0.92      0.92      9997


최종 검증 정확도:  0.9161748524557367
최종 f1 스코어 0.8775927548933684
최종 auc점수 :  0.9059183447849827
'''
  • 성능이 조금 더 올랐다.

스크린샷 2021-09-01 00 05 57

Hyperparameters tuning

  • Data imbalince에 사용하는 scale_pos_weigt 및 여러가지 Hyperparameters tuning을 진행한다.
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
model = CatBoostClassifier(scale_pos_weight = ratio, learning_rate = 0.1, max_depth = 10, n_estimators = 200)

model.fit(X_train, y_train)
y_pred = model.predict(X_val)

# roc_curve(타겟값, prob of 1)
y_pred_proba = model.predict_proba(X_val)[:, 1]
fpr, tpr, thresholds = roc_curve(y_val, y_pred_proba)

roc = pd.DataFrame({
    'FPR(Fall-out)': fpr, 
    'TPRate(Recall)': tpr, 
    'Threshold': thresholds
})
# print(roc)

# roc 시각화
plt.rcParams["figure.figsize"] = (10,4)
plt.subplot(121)
plt.scatter(fpr, tpr)
plt.title('ROC curve')
plt.xlabel('FPR(Fall-out)')
plt.ylabel('TPR(Recall)');

# 최적의 threshold
optimal_idx = np.argmax(tpr - fpr)
optimal_threshold = thresholds[optimal_idx]
print('idx:', optimal_idx, ', threshold:', optimal_threshold)

# auc 시각화
plt.subplot(122)
plt.plot(tpr-fpr);

# threshold 설정 및 레포트
y_pred_optimal = y_pred_proba >= optimal_threshold
print('Report \n',classification_report(y_val, y_pred_optimal))

# auc 점수
auc_score = roc_auc_score(y_val, y_pred_optimal)
print('최종 검증 정확도: ', accuracy_score(y_val, y_pred_optimal))
print('최종 f1 스코어',f1_score(y_val, y_pred_optimal))
print('최종 auc점수 : ', auc_score)
'''
idx: 978 , threshold: 0.3913897995892618
Report 
               precision    recall  f1-score   support

           0       0.95      0.91      0.93     10244
           1       0.84      0.90      0.87      5377

    accuracy                           0.91     15621
   macro avg       0.90      0.91      0.90     15621
weighted avg       0.91      0.91      0.91     15621

최종 검증 정확도:  0.9087126304333909
최종 f1 스코어 0.8719468390804599
최종 auc점수 :  0.907336532588475
'''
  • 성능이 약간 더 좋아졌다.

GridSearchCV

  • 최적의 parameters 값을 찾기 위해 GridSerchCV를 진행한다.
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
71
72
73
74
75
params ={
    'n_estimators': [100, 200, 300],
    'max_depth':[9, 10, 11],
    'learning_rate':[0.1, 0.2, 0.3]
}

cb = CatBoostClassifier(scale_pos_weight = ratio)
grid_cv = GridSearchCV(cb, param_grid=params, n_jobs=-1)
grid_cv.fit(X_train, y_train)
print('best parameters : \n', grid_cv.best_params_)
'''
best parameters : 
 {'learning_rate': 0.1, 'max_depth': 9, 'n_estimators': 200}
'''


# Best parameters 적용 Modeling
model = CatBoostClassifier(scale_pos_weight = ratio, learning_rate = 0.1, max_depth = 9, n_estimators = 200)

model.fit(X_train, y_train)
y_pred = model.predict(X_val)

# roc_curve(타겟값, prob of 1)
y_pred_proba = model.predict_proba(X_val)[:, 1]
fpr, tpr, thresholds = roc_curve(y_val, y_pred_proba)

roc = pd.DataFrame({
    'FPR(Fall-out)': fpr, 
    'TPRate(Recall)': tpr, 
    'Threshold': thresholds
})
# print(roc)

# roc 시각화
plt.rcParams["figure.figsize"] = (10,4)
plt.subplot(121)
plt.scatter(fpr, tpr)
plt.title('ROC curve')
plt.xlabel('FPR(Fall-out)')
plt.ylabel('TPR(Recall)');

# 최적의 threshold
optimal_idx = np.argmax(tpr - fpr)
optimal_threshold = thresholds[optimal_idx]
print('idx:', optimal_idx, ', threshold:', optimal_threshold)

# auc 시각화
plt.subplot(122)
plt.plot(tpr-fpr);

# threshold 설정 및 레포트
y_pred_optimal = y_pred_proba >= optimal_threshold
print('Report \n',classification_report(y_val, y_pred_optimal))

# auc 점수
auc_score = roc_auc_score(y_val, y_pred_optimal)
print('최종 검증 정확도: ', accuracy_score(y_val, y_pred_optimal))
print('최종 f1 스코어',f1_score(y_val, y_pred_optimal))
print('최종 auc점수 : ', auc_score)
'''
idx: 898 , threshold: 0.45687398247139754
Report 
               precision    recall  f1-score   support

           0       0.94      0.93      0.93     10244
           1       0.86      0.89      0.88      5377

    accuracy                           0.91     15621
   macro avg       0.90      0.91      0.90     15621
weighted avg       0.91      0.91      0.91     15621

최종 검증 정확도:  0.9133218103834582
최종 f1 스코어 0.8758936755270396
최종 auc점수 :  0.907448955909144
'''
  • 성능이 아주 조금 올랐다.

스크린샷 2021-09-01 00 20 18

최종 Modeling

  • 수동으로 조정한 Hyperparameters 값이 가장 좋은 성능을 나타내어 최종 Modeling을 진행했다.
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
# 최종 Modeling
model = CatBoostClassifier(scale_pos_weight = ratio, learning_rate = 0.1, max_depth = 10, n_estimators = 300)

model.fit(X_train, y_train)
y_pred = model.predict(X_val)

# roc_curve(타겟값, prob of 1)
y_pred_proba = model.predict_proba(X_val)[:, 1]
fpr, tpr, thresholds = roc_curve(y_val, y_pred_proba)

roc = pd.DataFrame({
    'FPR(Fall-out)': fpr, 
    'TPRate(Recall)': tpr, 
    'Threshold': thresholds
})
# print(roc)

# roc 시각화
plt.rcParams["figure.figsize"] = (10,4)
plt.subplot(121)
plt.scatter(fpr, tpr)
plt.title('ROC curve')
plt.xlabel('FPR(Fall-out)')
plt.ylabel('TPR(Recall)');

# 최적의 threshold
optimal_idx = np.argmax(tpr - fpr)
optimal_threshold = thresholds[optimal_idx]
print('idx:', optimal_idx, ', threshold:', optimal_threshold)

# auc 시각화
plt.subplot(122)
plt.plot(tpr-fpr);

# threshold 설정 및 레포트
y_pred_optimal = y_pred_proba >= optimal_threshold
print('Report \n',classification_report(y_val, y_pred_optimal))

# auc 점수
auc_score = roc_auc_score(y_val, y_pred_optimal)
print('최종 검증 정확도: ', accuracy_score(y_val, y_pred_optimal))
print('최종 f1 스코어',f1_score(y_val, y_pred_optimal))
print('최종 auc점수 : ', auc_score)
'''
idx: 896 , threshold: 0.38973459361256957
Report 
               precision    recall  f1-score   support

           0       0.95      0.91      0.93     10244
           1       0.85      0.90      0.87      5377

    accuracy                           0.91     15621
   macro avg       0.90      0.91      0.90     15621
weighted avg       0.91      0.91      0.91     15621

최종 검증 정확도:  0.9096728762563216
최종 f1 스코어 0.8728026683494096
최종 auc점수 :  0.9074501541229775
'''

스크린샷 2021-09-01 00 24 01

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
# 테스트 데이터 성능확인
y_pred = model.predict(X_test)

# roc_curve(타겟값, prob of 1)
y_pred_proba = model.predict_proba(X_test)[:, 1]
fpr, tpr, thresholds = roc_curve(y_test, y_pred_proba)

roc = pd.DataFrame({
    'FPR(Fall-out)': fpr, 
    'TPRate(Recall)': tpr, 
    'Threshold': thresholds
})

# roc 시각화
plt.rcParams["figure.figsize"] = (10,4)
plt.subplot(121)
plt.scatter(fpr, tpr)
plt.title('ROC curve')
plt.xlabel('FPR(Fall-out)')
plt.ylabel('TPR(Recall)');

# 최적의 threshold
optimal_idx = np.argmax(tpr - fpr)
optimal_threshold = thresholds[optimal_idx]
print('idx:', optimal_idx, ', threshold:', optimal_threshold)

# auc 시각화
plt.subplot(122)
plt.plot(tpr-fpr);

# threshold 설정 및 레포트
y_pred_optimal = y_pred_proba >= optimal_threshold
print('Report \n',classification_report(y_test, y_pred_optimal))

# auc 점수
auc_score = roc_auc_score(y_test, y_pred_optimal)
print('테스트 정확도', model.score(X_test, y_test))
print('f1 스코어',f1_score(y_test, y_pred_optimal))
print('auc점수 : ', auc_score)
'''
idx: 1072 , threshold: 0.46905030139281495
Report 
               precision    recall  f1-score   support

           0       0.94      0.93      0.93     12804
           1       0.87      0.89      0.88      6722

    accuracy                           0.91     19526
   macro avg       0.90      0.91      0.91     19526
weighted avg       0.92      0.91      0.91     19526

테스트 정확도 0.9150363617740449
f1 스코어 0.8772961058045555
auc점수 :  0.9082160941412145
'''

스크린샷 2021-09-01 00 27 37

  • Test Set에서의 결과도 만족할 만큼 나왔다.
  • Train Set에 과적합되지 않고 일반화가 잘 됐다고 볼 수 있다.
  • 최종적으로 91.5%의 정확도로 착륙 지연을 예측하는 머신러닝 모델을 만들었다.

해석

Permutation Importance

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
# Permutation Importance 확인
# permuter 정의
permuter = PermutationImportance(
    model, # model
    scoring='accuracy', # metric
    n_iter=5, # 다른 random seed를 사용하여 5번 반복
    random_state=2
)

# 실제로 fit 의미보다 스코어 다시 계산하는 작업
permuter.fit(X_val, y_val);

feature_names = ntrain.columns.tolist()
pd.Series(permuter.feature_importances_, feature_names).sort_values()
'''
SCHEDULED_ARRIVAL     -0.000371
WHEELS_OFF            -0.000346
TAIL_NUMBER            0.000090
SCHEDULED_DEPARTURE    0.000128
DEPARTURE_TIME         0.000755
ORIGIN_AIRPORT         0.003252
DESTINATION_AIRPORT    0.006120
AIRLINE                0.007016
DISTANCE               0.014506
SCHEDULED_TIME         0.026208
TAXI_OUT               0.064196
DEPARTURE_DELAY        0.317637
dtype: float64
'''

# 특성별 score 확인
eli5.show_weights(
    permuter, 
    top=None, # top n 지정 가능, None 일 경우 모든 특성 
    feature_names=feature_names # list 형식으로 넣어야 합니다
)

스크린샷 2021-09-01 01 04 53

가설1 : 출발 예정시간보다 출발에 지연된 시간이 클 수록 착륙 지연 확률은 늘어날 것이다.

  • 총 출발 지연 시간이 가장 Model에 큰 영향을 끼친 걸 볼 수 있다.
  • 다음으로 게이트에서 항공기가 이륙할 때까지 경과 시간도 도착 지연에 큰 영향을 미쳤다.
  • 계획되어있는 비행시간과 거리도 무시 못할만큼의 영향을 미쳤다.

PDP

  • Permutation Importance에서 영향을 많이 끼친 4가지 Feature에 대해 PDPlot 확인
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 화질
plt.rcParams['figure.dpi'] = 144

for i in ['DEPARTURE_DELAY', 'TAXI_OUT', 'SCHEDULED_TIME', 'DISTANCE']:
    feature = i
    isolated = pdp_isolate(
        model=model, 
        dataset=ntrain, 
        model_features=ntrain.columns, 
        feature=feature,
        grid_type='percentile', # default='percentile', or 'equal'
        num_grid_points=10 # default=10
    )
    pdp_plot(isolated, feature_name=feature);

스크린샷 2021-09-01 01 17 51

스크린샷 2021-09-01 01 18 13

  • SCHEDULED_TIME가 음의 상관계수인 것을 제외하면 나머지는 모두 양의 상관계수를 보인다.

SHAP

  • SHAP을 통해 각 Feature의 영향력 확인
1
2
3
4
5
row = ntrain.iloc[[1]]  # 중첩 brackets을 사용하면 결과물이 DataFrame
shap.initjs()
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(ntrain.iloc[:100])
shap.force_plot(explainer.expected_value, shap_values, ntrain.iloc[:100])

스크린샷 2021-09-01 01 33 42

1
shap.summary_plot(shap_values, ntrain.iloc[:300], plot_type="violin")

스크린샷 2021-09-01 01 34 03

  • Airline 특성이 착륙 지연 예측에 영향을 주므로 가설 ‘지연이 잦은 항공사가 있으므로 지연 확률을 줄이기 위한 고려사항이 된다.’라는 내용도 어느정도 검증이 된다.
1
2
# type ber
shap.summary_plot(shap_values, ntrain.iloc[:300], plot_type="bar")

스크린샷 2021-09-01 01 36 18

  • 각 그래프 확인 결과 Permutation importance와 마찬가지로 Departure delay의 영향력이 가장 크고 다음으로 taxi out, distance인 것을 확인할 수 있다.

Insight

  • 현재 Cost의 한계 때문에 10만개의 Data만 사용했음에도 착륙 지연에 관한 좋은 성능의 Modeling을 했다.
  • 모든 Data를 활용한다면 더 좋은 성능을 이끌어 낼 수 있을 거라 생각하고, 그렇게 된다면 Date 정보도 예측에 활용 될 수 있다.
  • 또한 현재 착륙 지연에 대한 예측을 할 수 밖에 없는 특성들이었는데, 기상 데이터와 항공 정비 이력에 관한 특성이 주어진다면 이륙 지연에 대한 예측이 가능해져 소비자 혹은 공항이나 항공사의 효율성과 비용절감에 더욱 크게 기여할 수 있을 거라고 생각한다.

Keynote 및 대본

Project2 001

안녕하세요.
Project 착륙 지연 예측 ML Model의 발표를 맡게 된
AI Bootcamp 5기의 이윤민이라고 합니다. 발표 시작하겠습니다.

Project2 002

목차는 데이터 수집부터 탐색적 분석과정과 Modeling,
그리고 그 Modeling을 통해 도출된 해석 및 인사이트까지 발표하도록 하겠습니다.

Project2 003

먼저 데이터 선정 이유와 해결하고자 하는 문제에 대해 말씀드리겠습니다.
현재 항공교통 수요가 지속해서 증가하고 있고,
미래에도 꾸준히 성장하게 될 텐데 그에 따라 항공기 지연으로 인한 이용자들의 불편과 피해가 늘어나고 있습니다.

지연이 발생하게 되면 공항이나 항공사뿐 아니라 승객까지 모두 시간적, 금전적 손해가 발생하며 공항 운영에 있어 피해를 보게 됩니다.
만약 지연 발생을 예측할 수 있다면 관계자가 적절한 조처를 할 수 있어 소비자가 입을 추가적인 피해에 대비할 수 있을 거로 생각했습니다.
그걸 위해서 캐글의 2015년 Flight delay & cancellations 데이터셋을 사용했는데 cost의 한계로 인해 데이터를 10만 개 까지만 사용했습니다.
단순한 지연 여부 분류 문제로 해결할 것이고요. 예측에 사용될 특성은 15분 이상 착륙이 지연됐다 안됐다를 표현하는 binary 값입니다.

Project2 004

탐색적 분석에 앞서 몇 가지 가설을 세우고 검증해가며 진행해보겠습니다.
세운 가설 첫 번째로는 약간은 당연한 얘기일 수도 있지만, 출발 예정 시간보다 실제로 이륙한 시간이 지연됐을 때 착륙이 지연될 확률은 늘어날 것이다 입니다.
실제로 이륙을 늦게 하더라도, 항공기의 속력을 조절해가며 도착 예정 시간에 맞춰 착륙이 가능합니다.
그런데도 이륙 지연 시간과 착륙 지연 시간이 관계가 있음을 나중에 모델링 해석에서 검증해보도록 하겠습니다.

두 번째로는 만약 어떤 항공사가 착륙 지연이 유의하게 타 항공사보다 잦다면,
여행이나 비즈니스 계획에 앞서 지연확률을 줄이기 위해 항공사의 선택이 고려사항이 될지 시각화를 통해서도 알아보고 모델링을 통해서도 알아볼 생각입니다.

세 번째로 복잡한 공항일수록 지연이 잦을 거로 생각하기 때문에 출발 공항에서의 착륙지연과 도착 공항에서의 착륙지연이 유의하게 비슷할지 시각화를 통해 비교해보려 합니다.

Project2 005

다음 Baseline Model에 대해서 알려드리도록 하겠습니다.
Baseline Model이란 Modeling을 진행할 때 성능을 비교하기 위해 잡는 Prototype의 초기 모델을 말합니다.
저는 두 번에 걸친 Baseline Model을 설정하려 하는데 보통 분류모델에서는 초기 비교 정확도로 최빈값을 설정하는데,

이 데이터에서는 정상 착륙의 비율이 66%이므로 일차적인 정확도가 66% 이상이 된다면 그 모델을 이차적인 Baseline Model로 설정해 AUC Score를 성능을 비교하는 평가지표로 사용하려 합니다.
여기서 AUC Score란 ML 분류 모델에서의 중요한 평가 지표로써 적중확률 대 오경보 확률 그래프의 면적을 점수화한 값입니다.
이런 그래프인데 참고하시면 되겠습니다.

Project2 007

다음 피쳐 엔지니어링입니다.
먼저 저희가 만들게 될 Model은 항공기의 바퀴가 지면에서 띄워지는 순간 착륙 지연을 예측해야 합니다.
현재 Dataset에는 도착과 관련된 정보까지 존재하는 상태라 항공기가 Take-off 하는 동시에 예측 할 수 있을 만큼의 특성만 남겨두고 모두 제거하였습니다.

또 Modeling에 쓰일 분류 특성을 새로 만들었습니다.
착륙 지연시간이 15분 이하면 정상 착륙으로 분류하고 15분이 넘어가게 되면 착륙 지연으로 분류하였습니다.
이렇게 만든 특성을 예측에 사용할 것입니다.

Project2 008

현재 데이터 내 결측값이 3% 정도 존재했습니다.
이미 임의로 10만 개로 줄인 데이터를 사용하기도 하고 결측값의 비율이 매우 작아 영향력이 미미하기 때문에 모두 삭제하는 조처를 했습니다.

Project2 009

현재 데이터 내에 정상 착륙과 착륙 지연의 비율을 확인해봤습니다.
대략 6 : 4 정도로의 불균형이 존재합니다.
이 불균형이 심각하진 않지만, 모델링에 성능에 영향을 줄 수 있기 때문에 상기해두고 나중에 적절한 조처를 했습니다.
현재 이 비율을 보고 최빈값 66%를 정확도 베이스라인으로 잡은 겁니다.

Project2 010

다음 시각화 자료를 보여드릴 텐데요.
먼저 항공사별 착륙 지연 횟수 그래프입니다.
여기서 지연이 잦은 항공사가 있음으로 지연 확률을 줄이기 위한 고려사항이 된다.
라는 가설을 잠시 짚고 넘어갈 건데요.
유독 southwest airlines에서 착륙 지연이 타 항공사에 비해 잦은 걸 볼 수 있습니다.
항공사가 예측에 쓰이는 특성이 될지는 추후 모델링을 통해 심층적으로 검증하겠습니다.

Project2 011

다음 시각화로는 공항별로 출발 공항과 도착 공항으로의 착륙 지연 횟수를 비교해봤는데요.
다음 그래프를 보시면 착륙지연이 잦은 출발 공항일수록 도착 공항으로써의 지연이 잦음을 유의하게 확인할 수 있습니다.

Project2 012

모델링에 앞서 모델의 유용성 및 한계를 짚고 넘어가려 하는데요.
현재 만들고자 하는 모델의 경우 항공기의 바퀴가 지면에서 띄워지는 순간에 착륙 지연을 예측할 수 있습니다.
이는 이륙하자마자 전 승객에게 착륙지연 여부를 알려줄 뿐 아니라,
도착 공항이나 항공사에서도 대비하고 조처를 할 수 있을 거라 생각하기 때문에 일부 유용하지만,
이륙 시 통신이 두절되는 항공기의 특성상 승객이 대비할 수 있는 여건은 마련되지 않는다는 한계가 있습니다.

Project2 013

이제 앞에서 설명해 드린 데이터를 토대로 예측 모델링 결과를 말씀드릴 텐데요.
먼저 일차적으로 RandoㅁmForest라는 머신러닝 모델을 통해서 학습을 진행했고 RandomForest란 쉽게 말하면,
학습한 여러 가지의 나무로부터 결과를 취합해서 얻는 일종의 인기투표라고 보시면 되는데요.
ML에서 좋은 성능을 가진 모델입니다.
Modeling 결과로는 정확도가 91% 나왔기 때문에 앞에서 설정한 Baseline보다 잘 나왔다고 할 수 있고요.
정확히 몰라도 되지만 재현율과 정밀도를 결합한 f1 score는 0.87이 나왔는데 현재 모델링에서 중점으로 보고 있는 AUC 스코어만 보시면 되기 때문에 무시하셔도 좋습니다.
이번 모델링에서 나온 AUC 점수는 0.895점인데 이 점수를 2차 baseline 평가지표로 삼고 다음 모델링을 진행하겠습니다.

Project2 014

2차 모델링으로 catboost를 사용했는데요.
catboost는 앞의 랜덤포레스트와 비슷한 방식의 모델링 방법이지만 범주형 변수가 많을 때 유용하게 쓰인다는 것 정도만 알면 되겠습니다.
항공사나 공항의 범주가 많았기 때문에 이 모델을 사용했고 결과로는 정확도 0.916, AUC Score가 0.905로써 2차로 잡아둔 Baseline Model보다 높은 성능을 보였습니다.

Project2 015

다음으로 Hyperparameter tuning을 진행하며 Girdsearch라는 것을 해보았는데요.
Hyperparameter란 앞에서 했던 Modeling에서 설정할 수 있는 여러 가지 값을 말하며 주로 성능을 올리고자 할 때 사용됩니다.
Gridsearch는 Hyperparameter의 최적값을 자동으로 탐색해주는 기능을 뜻하며 두 가지 기능으로 성능을 올린 결과,
성능이 조금 오른 것을 확인할 수 있었습니다.

Project2 016

최종적으로 성능이 가장 좋았던 모델인 Catboost, 각종 Hyperparameter tuning,
그리고 아까 데이터 균형을 살펴본 파트에서 상기해둔 imbalance 비율을 잘 조정해서
테스트를 하기 위해서 일부 빼두었던 데이터로 검증해본 결과
최종적으로 AUC Score 0.908이 나오게 되었고 정확도는 0.915가 나와

Project2 017

최종적으로 도착 지연에 대해 91.5%의 정확도로 예측할 수 있는 모델을 완성했습니다.

Project2 018

다음으로 Permutation importance와 SHAP를 이용해서 만든 모델에 대한 설명을 할 텐데요.
현재 왼쪽에 보이는 그래프는 모델에서 어떤 특성을 주로 사용해서 예측을 수행했는지를 보여주는 샵 그래프입니다.
양쪽으로 퍼져있는 정도로 얼마나 예측에 관여를 많이 했는지를 볼 수 있는데요.
첫 번째 departure delay가 가장 영향력이 높고 다음으로 taxi out, distance, scheduled time이 비슷하게 영향을 꽤 많이 준 것을 볼 수 있습니다.

Departure delay는 총 출발 지연 시각인데요.
아까 생각했던 출발 지연이 늦을수록 도착이 지연될 것이다.
라는 가설이 검증됨을 알 수 있습니다.
나머지 taxi out과 distance, scheduled time은
항공기가 이륙할 때까지의 경과 시간과 계획된 비행시간, 거리인데 이 세 가지 특성들도 예측에 무시 못 할 만큼의 영향을 미쳤습니다.
오른쪽에 보이는 표는 특성들의 영향력을 수치화한 Permutation importance 표입니다.
두 가지 모두 비슷한 특성의 영향을 확인할 수 있었습니다.

Project2 019

여기서 또 봐주셨으면 하는 게 Airline인데,
이것 또한 아까 세웠던 가설인 지연이 잦은 항공사가 있음으로 지연 확률을 줄이기 위한 고려사항이 된다.
라는 내용도 Airline 특성이 착륙 지연 예측에 영향을 주므로 어느 정도 검증이 되었다고 볼 수 있습니다.

Project2 020

현재 cost의 한계 때문에 10만 개의 data로만 사용했는데도 착륙 지연에 관한 좋은 성능의 모델링을 할 수 있었습니다.
만약 모든 data를 함께 활용한다면 성능도 좋아질 뿐 아니라 date 특성을 이용해 예측에 활용할 수 있게 될 것입니다.
또 현재는 착륙 지연에 대한 예측밖에 할 수 없는 특성들이었지만,
만약 기상 데이터와 항공 정비 이력에 대한 특성이 주어진다면 이륙 지연에 대한 예측이 가능해져 소비자 혹은 공항이나 항공사의 효율성과 비용 절감에 더욱 크게 기여할 수 있을 거라고 생각합니다.

Project2 021

이상으로 항공기 착륙 지연 예측 머신러닝 모델 프로젝트 발표를 마칩니다. 감사합니다.

Feedback

좋았던 점

  • 데이터 선정의 이유가 처음부터 잘 나타내서 집중하기 수월했고, 세운 가설과 검증 과정도 논리정연해서 듣기 편했습니다. 윤민님의 발표를 보니 제 발표는 비데이터 직군에게는 조금 어렵게 느껴질 수도 있겠다는 생각이 많이 드네요..!! 예측 모델에 대한 분석도 가설과 잘 맞는 부분도 훌륭하십니다. cost의 제한으로 10만개의 데이터로도 해결하고자 했던 착륙 지연 예측이 잘 돼서 다른 데이터를 추가했을 때의 예측 모델이 기대가 되네요! 프로젝트 하느라 고생 많으셨습니다ㅎㅎ 잘하시는 분의 발표와 결과를 보는 것은 언제나 흥미롭네요 :)
  • 여러시각화로 전체적인 흐름을 이해하기 좋았고 데이터직군이 아닌 청자를 위한 세세한 설명이 인상깊었습니다. 가설 제시로 시작해서 하나하나 설명하셔서 발표를 몰입감 있게 잘 보았습니다.
  • 전달력: 목소리가 크고 잘들려서 좋았습니다. / 데이터: 많이 고려해서 찾은 분류문제여서 발표자료에 잘 녹아들게 만든것같습니다. / 기타: 비전공자에게 자주 접하지 않는용어들을 쉽게 설명해서 잘 이해할수있게 만드셔서 좋았던것같습니다.
  • 모델의 종류에 따른 강점과 특징, 초보자의 입장에서 이해가 어려울 법한 용어들을 간략하고 쉽게 전달하였습니다. 발표전반적으로 섹션2에 대한 이해도가 높은 것이 느껴졌습니다. 피피티 자료가 깔끔하고 전달력이 좋았습니다. 따로 마우스포인터로 짚지 않았는데도 어느 부분을 설명하는지 쉽게 알 수 있었습니다. 다양한 가설을 eda부분에서 시각화해서 잘 나타내서 이해하기 쉬웠습니다.
  • 침착하고 속도도 적당하게 진행해주셔서 무리없이 잘 들었습니다. 주제와도 부합한 자료였습니다, 저랑 거의 비슷한 종류의 데이터로 저보다 훨씬 깔끔하고 일목요연하게 목표와 결론을 설정해주셔서, 제가 배운 부분이 많습니다.
  • 발표 전달력 및 속도가 듣기 편했습니다. 발표주제의 적절한 데이터를 검증하고 정확도를 예측해 신뢰감이 생깁니다.
  • 주제 선정 배경과 데이터셋의 출처를 명확히 밝혀주셔서 더 신뢰가 가고 집중해서 들을 수 있는 발표였습니다. 발표 자료의 가독성이 너무 좋아요! 중요한 텍스트만 써있고 요약이 잘 된 느낌이었습니다. 섹션에 대한 이해를 과제 진행에 잘 녹여낸 것 같습니다. 쉽게 설명하려고 하셨던 부분이 인상깊게 남았어요. 일종의 인기투표 ㅋㅋㅋㅋㅋ SHAP를 활용해서 앞부분 가설과 이어진 부분이 좋았습니다. 발표를 다 듣고 나서 ‘그래서 이건 왜 한 거지?’라는 생각이 드는 부분이 없었던 것 같아요. 이 점은 제가 개인적으로 프로젝트 할 때 가장 중요하게 생각하는 부분이거든요.

아쉬운 점

  • 아쉬운 점이라면 마지막에 윤민님이 말씀하신 대로 추가적인 데이터가 없어 이륙지연 예측의 결과를 보지 못한게 아쉽습니다ㅎㅎ.. 수행하신 내용에 대해 피드백을 잘 드리지 못하는 것 같아 괜히 죄송하네요ㅠ 개인적으로 프로젝트 발표를 듣는 대상이 비데이터 직군이라 설명이 간단한 것에 아쉬움이 있습니다. 조금 더 자세하게 듣고 싶은데 이 부분은 윤민님의 깃허브를 보고 공부를 해서 채우도록 할게요!
  • 한계에서도 언급하셨지만 지연발생의 예측이 이륙시점에 이루어짐으로 목표에서 제시하셨던 예측으로 인한 경제적인 효과를 보기에는 예측을 시행하는 시점이 조금 늦은게 아닌가 싶습니다. 예측으로 인해 발생하는 다른 이점을 제시하셨다면 높은 정확도로 예측하는 모델에 의미가 더욱 돋보였을것같습니다.
  • 열심히 고민하셔서 만드셔서 만든 영상이여서, 아쉬웠던것은 없었습니다. 프로젝트기간동안 고생하셨습니다!
  • 많은 내용을 담고있는건 좋았지만, 너무 숨가쁜 느낌이 들었습니다. 편집을 통해 틈을 없애서, 유튜브 1분요약영상 보는 느낌이 들었는데요, 차라리 조금 덜 중요한 설명을 줄이고 듣는 입장에서도 여유가 느껴질 수 있다면 더 좋을 것 같습니다. 얼굴위치때문에 ppt자료 글씨가 가려져서 조금 불편함이 느껴졌습니다. auc그래프나 shap를 시각화한 부분에서 단지 참고자료로 활용하기보다는, 그래프로 어떻게 해석이 가능한지에 초점을 맞춰서 설명해주시면 좋을 것 같습니다. 피피티는 공식자료이기 때문에, ‘착륙 지연시간이 15분 이하니?’와 같은 문장보다는 좀 더 공식적인 언어를 쓰는것이 좋겠습니다. 윤민님 발표자료 꼼꼼하게 보고싶어서 피드백 요청했습니다. 섹션2와 섹션1의 내용을 전반적으로 잘 반영하고 있었고, 군더더기 없는 깔끔한 발표내용이였습니다. 수고하셨습니다. ^^
  • 데이터분석에 대해 잘 알지 못하는 청자라면 알아듣지 못하는 내용이 많아 전체적인 내용의 이해하는 부분이 적을것으로 보입니다.
  • 모델이 개선될때마다 얼만큼 올랐는지 한 눈에 볼 수 있도록 해주셨다면 더 좋았을 것 같습니다. 저는 궁금해서 앞으로 다시 돌아갔거든요! 마지막에 인사이트 부분을 텍스트로 조금 요약해서 띄워주셨으면 더 좋지 않았을까 싶습니다. 근데 이렇게 쓰긴 했는데 별로 큰 아쉬움은 아니었어요.
0%