본문 바로가기

[Data Engineering]/[Gloud-GCP]

[GCP] 5-3. Data refining & model eval

728x90

 < 실습 - 품질 제어 >

 

- 이상치(outlier) 확인 - 

  클라우드 데이터랩으로 쿼리를 계속 작성할 수 있다. 하지만 빅쿼리 콘솔에서 쿼리문을 작성하면 즉각적인 피드백을 얻을 수 있으므로 빅 쿼리로 접속해 해당 쿼리문을 입력해 보자. 출발지연시간에 따른 항공편 숫자와 도착지연 평균을 나타낸다.

select
  DEP_DELAY,
  AVG(ARR_DELAY) AS arrival_delay,
  COUNT(ARR_DELAY) AS numflights
  from
    flights.tzcorr
  group by
    DEP_DELAY
  order by
    DEP_DELAY

< 쿼리문 결과를 살펴보면 82분 먼저 출발한 항공편도 있다 >

  두번째 행을 살펴보면 82분이나 먼저 출발한 항공편도 있다. 이런 소수의 데이터까지 포함시켜 통계에 혼란을 줄 필요가 있을까? 이런 이상값들로 통계 모델링을 혼란스럽게 하지 말아야 한다.

 

 

- 이상치(outlier) 제거 -

책에서 아웃라이어를 제거하는 방법으로는 두가지를 소개하지만, 2번째 방법을 권장하고 있다.

1. 출발지연 변수 자체를 바탕으로 데이터를 필터링 하는 방법

where dep_delay > -15

2. 항공편수를 바탕으로 필터링 하는 방법 (책에서 권장하는 방법)

where  numflights > 300

첫번째 방법은 입력된 데이터에 임계값을 부과하는 방법이고, '15분보다 더 일찍 출발하는 것'이 불합리하다고 '확신'하는 경우에만 사용할 수 있다. 반면에 두번쨰 방법은 특정 값이 얼마나 자주 관찰되느냐에 기반을 두고 판단을 하게 된다.

그렇다면 2번 방법을 따라가되, 300이라는 항공편의 숫자는 어떻게 설정하면 좋을까? 이는 3 시그마 규칙 ( three-sigma-rule) 지침에 따라 정해진다. 3 시그마 규칙 이란 일반적인 통계적 사고가 통용되는 정규분포에서 μ ± 1σ, μ ± 2σ, μ ± 3σ으로 구간을 나눠 대부분의 값이  μ ± 3σ 안으로 들어간다고 보는 경험적인 규칙(empirical rule)을 말한다.

< three-sigma-rule >

  해당 그림에 따라 임계값인  μ ± 3σ는 1/370이 되므로 numflights > 370 이 경계가 될 것이다. 이를 바탕으로 쿼리문을 다시 작성하고, 이번에는  탐색적 분석과 모델 개발을 병행하기 위해 Google Data-LAB에서 이어 살펴보자.

select
  DEP_DELAY,
  arrival_delay,
  stddev_arrival_delay,
  numflights
from
  (
  select
    DEP_DELAY,
    AVG(ARR_DELAY) AS arrival_delay,
  	STDDEV(ARR_DELAY) AS stddev_arrival_delay,
  	COUNT(ARR_DELAY) AS numflights
  from
    flights.tzcorr
  group by
    DEP_DELAY )
where
  numflights > 370
order by
  DEP_DELAY

 

- 구글 데이터랩에서 의사 결정 모델 개발 -

  빅쿼리와 다르게 Google Data Lab에서는 쿼리문으로 구성한 모델의 그래프를 그릴 수 있다는 이점이 있다. depdelayquery를 작성해 이를 데이터프레임화 하고, plot으로 그래프를 그리는 과정이다.

  ※  STDDEV는 입력된 데이터값들의 표준편차를 보여주는 GROUP함수의 종류이다.

