< 실습 - 품질 제어 >
- 이상치(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분이나 먼저 출발한 항공편도 있다. 이런 소수의 데이터까지 포함시켜 통계에 혼란을 줄 필요가 있을까? 이런 이상값들로 통계 모델링을 혼란스럽게 하지 말아야 한다.
- 이상치(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)을 말한다.
해당 그림에 따라 임계값인 μ ± 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."
'[Data Engineering] > [Gloud-GCP]' 카테고리의 다른 글
[GCP] 6-2. Quantization using Spark SQL (0) | 2020.03.05 |
---|---|
[GCP] 6-1. Dataproc cluster, bayes classification (0) | 2020.03.04 |
[GCP] 5-2. Cloud Data LAB (4) | 2020.02.24 |
[GCP] 5-1. Bigquery, Data Loading (0) | 2020.02.19 |
[GCP] 4-2. Stream Processing (2) | 2020.02.19 |