Categories: R

R에서 데이터 분할 (train_test_split() 대신 sample())

안녕하세요, 여러분! 데이터 분석을 하다 보면 항상 마주치는 중요한 단계, 바로 데이터 분할에 대해 이야기해보려고 해요.

R에서 머신러닝 모델을 만들 때 흔히 `train_test_split()` 함수를 많이 사용하시죠? 저도 그랬어요! 하지만 오늘은 좀 더 자유롭게 데이터를 다룰 수 있는 `sample()` 함수를 소개해 드리려고 합니다.

`sample()` 함수를 이용하면 `train_test_split()`보다 더욱 유연하게 데이터 샘플링을 할 수 있어요. 데이터 샘플링의 기본 원리를 이해하고, `sample()` 함수를 활용하여 데이터를 원하는 대로 나눠보는 재미를 느껴보세요!

`train_test_split()`과 비교하며 실제 데이터 적용 예시까지 함께 살펴볼 거예요. 자, 그럼 이제 흥미진진한 R의 세계로 함께 떠나볼까요?

 

 

데이터 샘플링의 기본 원리

데이터 분석, 특히 머신러닝에서 믿음직한 모델을 만들려면 데이터 샘플링이 얼마나 중요한지 아시나요? 마치 요리할 때 좋은 재료가 맛있는 음식을 만드는 기본이 되는 것처럼요! 데이터 샘플링은 전체 데이터에서 일부를 뽑아 분석하는 과정인데, 이때 ‘어떻게’ 뽑느냐가 정말 중요해요. 잘못 뽑으면 엉뚱한 결과가 나올 수도 있거든요! 마치 딸기 한 조각만 맛보고 케이크 전체가 맛있다고 판단하는 것과 같아요.

대표성

자, 그럼 데이터 샘플링의 기본 원리를 좀 더 깊이 파고들어 볼까요? 가장 중요한 건 바로 대표성입니다. 샘플이 전체 데이터의 특징을 잘 반영해야 한다는 거죠. 예를 들어, 대한민국 국민들의 평균 키를 알고 싶다고 해 봅시다. 농구 선수들만 모아서 키를 재면 당연히 평균 키가 높게 나오겠죠? 이건 대표성이 떨어지는 샘플이기 때문이에요. 전국 각지, 다양한 연령대의 사람들을 골고루 뽑아야 신뢰할 수 있는 결과를 얻을 수 있답니다.

샘플링 방법

샘플링 방법도 여러 가지가 있어요.

랜덤 샘플링(Random Sampling)

랜덤 샘플링(Random Sampling)은 말 그대로 무작위로 샘플을 추출하는 방법이에요. 제비뽑기를 생각하면 쉽겠죠? 각 데이터가 뽑힐 확률이 모두 동일해서, 편향 없는 결과를 얻을 수 있다는 장점이 있어요. 하지만 데이터의 특성에 따라 특정 그룹이 과소 표현될 수도 있다는 점을 염두에 둬야 해요. 예를 들어 1000명 중 여성이 10명뿐이라면, 랜덤 샘플링으로 100명을 뽑았을 때 여성이 한 명도 포함되지 않을 가능성도 있겠죠?

계층적 샘플링(Stratified Sampling)

이런 문제를 해결하기 위해 계층적 샘플링(Stratified Sampling)을 사용할 수 있어요. 전체 데이터를 여러 그룹(계층)으로 나눈 후, 각 그룹에서 일정 비율로 샘플을 추출하는 방법이에요. 앞선 예시에서 여성이 10명, 남성이 990명이라면, 100명의 샘플을 뽑을 때 여성 1명, 남성 99명을 뽑는 식이죠. 이렇게 하면 각 그룹의 특성이 샘플에 잘 반영될 수 있답니다.

클러스터 샘플링(Cluster Sampling)

또 다른 방법으로는 클러스터 샘플링(Cluster Sampling)이 있어요. 전체 데이터를 여러 개의 클러스터로 나눈 후, 몇 개의 클러스터를 선택해서 그 안의 데이터를 모두 샘플로 사용하는 거죠. 예를 들어 전국 초등학생들의 독서량을 조사한다고 할 때, 몇 개의 학교를 무작위로 선택하고 그 학교 학생들 전체를 조사하는 방식이에요. 클러스터 샘플링은 비용과 시간을 절약할 수 있다는 장점이 있지만, 선택된 클러스터가 전체를 대표하지 못할 위험도 있으니 주의해야 해요!

시스템 샘플링(Systematic Sampling)

