데이터·데이터전처리

[데이터 전처리 07] - 데이터의 누수"Data Leakage"를 바로 잡자!

데이터요리사 2021. 11. 30. 17:45

안녕하세요. 데이터 요리사, 루나입니다.

데이터 누수(Data leakage) 현상은 학습모델에 성능을 높이기 위해서

며칠 밤샘하다가 이것저것하다가 저지르기 쉬운 현상 중 하나입니다. 

 

모델의 성능이 갑자기 너무 좋아졌다? 

한번에? 갑자기? 이래도 되는거야?

데이터 누수를 한 번 의심해보세요.

 

데이터 누수를 막기 위해서는 대단한 수식이 적용된 전처리기법을 적용해야하는 것도 아니고,

닭이 먼저냐 데이터의 인과관계를 깊이있게 고민하는 과정이 필요합니다.

 

 

 

1 예제로 이해하기(1)! - Target leakage

캐글의 유명한 대회중 하나인 Bike sharing demand의 데이터를 예로 들어볼께요.

이 대회는  워싱턴 DC의 Capital Bikeshare 프로그램에서 사용할

자전거 대여 수요량을 얼마나 잘 예측하는지 겨루는 대회입니다.

데이터 셋으로는 날짜/시간별 요일, 휴일여부, 온도, 습도 등의 날씨정보와

회원/비회원 여부에 따른 대여량 정보가 포함되어있습니다. 

 

이 대회는 시간별 자전거의 총 대여량(count)을 구해야합니다.

Data Fields

datetime - hourly date + timestamp  
season -  1 = spring, 2 = summer, 3 = fall, 4 = winter 
holiday - whether the day is considered a holiday
workingday - whether the day is neither a weekend nor holiday
weather - 1: Clear, Few clouds, Partly cloudy, Partly cloudy
2: Mist + Cloudy, Mist + Broken clouds, Mist + Few clouds, Mist
3: Light Snow, Light Rain + Thunderstorm + Scattered clouds, Light Rain + Scattered clouds
4: Heavy Rain + Ice Pallets + Thunderstorm + Mist, Snow + Fog 
temp - temperature in Celsiusatemp - "feels like" temperature in Celsius
humidity - relative humiditywindspeed - wind speed
casual - number of non-registered user rentals initiated
registered - number of registered user rentals initiated
count - number of total rentals

 

그런데 여기서 casual, registered 이 두 변수를 눈여겨봐주세요. 

casual은 비회원의 자전거 대여량이고, registered는 회원의 자전거 대여량입니다.

즉 비회원(casual) + 회원(registered) = 총 대여량(count)이 되는 것입니다.  

 

비회원/회원의 자전거 대여량(casual/registered)을 더해서 총 대여량(count)을 알 수 있는데, 

이 비회원/회원의 자전거 대여량(casual/registered)을 독립변수로 사용한다면 당연히 좋은 결과가 나올 수 밖에 없겠죠.

 

그리고 예측모델을 활용하고자 하는 시점에는 값을 넣을 수 없어서 곤란한 상황이 생길테구요.

 

2 예제로 이해하기(2)! - Target leakage

데이터 누출은 학습용 데이터에는 포함되어 있지만 모델을 활용하여 예측할 시점에는 해당 정보를 사용할 수 없을 때 발생합니다. 

다음과 같은 개인정보가 존재할 때, 이 사람이 코로나 확진을 받은 적이 있는지 여부를 예측한다고 가정해봅시다.

 

>> 이름, 성별, 나이, 거주지, 직업, 백신접종여부, 코로나 검진키트 사용여부, 자가격리기간, 코로나확진자 지원금 수령여부

 

여기서 데이터 누출의 냄새가 나지 않나요? 

'코로나확진자 지원금'은 확진을 받은 사람만이 받을 수 있는 값이니 이 값을 피처(feature)로 사용하면 당연히 모델 예측도는 올라가겠죠. 물론 확진자 중에 지원금을 받지 않은 사람이 존재할 수 있겠지만, 피처간의 인과관계를 고민해보았을 때 이 값을 사용하는 것은 바람직하지 않습니다.

 

이미지출처 - https://www.kaggle.com/alexisbcook/data-leakage

 

 

3 예제로 이해하기(3) - Train-Test Contamination

학습 진행 시 학습용 데이터와 테스트용 데이터, 검증용 데이터로 분할을 진행합니다.

데이터 분할을 진행하는 이유는, 데이터를 덩어리로 구분지어서 덩어리마다 목적을 다르게 활용하려고 하는 것이죠. 학습 모델을 실제로 활용할 시점에 어떤 형태의 데이터가 발생할지 모르니까, 일부를 뗴어서 '이건 없는거다' 생각하고 학습을 시키는거죠.

 

그런데 전처리 진행 중에  '이건 없는거다'라고 아예 떼 놓지 않고 함께 사용하는 경우가 존재합니다. 이렇게 말이죠.

X = scaler.fit_transform(X)
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.3, random_state=42)


이 경우의 문제점은 검증용 데이터의 정보가 학습용 데이터에 스며들 수 있다(leakage)는 것입니다. 예를 들어서 학습데이터는 0부터 10까지의 숫자로 구성되어있었는데, 검증용 데이터에는 7부터 13까지의 숫자로 구성되어있었다고 가정해봅시다. 위의 코드에서 사용한 scaler가 MinMaxScaler라면 데이터 분할을 하고 변환을 하느냐, 분할 이후에 변환을 하느냐에 따라 결과가 달라지겠죠. 

 

그렇기 때문에 데이터 분할을 한 이후에 각각에 대해서 전처리를 수행하는 것이 데이터 누수를 예방하는 방법입니다.

X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.3, random_state=42)

X_train = scaler.fit_transform(X_train) 
X_valid = scaler.transform(X_valid)

 

데이터 누수는 보완할 수 있지만, 학습 할 때 0~10만 공부하고 검증은 7~13으로 하는건 억울한거 아니냐구요? 그래서 우리가 데이터의 역할을 번갈아가면서 사용하는 교차검증(Cross validation)같은 작업을 수행하면서 다양한 경우에 대해서 충분히 학습하는 기법을 활용하는 것입니다.

 

 

함께 보면 좋은 글

 


※ 이 글의 내용을 상업적으로 무단 활용, 편집하는 것은 금지하고 있습니다. 강의, 출판 등 상업적 이용이 필요하신 경우, 문의 바랍니다.

728x90