import google.datalab.bigquery as bq
depdelayquery = """
SELECT * FROM (
  SELECT
    DEP_DELAY,
    AVG(ARR_DELAY) AS arrival_delay,
    STDDEV(ARR_DELAY) AS stddev_arrival_delay,
    COUNT(ARR_DELAY) AS numflights
  FROM
    `flights.tzcorr`
  GROUP BY
    DEP_DELAY )
WHERE
  numflights > 370
ORDER BY
  DEP_DELAY
"""
depdelay = bq.Query(depdelayquery).execute().result().to_dataframe()
depdelay[:5]

출력된 데이터 도표를 그래프화 해 보자. 전에는 seaborn을 이용했지만 pandas 자체에도 내장형의 도표기능이 있다.

( 원래 코드에서 그래프 크기를 좀더 확대하기 위해 figsize를 추가했다. )

ax = depdelay.plot(kind='line', x='DEP_DELAY', 
              y='arrival_delay', yerr='stddev_arrival_delay', figsize=(12,9))

< 데이터 도표를 바탕으로 그린 그래프 >

  도표를 보면 확실히 출발 지연과 도착 지연의 관계가 선형적이며, 그 차이에 해당하는 폭도 대략 10분정도로 일정한 것을 볼 수 있다. 이는 판다스 데이터프레임 표를 확인해도 대략 10±2 정도의 값들로 일정하게 분포한 것을 확인할 수 있다.

 

- 확률적 결정 임계값 -

  맨 처음 우리가 세운 가설은 15분 이상 도착지연될 확률이 30%면 회의를 취소한다는 것이였다. 도착 지연을 예측하기 위한 조건이 출발지연이므로 어떤 출발지연 상황에서 이런 상황(도착지연)이 생기는지 알아야 한다. 책에서는 각 출발지연에 대응하는 도착지연의 표준편차를 계산했다. 이는 도착지연이 정상적으로 분배되어있음을 전제로 한다.  아래 도표에서 붉은선과의 교차지점을 보면, 출발 지연이 13분 이상이면 15분 이상 지연될 확률이 30%이상임을 확인 할 수 있다.

import matplotlib.pyplot as plt
Z_30 = 0.52
depdelay['arr_delay_30'] = (Z_30 * depdelay['stddev_arrival_delay']) \
             + depdelay['arrival_delay']
plt.axhline(y=15, color='r')
ax = plt.axes()
depdelay.plot(kind='line', x='DEP_DELAY', y='arr_delay_30',
              ax=ax, ylim=(0,30), xlim=(0,30), legend=False ,figsize=(9,6))
ax.set_xlabel('Departure Delay (minutes)')
ax.set_ylabel('> 30% likelihood of this Arrival Delay (minutes)');

 

- 경험 확률 분포 함수 -

위의 case에서는 출발 지연된 각 항공편의 분포가 고르게 퍼져있다는 가정이 있었다. 이런 가정을 제외한 일반적인 상황은 어떻게 보면 좋을까? 우리는 이미 출발지연에 대한 적어도 370편 이상의 데이터를 확보하고 있다. 이를 통해 각 지연당 30번째의 백분위수를 구할 수 있다. 이는 APPROX_QUANTILES와 OFFSET의 조정으로 설정할 수 있다.

통계학적인 내용( 그린왈드와 칸나의 알고리즘 등.)이 다수 포함되어 있으므로,  관련 설명은 추후에 보강하기로 하겠다.  

import google.datalab.bigquery as bq
depdelayquery = """
SELECT
  DEP_DELAY,
  arrival_delay,
  numflights
FROM (
  SELECT
    DEP_DELAY,
    APPROX_QUANTILES(ARR_DELAY,
      101)[OFFSET(70)] AS arrival_delay,
    COUNT(ARR_DELAY) AS numflights
  FROM
    `flights.tzcorr`
  GROUP BY
    DEP_DELAY )
WHERE
  numflights > 370
ORDER BY
  DEP_DELAY
"""
depdelay = bq.Query(depdelayquery).execute().result().to_dataframe()

plt.axhline(y=15, color='r')
ax = plt.axes()
depdelay.plot(kind='line', x='DEP_DELAY', y='arrival_delay',
              ax=ax, ylim=(0,30), xlim=(0,30), legend=False, figsize=(15,8)) 