마지막으로, 시스템 샘플링(Systematic Sampling)은 일정 간격으로 데이터를 추출하는 방법이에요. 예를 들어 1000개의 데이터에서 100개를 뽑고 싶다면, 10번째 데이터마다 하나씩 뽑는 거죠. 간단하고 효율적이지만, 데이터에 주기적인 패턴이 있는 경우 편향된 결과를 얻을 수 있으니 조심해야 해요.

샘플링 기법 활용의 중요성

이렇게 다양한 샘플링 기법들을 상황에 맞게 잘 활용하는 것이 정말 중요해요! 데이터의 특징과 분석 목적을 고려해서 가장 적절한 방법을 선택해야 정확하고 의미 있는 결과를 얻을 수 있답니다. 다음에는 `sample()` 함수를 R에서 어떻게 활용하는지 자세히 알아볼 거예요. 기대해 주세요!

 

sample() 함수 활용하기

자, 이제 R의 sample() 함수를 제대로 파헤쳐 볼까요? 이 함수, 생각보다 훨씬 강력하고 유용한 도구랍니다! 마치 마법의 지팡이처럼 데이터를 이리저리 섞어서 원하는 만큼 쏙쏙 뽑아낼 수 있어요. 마치 요리할 때 필요한 재료만 쏙쏙 골라내는 것처럼 말이죠! ^^

sample() 함수의 기본적인 구조는 놀랍도록 간단해요. sample(x, size, replace = FALSE, prob = NULL) 이렇게 생겼답니다. 복잡해 보인다고요? 전혀 그렇지 않아요! 하나씩 뜯어보면 금방 이해할 수 있을 거예요.

sample() 함수의 인자

  • x: 여기에는 우리가 샘플을 추출할 데이터, 즉 전체 집합을 넣어줍니다. 1부터 100까지의 숫자, 아니면 “사과”, “바나나”, “포도” 같은 문자열, 뭐든지 가능해요! 마치 냉장고에서 뭘 꺼낼지 고르는 것과 같아요.
  • size: 이 부분에는 뽑아낼 샘플의 크기를 지정합니다. 100개 중에 10개만 뽑고 싶다면 size = 10 이렇게 써주면 된답니다. 참 쉽죠?
  • replace: 이건 좀 재밌는 부분인데요, 복원 추출을 할지 말지를 결정하는 옵션이에요. replace = TRUE로 설정하면, 한번 뽑은 데이터를 다시 넣고 또 뽑을 수 있어요! 마치 마법의 주머니처럼 같은 숫자나 문자열이 여러 번 나올 수도 있다는 거죠. 기본값은 FALSE니까, 한 번 뽑은 데이터는 다시 뽑히지 않아요. 뽑기를 할 때 뽑은 것을 다시 넣을지 말지 정하는 것과 같네요!
  • prob: 이 옵션을 사용하면 각 데이터가 뽑힐 확률을 다르게 설정할 수 있어요. 예를 들어, 1은 50% 확률로, 2는 30% 확률로, 3은 20% 확률로 뽑히도록 설정할 수 있답니다. 마치 뽑기 상자에 특정 숫자가 더 많이 들어있는 것과 같은 효과를 낼 수 있죠! 신기하지 않나요?

자, 그럼 이제 실제로 sample() 함수를 어떻게 활용하는지 몇 가지 예시를 통해 알아볼까요?

sample() 함수 활용 예시

1. 1부터 100까지의 숫자 중 랜덤으로 5개 뽑기 (비복원)

sample(1:100, 5)

이 코드를 실행하면 1부터 100까지의 숫자 중 랜덤으로 5개의 숫자가 뽑힙니다. 매번 실행할 때마다 다른 숫자들이 뽑히는 것을 볼 수 있을 거예요! 마치 로또 번호를 뽑는 것 같죠?!

2. “apple”, “banana”, “cherry” 중 랜덤으로 2개 뽑기 (복원)

sample(c("apple", "banana", "cherry"), 2, replace = TRUE)

이 코드는 “apple”, “banana”, “cherry” 중 랜덤으로 2개의 과일을 뽑아줍니다. replace = TRUE로 설정했기 때문에 같은 과일이 두 번 뽑힐 수도 있어요. 마치 과일 바구니에서 눈을 감고 두 번 과일을 집는 것과 같네요!

3. 1부터 5까지의 숫자 중 랜덤으로 3개 뽑기 (각 숫자의 확률 다르게 설정)

sample(1:5, 3, prob = c(0.1, 0.2, 0.3, 0.2, 0.2))

