3단 분석법
순서 | 분석 | 단어 | 내용 |
1 | 정의 | 데이터셋
분할 | 주어진 데이터를 학습(training), 검증(validation), 테스트(test) 데이터셋으로 나누어 모델의 성능을 평가하고 일반화하기 위한 과정 |
2 | 알아야하는 이유 | 데이터셋
분할 | 모델을 학습할 때 과적합을 방지하고, 모델의 성능을 객관적으로 평가하며, 실제 데이터를 처리할 때 모델이 잘 일반화되는지 확인하기 위해서 |
3 | 동작방식 | 데이터셋
분할 | 1. 전체 데이터 수집
2. 학습 데이터 분할
3. 검증 데이터 분할
4. 테스트 데이터 분할
5. 랜덤 분할 |
정의
데이터셋
분할 | 주어진 데이터를 학습(training), 검증(validation), 테스트(test) 데이터셋으로 나누어 모델의 성능을 평가하고 일반화하기 위한 과정 |
데이터셋 분할은 주어진 데이터를 학습, 검증, 테스트 데이터셋으로 나누어 모델의 성능을 평가하고 일반화하기 위한 과정입니다.
이를 통해 모델이 새로운 데이터에서도 잘 작동할 수 있도록 합니다.
데이터셋 분할은 머신러닝 모델을 개발하면서 모델을 검증하는 데 있어 도움이 될 수 있습니다.
하지만, 오히려 검증 데이터가 없을 때 모델이 성능이 더 좋을 수도 있습니다.
데이터의 양
데이터셋이 충분히 큰 경우, 일부 데이터를 검증 데이터로 분할해도 모델의 성능을 평가할 수 있습니다.
하지만 데이터셋이 작은 경우, 검증 데이터를 따로 분리하면 트레이닝 데이터가 너무 적어져 모델 성능이 떨어질 수 있습니다.
모델의 복잡성
간단한 모델의 경우, 데이터 분할 없이도 충분한 성능을 보일 수 있습니다.
반면, 복잡한 모델일수록 과적합(overfitting)을 방지하기 위해 검증 데이터가 필요할 수 있습니다.
검증 데이터의 필요성
특정 프로젝트에서는 검증 데이터 없이도, 예를 들어 교차 검증(cross-validation)과 같은 기법을 통해 모델의 성능을 평가할 수 있습니다.
프로젝트의 특성에 따라, 실제 데이터로 테스트를 하거나 다른 평가 방법을 사용할 수도 있습니다.
무조건 트레이닝 데이터를 분할하여 검증 데이터를 만드는 것보다, 모델의 성능을 검증하면서 검증 데이터의 필요성을 판단하는 것이 중요합니다.
각 모델의 특성과 데이터셋의 크기, 모델의 복잡성 등을 고려하여 최적의 방법을 선택하는 것이 바람직합니다.
알아야하는 이유
데이터셋
분할 | 모델을 학습할 때 과적합을 방지하고, 모델의 성능을 객관적으로 평가하며, 실제 데이터를 처리할 때 모델이 잘 일반화되는지 확인하기 위해서 |
이유 | 설명 |
과적합 방지 | 모델이 학습 데이터에만 치우치지 않고, 새로운 데이터에도 잘 일반화되도록 합니다. |
성능 평가 | 모델의 성능을 객관적으로 평가할 수 있도록 합니다. |
일반화 확인 | 모델이 실제 데이터를 처리할 때 잘 일반화되는지 확인할 수 있습니다. |
하이퍼파라미터 튜닝 | 검증 데이터셋을 이용해 모델의 하이퍼파라미터를 최적화할 수 있습니다. |
비교 연구 | 다양한 모델 및 설정을 비교할 때 공정하게 성능을 평가할 수 있습니다. |
동작 방식
데이터셋
분할 | 1. 학습 데이터 분할
2. 검증 데이터 분할
3. 테스트 데이터 분할
4. 랜덤 분할 |
샘플 데이터셋을 생성하여 분할하는 4가지 방법에 대해 소개하는 방식으로 진행하겠습니다.
전체 데이터 수집
먼저, 필요한 라이브러리를 불러오고, 샘플 데이터를 생성합니다. 이 예제에서는 pandas 라이브러리를 사용하여 데이터프레임을 만듭니다.
# 필요한 라이브러리 불러오기
import pandas as pd
# 샘플 데이터 생성
data = {
'feature1': range(1, 101), # feature1은 1부터 100까지의 숫자
'feature2': range(101, 201), # feature2는 101부터 200까지의 숫자
'label': [1 if x % 2 == 0 else 0 for x in range(1, 101)] # label은 짝수이면 1, 홀수이면 0
}
df = pd.DataFrame(data) # 데이터프레임 생성
# 전체 데이터셋 크기 확인
print("전체 데이터셋 크기:", len(df))
Python
복사
•
pandas는 데이터 조작 및 분석을 위한 라이브러리입니다.
•
data 딕셔너리는 feature1, feature2, label 세 개의 키와 각 키에 대응하는 값으로 구성됩니다.
•
range(1, 101)은 1부터 100까지의 숫자 생성.
•
label은 짝수인 경우 1, 홀수인 경우 0으로 설정됩니다.
•
pd.DataFrame(data)는 data 딕셔너리를 데이터프레임으로 변환합니다.
데이터 프레임이 무엇인가요?
데이터프레임(DataFrame)은 pandas 라이브러리에서 제공하는 2차원 데이터 구조로, 엑셀 시트와 유사합니다.
행(row)과 열(column)로 구성되며, 다양한 형태의 데이터를 다루는 데 매우 유용합니다.
[1 if x % 2 == 0 else 0 for x in range(1, 101)] 어떤 코드인가요?
if x % 2 == 0 else 0 부분이 조건부 표현식입니다. 이는 x % 2 == 0 조건이 참일 때 1을 반환하고, 거짓일 때 0을 반환합니다.
List Comprehension 추가설명 : 위키독스1) 리스트 컴프리헨션
위와 같이 샘플 데이터셋을 생성하였습니다. 이제부터 분할을 해보도록 하겠습니다.
1. 학습 데이터 분할
전체 데이터셋의 60%를 학습 데이터로 분할합니다.
# 전체 데이터셋에서 학습 데이터 비율 설정
train_size = int(0.6 * len(df)) # 학습 데이터 비율 (60%)
# 학습 데이터 분할
train_data = df[:train_size] # 학습 데이터로 분할
# 학습 데이터셋 크기 확인
print("학습 데이터셋 크기:", len(train_data))
# train_data 형태 확인하기
print("train_data:", train_data) # 0 ~ 59
Python
복사
•
train_size는 전체 데이터셋의 60%를 의미합니다.
•
df[:train_size]는 데이터프레임의 처음 60%를 학습 데이터로 분할합니다.
◦
슬라이싱(Slicing): : 연산자는 슬라이싱을 나타내며, df[:train_size]는 데이터프레임의 행을 선택합니다.
print("train_data:", train_data) 결과
2. 검증 데이터 분할
나머지 데이터의 20%를 검증 데이터로 분할합니다.
# 전체 데이터셋에서 검증 데이터 비율 설정
validation_size = int(0.2 * len(df)) # 검증 데이터 비율 (20%)
# 검증 데이터 분할
validation_data = df[train_size:train_size + validation_size] # 검증 데이터로 분할 (60 ~ 79행 까지)
# 검증 데이터셋 크기 확인
print("검증 데이터셋 크기:", len(validation_data))
print("validation_data:", validation_data) # 60 ~ 79
Python
복사
•
validation_size는 전체 데이터셋의 20%를 의미합니다.
•
df[train_size:train_size + validation_size]는 학습 데이터 이후의 20%를 검증 데이터로 분할합니다.
"validation_data:", validation_data 결과
3. 테스트 데이터 분할
남은 데이터를 테스트 데이터로 분할합니다.
# 테스트 데이터 분할
test_data = df[train_size + validation_size:] # 테스트 데이터로 분할
# 테스트 데이터셋 크기 확인
print("테스트 데이터셋 크기:", len(test_data))
print("test_data:", test_data) # 80 ~ 99
Python
복사
•
나머지 20%의 데이터는 테스트 데이터로 사용됩니다.
•
df[train_size + validation_size:]는 학습 데이터와 검증 데이터 이후의 나머지 데이터를 테스트 데이터로 분할합니다.
"test_data:", test_data 결과
4. 랜덤 분할
데이터를 무작위로 섞어 학습, 검증, 테스트 데이터셋을 분할합니다.
# 필요한 라이브러리 불러오기
from sklearn.model_selection import train_test_split
# 데이터셋을 학습, 검증, 테스트 세트로 랜덤 분할 (60:20:20 비율)
train_data, temp_data = train_test_split(df, test_size=0.4, random_state=42) # 먼저 학습 데이터 분할
validation_data, test_data = train_test_split(temp_data, test_size=0.5, random_state=42) # 남은 데이터에서 검증 및 테스트 데이터 분할
# 각 데이터셋 크기 확인
print("학습 데이터셋 크기:", len(train_data))
print("검증 데이터셋 크기:", len(validation_data))
print("테스트 데이터셋 크기:", len(test_data))
Python
복사
•
train_test_split 함수는 데이터를 무작위로 섞어 주어진 비율로 분할합니다.
•
train_test_split(df, test_size=0.4, random_state=42)는 전체 데이터의 60%를 학습 데이터로, 40%를 임시 데이터(temp_data)로 분할합니다.
•
train_test_split(temp_data, test_size=0.5, random_state=42)는 임시 데이터를 다시 검증 데이터와 테스트 데이터로 50:50 비율로 분할합니다.
•
random_state=42는 무작위 분할을 재현 가능하게 하기 위한 시드 값입니다.
"train_data:", train_data 결과
"validation_data:", validation_data 결과
"test_data:", test_data 결과
코랩에서 동작하기 : Google Colab
알면 좋은 정보
Cross Validation (교차 검증)
교차 검증은 Training Data에서 일정 부분을 Validation Data로 분할해 여러 번 검증하는 것을 의미합니다.
위의 이미지는 일반적으로 많이 사용하는 K-Fold 교차 검증을 그림으로 표현한 것입니다.
K-Fold 교차 검증은 데이터셋을 K개의 폴드로 나누어 각 폴드를 한번씩 검증 데이터로 사용하고 나머지 폴드를 학습 데이터로 사용하는 방식입니다.
K Fold 교차 검증 과정
1.
데이터셋 분할
•
전체 데이터셋을 K개의 폴드로 나눕니다.
2.
모델 학습 및 검증
•
첫 번째 폴드를 검증 데이터로 사용하고, 나머지 폴드를 학습 데이터로 사용하여 모델을 학습시킵니다.
•
학습된 모델을 첫 번째 폴드로 검증합니다.
•
이 과정을 K번 반복하여 모든 폴드가 한 번씩 검증 데이터로 사용되도록 합니다.
3.
결과 통합
•
각 폴드에서의 검증 결과를 평균내어 최종 모델의 성능을 평가합니다.
장단점
장점 | 단점 |
모든 데이터를 검증에 사용하기 때문에 데이터셋의 특정 분할에 따른 편향을 줄일 수 있습니다. | K번의 학습과 검증을 반복해야 하므로 계산 비용이 많이 듭니다. |
학습과 검증에 모든 데이터를 사용하여 모델의 일반화 성능을 높일 수 있습니다. | 만약 데이터셋 자체가 한쪽으로 치우쳐 있다면, 교차 검증 결과가 왜곡될 수 있습니다. |
데이터 분할 비율
데이터셋을 분할할 때 일반적으로 70:15:15, 60:20:20 등의 비율을 사용합니다.
상황에 따라 다르게 조정할 수 있습니다.
K-Fold 교차 검증 예제
1. 라이브러리 설치 및 불러오기
먼저 필요한 라이브러리를 설치하고 불러옵니다.
# Scikit-Learn 라이브러리는 일반적으로 코랩에 기본 설치되어 있습니다.
# 만약 설치되어 있지 않다면 아래 주석을 제거하고 실행하세요.
# !pip install scikit-learn
import numpy as np
import pandas as pd
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score
Python
복사
2. 데이터 생성
간단한 샘플 데이터를 생성합니다.
# 샘플 데이터 생성
data = {
'feature1': range(1, 101), # 1부터 100까지의 숫자
'feature2': range(101, 201), # 101부터 200까지의 숫자
'label': [1 if x % 2 == 0 else 0 for x in range(1, 101)] # 짝수이면 1, 홀수이면 0
}
df = pd.DataFrame(data) # 데이터프레임 생성
# 특성(features)와 라벨(label) 분리
X = df[['feature1', 'feature2']]
y = df['label']
Python
복사
3. K-Fold 교차 검증 설정 및 수행
K-Fold 교차 검증을 설정하고 수행합니다.
# KFold 설정
kf = KFold(n_splits=5, shuffle=True, random_state=42)
# 결과를 저장할 리스트
accuracy_scores = []
# 각 폴드에 대해 학습 및 평가
for train_index, test_index in kf.split(X):
# 학습 데이터와 테스트 데이터 분할
X_train, X_test = X.iloc[train_index], X.iloc[test_index]
y_train, y_test = y.iloc[train_index], y.iloc[test_index]
# 간단한 모델: 예제에서는 feature1의 값이 짝수면 1, 홀수면 0으로 예측
y_pred = [1 if x % 2 == 0 else 0 for x in X_test['feature1']]
# 정확도 계산
accuracy = accuracy_score(y_test, y_pred)
accuracy_scores.append(accuracy)
# 각 폴드의 정확도 출력
for i, score in enumerate(accuracy_scores):
print(f"폴드 {i+1}의 정확도: {score:.2f}")
# 평균 정확도 출력
print(f"평균 정확도: {np.mean(accuracy_scores):.2f}")
Python
복사
결과
폴드 1의 정확도: 1.00
폴드 2의 정확도: 1.00
폴드 3의 정확도: 1.00
폴드 4의 정확도: 1.00
폴드 5의 정확도: 1.00
평균 정확도: 1.00
Python
복사
random_state=42가 가 무엇인가요?
난수 생성기의 초기값입니다. 특정 시드를 설정하면 난수 생성기는 항상 동일한 순서의 난수를 생성합니다.
사용이유
•
재현 가능성(Reproducibility): 실험이나 테스트를 반복할 때, 동일한 입력 데이터와 동일한 시드 값이 사용되면 항상 동일한 결과를 얻을 수 있습니다. 이는 결과를 검증하거나 문제를 디버그할 때 매우 유용합니다.
•
공정한 비교: 모델의 성능을 비교할 때, 동일한 데이터 분할과 동일한 조건을 보장하여 공정하게 비교할 수 있습니다.
예제
아래는 랜덤 시드를 설정하지 않았을 때와 설정했을 때의 차이를 보여주는 예제입니다.
랜덤 시드를 설정하지 않은 경우
import numpy as np
# 난수 생성 (랜덤 시드 없음)
random_numbers1 = np.random.rand(5)
random_numbers2 = np.random.rand(5)
print("Random numbers without seed (first call):", random_numbers1)
print("Random numbers without seed (second call):", random_numbers2)
Python
복사
Random numbers without seed (first call): [0.51718097 0.31576424 0.03235194 0.44730853 0.58715261]
Random numbers without seed (second call): [0.23335989 0.09808566 0.41867871 0.69419256 0.89127382]
Python
복사
이 경우, random_numbers1과 random_numbers2는 각각 다른 값을 가집니다.
랜덤 시드를 설정한 경우
import numpy as np
# 난수 생성 (랜덤 시드 설정)
np.random.seed(42)
random_numbers1 = np.random.rand(5)
np.random.seed(42)
random_numbers2 = np.random.rand(5)
print("Random numbers with seed (first call):", random_numbers1)
print("Random numbers with seed (second call):", random_numbers2)
Python
복사
Random numbers with seed (first call): [0.37454012 0.95071431 0.73199394 0.59865848 0.15601864]
Random numbers with seed (second call): [0.37454012 0.95071431 0.73199394 0.59865848 0.15601864]
Python
복사
이 경우, random_numbers1과 random_numbers2는 동일한 값을 가집니다. 이는 두 번째 호출에서도 동일한 시드를 사용하여 동일한 난수를 생성했기 때문입니다.
iloc()는 무엇인가요?
iloc는 pandas 라이브러리에서 제공하는 인덱싱 방법 중 하나로, 위치 기반 인덱싱을 의미합니다. 이는 데이터프레임의 행과 열을 정수 인덱스를 사용하여 선택할 수 있게 해줍니다.
import pandas as pd
# 샘플 데이터프레임 생성
data = {
'feature1': [10, 20, 30, 40, 50],
'feature2': [60, 70, 80, 90, 100],
'label': [0, 1, 0, 1, 0]
}
df = pd.DataFrame(data)
# 위치 기반 인덱싱 사용 예제
print(df)
print("-----")
print(df.iloc[0]) # 첫 번째 행 선택
print("-----")
print(df.iloc[:, 1]) # 모든 행에서 두 번째 열 선택
print('-----')
print(df.iloc[1:3]) # 두 번째와 세 번째 행 선택
Python
복사
결과
feature1 feature2 label
0 10 60 0
1 20 70 1
2 30 80 0
3 40 90 1
4 50 100 0
-----
feature1 10
feature2 60
label 0
Name: 0, dtype: int64
-----
0 60
1 70
2 80
3 90
4 100
Name: feature2, dtype: int64
-----
feature1 feature2 label
1 20 70 1
2 30 80 0
Python
복사
코랩에서 동작하기 : Google Colab
미니퀘스트
1번 미니퀘스트 - 데이터셋 분할 실습
데이터셋을 랜덤으로 분할하고 각 데이터셋의 크기를 출력하여 분할이 제대로 이루어졌는지 확인해 보세요.
문제 설명
1.
데이터 로드
•
샘플 데이터셋을 로드합니다.
•
예제데이터
# 샘플 데이터 생성
data = {
'feature1': range(1, 101),
'feature2': range(101, 201),
'label': [1 if x % 2 == 0 else 0 for x in range(1, 101)]
}
df = pd.DataFrame(data)
Python
복사
2.
데이터셋 분할
•
데이터를 학습, 검증, 테스트 데이터셋으로 나눕니다.
3.
결과 확인
•
각 데이터셋의 크기를 출력하여 분할 결과를 확인합니다.
코드
# 필요한 라이브러리 불러오기
import pandas as pd
from sklearn.model_selection import train_test_split
# 샘플 데이터 생성
data = {
'feature1': range(1, 101),
'feature2': range(101, 201),
'label': [1 if x % 2 == 0 else 0 for x in range(1, 101)]
}
df = pd.DataFrame(data)
# 전체 데이터셋 크기 확인
print("전체 데이터셋 크기:", len(df))
# 데이터셋을 학습, 검증, 테스트 세트로 분할 (60:20:20 비율)
train_data, temp_data = train_test_split(df, test_size=0.4, random_state=42)
validation_data, test_data = train_test_split(temp_data, test_size=0.5, random_state=42)
# 각 데이터셋 크기 출력
print("학습 데이터셋 크기:", len(train_data))
print("검증 데이터셋 크기:", len(validation_data))
print("테스트 데이터셋 크기:", len(test_data))
Python
복사
결과 예시
•
전체 데이터셋 크기: 100
•
학습 데이터셋 크기: 60
•
검증 데이터셋 크기: 20
•
테스트 데이터셋 크기: 20
결과 설명
•
전체 데이터셋 크기
◦
주어진 데이터셋의 총 샘플 수는 100개입니다.
•
학습 데이터셋 크기
◦
전체 데이터셋의 60%인 60개 샘플이 학습 데이터로 할당되었습니다. 이 데이터는 모델을 학습시키는 데 사용됩니다.
•
검증 데이터셋 크기
◦
나머지 데이터의 20%, 즉 20개 샘플이 검증 데이터로 할당되었습니다. 이 데이터는 학습 과정 중 모델의 성능을 평가하고 튜닝하는 데 사용됩니다.
•
테스트 데이터셋 크기
◦
최종적으로 남은 20개 샘플이 테스트 데이터로 할당되었습니다. 이 데이터는 모델의 최종 성능을 객관적으로 평가하는 데 사용됩니다.
코드 설명
2번 미니퀘스트 - 데이터 분할과 성능 평가
간단한 모델을 학습하고, 검증 및 테스트 데이터셋을 사용하여 모델의 성능을 평가해보세요.
문제 설명
1.
데이터 로드 및 분할
•
데이터를 학습, 검증, 테스트 데이터셋으로 분할합니다.
•
예제데이터
# 샘플 데이터 생성
data = {
'feature1': range(1, 101),
'feature2': range(101, 201),
'label': [1 if x % 2 == 0 else 0 for x in range(1, 101)]
}
df = pd.DataFrame(data)
Python
복사
2.
모델 학습
•
학습 데이터셋을 사용하여 간단한 모델을 학습합니다.
3.
모델 평가
•
검증 데이터셋을 사용하여 모델의 성능을 평가합니다.
4.
최종 평가
•
테스트 데이터셋을 사용하여 모델의 최종 성능을 평가합니다.
코드
# 필요한 라이브러리 불러오기
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# 샘플 데이터 생성
data = {
'feature1': range(1, 101),
'feature2': range(101, 201),
'label': [1 if x % 2 == 0 else 0 for x in range(1, 101)]
}
df = pd.DataFrame(data)
# 데이터셋을 학습, 검증, 테스트 세트로 분할 (60:20:20 비율)
train_data, temp_data = train_test_split(df, test_size=0.4, random_state=42)
validation_data, test_data = train_test_split(temp_data, test_size=0.5, random_state=42)
# 학습 데이터와 레이블 분리
X_train = train_data[['feature1', 'feature2']]
y_train = train_data['label']
X_validation = validation_data[['feature1', 'feature2']]
y_validation = validation_data['label']
X_test = test_data[['feature1', 'feature2']]
y_test = test_data['label']
# 모델 학습
model = LogisticRegression()
model.fit(X_train, y_train)
# 검증 데이터로 성능 평가
y_val_pred = model.predict(X_validation)
val_accuracy = accuracy_score(y_validation, y_val_pred)
print("검증 데이터 정확도:", val_accuracy)
# 테스트 데이터로 최종 성능 평가
y_test_pred = model.predict(X_test)
test_accuracy = accuracy_score(y_test, y_test_pred)
print("테스트 데이터 정확도:", test_accuracy)
Python
복사
결과 예시
•
검증 데이터 정확도: 0.55
•
테스트 데이터 정확도: 0.5
결과 설명
•
검증 데이터 정확도
◦
검증 데이터셋을 사용하여 모델의 성능을 평가한 결과, 정확도는 0.55(55%)입니다. 이는 모델이 검증 데이터셋에서 55%의 정확도로 예측했음을 의미합니다.
•
테스트 데이터 정확도
◦
테스트 데이터셋을 사용하여 모델의 최종 성능을 평가한 결과, 정확도는 0.5(50%)입니다. 이는 모델이 테스트 데이터셋에서 50%의 정확도로 예측했음을 의미합니다.
결과 분석
1.
검증 데이터 정확도가 55%로, 데이터셋이 무작위로 분할된 경우 모델이 검증 데이터에 대해 과적합 되지 않았음을 나타냅니다.
그러나, 정확도가 높지 않으므로 모델의 성능이 그다지 좋지 않음을 시사합니다.
2.
테스트 데이터 정확도가 50%로, 모델이 새로운 데이터에 대해 예측할 때 동전 던지기와 같은 수준의 성능을 보이고 있습니다.
이는 모델이 학습 데이터에서 충분히 학습하지 못했거나, 단순한 모델로 인해 복잡한 패턴을 제대로 학습하지 못했기 때문일 수 있습니다.
코드 설명
미니퀘스트 답안지
ⓒ 2024 startupcode. 모든 권리 보유. 무단 복제 금지.