ax.set_xlabel('Departure Delay (minutes)')
ax.set_ylabel('> 30% likelihood of this Arrival Delay (minutes)');

여차저차해서 표준편자의 분포에 대한 가설을 제외하고 세운 임계 기준은 16분이다. 이는 다시 말해 항공편의 지연시간이 16분을 넘어가게 되면 15분 이상 늦게 도착할 확률이 30% 이상이다. 

 

< 실습 - 모델 평가 >

 

- 훈련과 테스트 -

import google.datalab.bigquery as bq
depdelayquery = """
SELECT
  DEP_DELAY,
  arrival_delay,
  numflights
FROM (
  SELECT
    DEP_DELAY,
    APPROX_QUANTILES(ARR_DELAY,
      101)[OFFSET(70)] AS arrival_delay,
    COUNT(ARR_DELAY) AS numflights
  FROM
    `flights.tzcorr` f
  JOIN
    `flights.trainday` t
  ON
    f.FL_DATE = t.FL_DATE
  WHERE
    t.is_train_day = 'True'
  GROUP BY
    DEP_DELAY )
WHERE
  numflights > 370
ORDER BY
  DEP_DELAY
"""
depdelay = bq.Query(depdelayquery).execute().result().to_dataframe()

plt.axhline(y=15, color='r')
ax = plt.axes()
depdelay.plot(kind='line', x='DEP_DELAY', y='arrival_delay',
              ax=ax, ylim=(0,30), xlim=(0,30), legend=False, figsize=(15,8))
ax.set_xlabel('Departure Delay (minutes)')
ax.set_ylabel('> 30% likelihood of this Arrival Delay (minutes)');

 

- 평가1 -

import google.datalab.bigquery as bq
evalquery = """
SELECT
  SUM(IF(DEP_DELAY < 16
      AND arr_delay < 15, 1, 0)) AS correct_nocancel,
  SUM(IF(DEP_DELAY < 16
      AND arr_delay >= 15, 1, 0)) AS wrong_nocancel,
  SUM(IF(DEP_DELAY >= 16
      AND arr_delay < 15, 1, 0)) AS wrong_cancel,
  SUM(IF(DEP_DELAY >= 16
      AND arr_delay >= 15, 1, 0)) AS correct_cancel
FROM (
  SELECT
    DEP_DELAY,
    ARR_DELAY
  FROM
    `flights.tzcorr` f
  JOIN
    `flights.trainday` t
  ON
    f.FL_DATE = t.FL_DATE
  WHERE
    t.is_train_day = 'False' )
"""
eval = bq.Query(evalquery).execute().result().to_dataframe()

print(eval['correct_nocancel'] /
      (eval['correct_nocancel'] + eval['wrong_nocancel']))
print(eval['correct_cancel'] / 
      (eval['correct_cancel'] + eval['wrong_cancel']))

 

 

- 평가2 -

import google.datalab.bigquery as bq
evalquery = """
SELECT
  SUM(IF(DEP_DELAY = 15
      AND arr_delay < 15, 1, 0)) AS correct_nocancel,
  SUM(IF(DEP_DELAY = 15
      AND arr_delay >= 15, 1, 0)) AS wrong_nocancel,
  SUM(IF(DEP_DELAY = 16
      AND arr_delay < 15, 1, 0)) AS wrong_cancel,
  SUM(IF(DEP_DELAY = 16
      AND arr_delay >= 15, 1, 0)) AS correct_cancel
FROM (
  SELECT
    DEP_DELAY,
    ARR_DELAY
  FROM
    `flights.tzcorr` f
  JOIN
    `flights.trainday` t
  ON
    f.FL_DATE = t.FL_DATE
  WHERE
    t.is_train_day = 'False' )
"""
eval = bq.Query(evalquery).execute().result().to_dataframe()

 

 

 

 

 

"Data Science on the Google Cloud Platform by Valliappa Lakshmanan (O'Reilly). Copyright 2018 Google Inc."

 

728x90