이 코드는 1부터 5까지의 숫자 중 랜덤으로 3개의 숫자를 뽑는데, 각 숫자가 뽑힐 확률을 다르게 설정했어요. 3이 뽑힐 확률이 가장 높고, 1이 뽑힐 확률이 가장 낮답니다. 마치 뽑기 상자에 3이 적힌 뽑기가 가장 많이 들어있는 것과 같죠!

sample() 함수는 정말 다양한 상황에서 활용할 수 있어요. 데이터 분석에서는 훈련 데이터와 테스트 데이터를 나눌 때, 시뮬레이션에서는 랜덤 이벤트를 생성할 때, 심지어 게임 개발에서 랜덤 아이템을 생성할 때도 사용할 수 있답니다! 정말 만능 함수라고 할 수 있겠죠? 이 함수 하나만 잘 알아두면 데이터 분석의 세계가 훨씬 넓어질 거예요! 앞으로도 sample() 함수를 적극 활용해서 데이터 분석의 마법사가 되어보세요! 화이팅!

 

train_test_split()과의 비교

자, 이제 sample() 함수를 봤으니, 익숙한 train_test_split()과 비교를 안 해볼 수 없겠죠? 둘 다 데이터를 나누는 역할을 하지만, 속사정을 들여다보면 미묘한 차이들이 숨어있답니다. 마치 쌍둥이처럼 보이지만 성격이 다른 것처럼요! ^^

train_test_split()의 장점

train_test_split()은 scikit-learn 라이브러리에서 제공하는 함수로, 사용하기 편리하다는 장점이 있어요. 데이터를 무작위로 섞어서 지정된 비율로 훈련 세트와 테스트 세트를 뚝딱! 나눠주죠. 보통 7:3이나 8:2 비율로 나누는 경우가 많잖아요? 그럴 때 test_size 파라미터에 0.3이나 0.2를 넣어주면 간단하게 해결돼요. 층화 추출(Stratified Sampling)도 지원해서, 클래스 비율을 유지하면서 데이터를 나눌 수 있다는 것도 큰 장점이에요. 불균형 데이터를 다룰 때 특히 유용하죠!

sample()의 장점

반면 sample() 함수는 좀 더 유연하게 사용할 수 있다는 매력이 있어요. train_test_split()처럼 단순히 비율만 지정하는 게 아니라, 훈련 세트의 크기를 직접 정할 수 있거든요. 예를 들어 전체 데이터의 80%를 훈련 세트로 사용하고 싶다면 n = len(data) * 0.8 이렇게 지정하면 돼요. 간단하죠? 게다가 replace = True 옵션을 사용하면 복원 추출도 가능해요! 부트스트래핑(Bootstrapping) 같은 기법을 적용할 때 아주 유용하답니다.

표로 정리한 두 함수의 비교

표로 정리해보면 이렇게 돼요:

기능 train_test_split() sample()
라이브러리 scikit-learn base R
분할 방식 비율 지정 크기 또는 비율 지정
층화 추출 지원 지원하지 않음 (직접 구현 필요)
복원 추출 지원하지 않음 지원 (replace = True)
셔플링 기본적으로 수행 기본적으로 수행
사용 편의성 매우 높음 높음
유연성 다소 낮음 높음

train_test_split() 사용 시 장점

train_test_split()빠르고 간편하게 데이터를 나누고 싶을 때, 특히 층화 추출이 필요한 경우에 사용하면 좋아요.

sample() 사용 시 장점

반면 sample() 함수는 좀 더 세밀하게 훈련 세트의 크기를 조절하고 싶거나, 복원 추출이 필요한 경우, 그리고 층화 추출을 직접 구현하고 싶을 때! 유용하게 쓸 수 있답니다.

각 함수의 활용 예시

예를 들어, 10,000개의 데이터에서 7,500개를 훈련 세트로, 나머지 2,500개를 테스트 세트로 사용하고 싶다고 해봐요. train_test_split()을 사용하면 test_size=0.25로 지정하면 되지만, 만약 정확히 7,500개를 훈련 세트로 사용해야 한다면 sample() 함수가 더 적합해요. n = 7500으로 직접 지정할 수 있으니까요!

또 다른 예시로, 5-fold 교차 검증을 수행한다고 생각해 봐요. train_test_split()을 반복적으로 사용해서 데이터를 5개의 fold로 나눌 수도 있지만, sample() 함수를 사용하면 각 fold의 크기를 정확하게 제어하면서 데이터를 나눌 수 있어 더욱 편리해요.

sample() 사용 시 주의사항

하지만 sample() 함수를 사용할 때 주의할 점도 있어요! 바로 층화 추출을 직접 구현해야 한다는 점인데요. train_test_split()stratify 파라미터 하나로 간단하게 층화 추출을 할 수 있지만, sample() 함수는 그렇지 않아요. 각 클래스별로 sample() 함수를 적용하고, 그 결과를 합쳐야 하죠. 조금 번거롭지만, 직접 구현하면 데이터 분포를 더욱 세밀하게 제어할 수 있다는 장점도 있어요!

결론

결국 어떤 함수를 사용할지는 데이터의 특성과 분석 목적에 따라 결정해야 해요. train_test_split()은 빠르고 편리하지만 유연성이 떨어지고, sample() 함수는 유연하지만 층화 추출을 직접 구현해야 하는 번거로움이 있죠. 두 함수의 장단점을 잘 이해하고 상황에 맞게 적절한 함수를 선택하는 것이 중요해요! 마치 요리할 때 재료에 따라 다른 칼을 사용하는 것과 같은 이치겠죠?

데이터 분석은 마치 탐험과 같아서, 정해진 길만 있는 게 아니에요. 다양한 도구와 기법들을 활용해서 자신만의 길을 개척해 나가는 재미가 쏠쏠하답니다! sample() 함수와 train_test_split() 함수도 그 여정에서 든든한 동반자가 되어줄 거예요. 두 함수를 적절히 활용해서 데이터 분석의 세계를 마음껏 탐험해 보세요! 화이팅! ^^!

 

실제 데이터 적용 예시

자, 이제 sample() 함수를 활용해서 실제 데이터를 어떻게 분할하는지, train_test_split()과 비교하며 자세히 알아볼까요? 두근두근! ✨ 데이터 과학 프로젝트에서 가장 흔하게 마주치는 데이터셋 중 하나인 iris 데이터를 사용해보겠습니다. R에 기본적으로 내장되어 있어서 쉽게 불러와서 사용할 수 있답니다! 😊

iris 데이터 소개

먼저, iris 데이터를 간단히 살펴보면, 150개의 관측치와 5개의 변수(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width, Species)로 이루어져 있어요. 우리의 목표는 꽃잎과 꽃받침의 크기를 기반으로 붓꽃의 종류를 예측하는 모델을 만드는 거예요. 흥미진진하죠?! 😄

`sample()` 함수를 사용한 데이터 분할

sample() 함수를 사용해서 데이터를 7:3 비율로 훈련 데이터와 테스트 데이터로 나눠봅시다. 전체 데이터의 70%인 105개의 관측치를 훈련 데이터로, 나머지 30%인 45개의 관측치를 테스트 데이터로 사용할 거예요.

# 랜덤 시드 설정! 재현 가능성을 위해 꼭 필요해요!
set.seed(123)

# 전체 데이터 개수
n <- nrow(iris)

# 훈련 데이터 인덱스 추출 (70%)
train_idx <- sample(1:n, size = 0.7 * n)

# 훈련 데이터
train_data <- iris[train_idx, ]

# 테스트 데이터
test_data <- iris[-train_idx, ]

# 잘 나뉘었는지 확인!
dim(train_data) # 105  5
dim(test_data) # 45  5

이렇게 sample() 함수를 이용하면 간단하게 데이터를 원하는 비율로 나눌 수 있어요. 참 쉽죠? 😉 train_idx를 생성할 때 1:n은 전체 데이터의 행 번호를 의미하고, size = 0.7 * n은 전체 데이터의 70%를 샘플링하도록 지정한 부분이에요. -train_idx를 사용하면 train_idx에 포함되지 않은 나머지 행 번호를 선택할 수 있답니다. 이 부분이 테스트 데이터가 되는 거죠!

`createDataPartition()` 함수를 사용한 데이터 분할

이제 같은 데이터를 caret 패키지의 createDataPartition() 함수를 사용해서 7:3 비율로 나눠볼게요. createDataPartition()은 클래스 비율을 유지하면서 데이터를 분할하는 데 유용한 함수랍니다! 특히, 분류 문제를 다룰 때 아주 효과적이죠. 👍

library(caret)

# 랜덤 시드 설정 (재현 가능성 확보!)
set.seed(123)

# createDataPartition()으로 훈련 데이터 인덱스 생성
train_idx_caret <- createDataPartition(iris$Species, p = 0.7, list = FALSE)

# 훈련 데이터
train_data_caret <- iris[train_idx_caret, ]

# 테스트 데이터
test_data_caret <- iris[-train_idx_caret, ]

# 잘 나뉘었는지 확인!
dim(train_data_caret) # 107  5
dim(test_data_caret) # 43  5

# 각 종의 비율 확인 (훈련 데이터)
prop.table(table(train_data_caret$Species))
#     setosa versicolor  virginica 
# 0.3364486 0.3271028 0.3364486 

# 각 종의 비율 확인 (테스트 데이터)
prop.table(table(test_data_caret$Species))
#     setosa versicolor  virginica 
# 0.3488372 0.3255814 0.3255814 

createDataPartition() 함수를 사용할 때 p = 0.7은 훈련 데이터의 비율을 70%로 설정하는 부분이에요. list = FALSE는 결과를 행렬 형태로 반환하도록 지정하는 옵션이랍니다. sample() 함수와 마찬가지로 -train_idx_caret를 사용해서 테스트 데이터를 추출했어요.

prop.table() 함수를 사용해서 훈련 데이터와 테스트 데이터에서 각 종의 비율을 확인해보면, 거의 비슷한 비율로 데이터가 분할된 것을 알 수 있어요. createDataPartition() 함수가 클래스 비율을 잘 유지하면서 데이터를 분할해준 덕분이죠! 데이터셋의 클래스 분포가 고르지 않을 때 특히 유용하겠죠? 😊

`train_test_split()` 함수와의 비교

train_test_split() 함수는 sklearn.model_selection 모듈에 있는 함수로, Python에서 데이터를 훈련 세트와 테스트 세트로 분할하는 데 사용됩니다. R에서는 caret 패키지의 createDataPartition() 함수를 사용할 수 있다는 점 기억해 주세요!

자, 이렇게 sample() 함수와 createDataPartition() 함수를 활용해서 실제 데이터를 분할하는 방법을 알아봤어요! 🎉 어떤가요? 생각보다 어렵지 않죠? 이제 여러분도 자신 있게 데이터를 분할하고 머신러닝 모델을 훈련시킬 수 있을 거예요! 💪 다음에는 더욱 흥미로운 주제로 찾아올게요! 기대해 주세요! 😉

 

R에서 데이터를 train set과 test set으로 나누는 방법, 이제 좀 더 명확해졌나요? `sample()` 함수, 생각보다 간단하고 강력하죠? train_test_split()만 알고 있었다면 새로운 무기를 장착한 기분일 거예요. 복잡한 패키지 없이도 몇 줄의 코드로 깔끔하게 데이터를 나눌 수 있다니, 정말 편리하지 않나요? 데이터 분석의 첫걸음인 데이터 분할, 이제 sample() 함수로 자신 있게 시작해 보세요! 여러분의 분석 여정을 응원할게요! 앞으로도 흥미로운 R 팁들을 많이 공유할 테니, 자주 놀러 오세요!

 

Itlearner

Share
Published by
Itlearner

Recent Posts

R에서 랜덤 포레스트 (randomForest())

안녕하세요, 여러분! 👋 오늘 함께 알아볼 주제는 바로 랜덤 포레스트(randomForest)에요! 혹시 나무를 보면서 숲을 못…

52분 ago

R에서 의사결정 나무 (rpart(), rpart.plot())

안녕하세요! 오늘은 데이터 분석에서 핫한 알고리즘 중 하나, 바로 의사결정 나무에 대해 같이 알아보는 시간을…

5시간 ago

R에서 선형 회귀 모델 (lm())

안녕하세요! 데이터 분석에 관심 있는 분들, 모두 환영해요! 🤗 오늘은 R을 이용해서 선형 회귀 모델을…

11시간 ago

R에서 머신러닝 패키지 (caret, randomForest, e1071)

안녕하세요! 😊 요즘 데이터 분석, 머신러닝 핫하잖아요. 그래서 오늘은 R 언어로 머신러닝을 시작하는 분들에게 정말…

23시간 ago

R에서 정규성 검정 (shapiro.test(), qqnorm())

안녕하세요! 데이터 분석을 하다 보면 "내 데이터가 정규분포를 따르는 걸까?" 하는 궁금증, 한 번쯤은 가져보셨을…

1일 ago

R에서 상관 분석 (cor(), cor.test())

안녕하세요! 데이터 분석에 관심 있는 분들, 모두 환영해요! 😊 오늘 우리 같이 재미난 통계 이야기…

1일 ago