pandas 난수 시드 완벽 가이드: np.random.seed, sample(random_state), pd.util.testing.rands 재현성
🎯 실험을 다시 돌려도 같은 결과가 나오는 파이썬 재현성 설정법을 한 번에 정리합니다
데이터 실험을 하다 보면 모델이 잘 맞던 코드가 실행할 때마다 미묘하게 달라져서 원인을 찾느라 시간을 허비하는 순간이 생깁니다.
그래서 분석 초반부터 난수 시드를 명확히 고정해 두는 습관이 꽤 중요합니다.
특히 파이썬 환경에서 많이 쓰는 조합인 pandas와 NumPy에서는 전역 시드 설정과 함수별 시드 제어가 뒤섞여 등장해 헷갈리기 쉽습니다.
이번 글은 그 혼란을 깔끔하게 정리하려는 목적을 담고 있습니다.
핵심은 세 가지입니다.
NumPy의 np.random.seed로 전역 상태를 고정하는 법.
pandas의 DataFrame.sample(random_state=…)로 표본추출 결과를 재현하는 법.
그리고 예전 테스트 코드에서 보일 수 있는 pd.util.testing.rands 사용 맥락을 이해하는 일입니다.
이 글은 실제 업무와 테스트 환경 모두에서 바로 적용할 수 있도록 구성합니다.
전역 시드와 지역 시드의 차이, 샘플링 가중치가 있을 때의 주의점, 그리고 문자열 더미 데이터를 만들 때 어떤 대안이 적합한지까지 간단한 예와 함께 설명합니다.
특히 pd.util.testing.rands처럼 과거에 자주 쓰이던 유틸의 현재 상태를 짚고, 동일한 목적을 달성할 수 있는 최신 방식도 함께 제시합니다.
분석 리포트가 매번 달라지는 난감한 상황을 줄이고, 팀원 모두가 같은 코드를 같은 결과로 재현할 수 있게 돕는 실전 가이드를 목표로 합니다.
📋 목차
🔗 pandas에서 난수 시드의 의미와 필요성
데이터 분석과 테스트 자동화에서 난수는 표본추출과 셔플, 교차검증 분할 등 다양한 순간에 쓰입니다.
무작위성은 편향을 줄여 주지만, 실행 때마다 결과가 달라지면 원인 분석과 회귀 테스트가 어려워집니다.
그래서 시드(seed)로 난수 생성기의 시작 상태를 고정해 동일 입력에 대해 동일 출력을 확보합니다.
파이썬 생태계에서는 주로 NumPy의 난수 상태를 고정하거나, pandas 함수에 random_state를 넘겨 지역적으로 제어합니다.
이 두 가지를 적절히 조합하면 노트북, CI 서버, 동료 PC 어디서 돌려도 결과를 재현할 수 있습니다.
난수는 사실상 의사난수(pseudorandom)입니다.
같은 알고리즘과 같은 초기 상태면 같은 수열이 나옵니다.
따라서 전역으로 np.random.seed(정수)를 호출하면 이후 NumPy 기반 난수 호출은 같은 순서를 따릅니다.
반대로 DataFrame.sample(random_state=정수)처럼 함수 인자로 시드를 주면, 그 함수의 무작위 동작만 독립적으로 고정됩니다.
전역 고정은 빠르지만 사이드이펙트가 커질 수 있고, 지역 고정은 안전하지만 모든 호출에 값을 챙겨 넣어야 한다는 점이 특징입니다.
🧠 무작위성과 재현성의 균형
실험 설계에서 무작위성은 과적합 신호를 줄이지만, 결과 검증 단계에서는 재현성이 우선입니다.
초기 탐색 단계에서는 시드를 열어 두고, 보고서 산출이나 테스트 코드에서는 시드를 고정하는 식으로 역할을 분리하면 효율적입니다.
또한 팀 규칙으로 시드 값을 상수로 관리하거나, 환경변수에서 읽어 오면 배포 환경 간 일관성을 지키기 쉽습니다.
🧩 전역 상태와 지역 제어의 차이
전역 시드 고정은 노트북 상단에서 한 번만 설정하면 편리합니다.
하지만 같은 커널에서 다른 셀의 무작위 호출 순서가 바뀌면 이후 결과가 달라질 수 있습니다.
반면 random_state를 인자로 주면 호출 순서가 달라도 해당 함수의 결과는 일정합니다.
실무에서는 전역 시드 + 핵심 함수의 random_state 이중 고정을 권장합니다.
import numpy as np
import pandas as pd
# 전역 시드 고정
np.random.seed(42)
df = pd.DataFrame({"x": np.arange(10)})
# 호출 순서가 바뀌어도 sample 결과를 고정하고 싶다면 random_state를 함께 지정
a = df.sample(n=3, random_state=42).sort_values("x").x.tolist()
b = df.sample(frac=0.3, random_state=42).sort_values("x").x.tolist()
print(a) # [0, 1, 5]
print(b) # [0, 1, 5]
💡 TIP: 전역 시드만 걸고 sample에 random_state를 생략하면, 다른 코드가 중간에 난수를 소모했을 때 결과가 바뀔 수 있습니다.
테스트 코드, 데이터 스냅샷 생성, 보고서 표본 고정에는 반드시 random_state를 지정하세요.
⚠️ 주의: 일부 라이브러리는 내부적으로 NumPy가 아닌 자체 난수기를 사용할 수 있습니다.
이 경우 np.random.seed만으로는 완전한 재현성이 보장되지 않습니다.
가능하면 해당 함수가 제공하는 random_state 또는 시드 인자를 함께 설정하세요.
- 🛠️노트북 첫 셀에서 np.random.seed(고정값) 호출
- ⚙️DataFrame.sample에는 항상 random_state 지정
- 🔌외부 라이브러리도 시드 인자 지원 여부 확인 후 설정
💬 재현성은 디버깅 시간을 절약하고, 코드 리뷰와 CI 파이프라인의 신뢰도를 높입니다.
같은 입력과 설정에서 결과가 같아야 품질이 관리됩니다.
🛠️ np.random.seed와 random_state 차이와 사용법
파이썬에서 난수를 제어하는 대표적인 방식은 두 가지입니다.
하나는 np.random.seed()로 전역 난수 상태를 고정하는 방법이고, 다른 하나는 pandas나 scikit-learn 함수의 random_state 매개변수를 이용하는 지역 제어 방식입니다.
두 접근은 겉보기엔 비슷하지만 동작 원리와 범위가 다릅니다.
적절히 구분해서 써야 원하는 수준의 재현성을 얻을 수 있습니다.
🧩 np.random.seed로 전역 상태 고정
NumPy는 내부적으로 RandomState 객체를 사용해 난수를 만듭니다.
np.random.seed(정수)를 호출하면 이 객체의 초기 상태가 지정되어, 이후 np.random.rand(), np.random.randint() 등 모든 난수 호출이 동일한 순서로 결과를 냅니다.
즉 한 번 설정하면 세션 전체에 적용되며, pandas나 matplotlib 등 NumPy 기반 난수 기능에도 영향을 줍니다.
import numpy as np
np.random.seed(123)
print(np.random.randint(0, 10, 5))
# 결과: [2 2 6 1 3]
np.random.seed(123)
print(np.random.randint(0, 10, 5))
# 다시 실행해도 결과가 동일
전역 시드는 테스트 초기화나 스크립트 단위에서는 유용하지만, 복잡한 파이프라인이나 병렬 연산에서는 예측이 어려워질 수 있습니다.
예를 들어 여러 함수가 내부적으로 난수를 호출하면 호출 순서만 바뀌어도 결과가 달라질 수 있습니다.
그래서 함수 단위로 시드를 직접 지정하는 random_state 방식이 점점 더 많이 사용되고 있습니다.
🎲 random_state로 지역 제어
pandas의 DataFrame.sample(), scikit-learn의 train_test_split(), XGBoost의 random_state 등은 공통적으로 지역적 시드 제어를 지원합니다.
이 값은 보통 정수이며, 내부적으로 독립된 RandomState를 생성해 사용합니다.
따라서 전역 난수 상태에 영향을 주지 않으면서, 해당 호출만 재현 가능한 결과를 보장합니다.
from sklearn.model_selection import train_test_split
import numpy as np
X = np.arange(10).reshape(5, 2)
y = np.array([0, 1, 0, 1, 0])
# random_state 지정으로 결과 고정
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=42)
print(X_test)
# 항상 같은 행이 선택됨
💡 TIP: random_state는 정수 외에도 np.random.RandomState 객체를 직접 넘길 수 있습니다.
이를 활용하면 여러 함수에서 동일 객체를 공유해 일관된 샘플링 시퀀스를 유지할 수 있습니다.
| 구분 | 특징 |
|---|---|
| np.random.seed() | 전역 상태를 고정하며, 이후 모든 NumPy 난수 호출에 영향 |
| random_state | 특정 함수 호출에만 적용되어, 전역 상태와 분리 |
💬 np.random.seed는 “전체 환경”을, random_state는 “개별 함수 동작”을 고정한다고 이해하면 됩니다.
둘을 적절히 조합하면 코드 전반의 재현성을 완벽히 확보할 수 있습니다.
⚙️ DataFrame.sample random_state로 재현성 확보
pandas의 DataFrame.sample()은 데이터프레임에서 행을 무작위로 추출할 때 사용됩니다.
이 함수는 표본의 개수(n) 또는 비율(frac)을 지정할 수 있으며, 재현성을 확보하기 위해 random_state 인자를 제공합니다.
이 인자를 설정하지 않으면 호출할 때마다 샘플링 결과가 달라집니다.
분석 리포트나 테스트 코드에서는 반드시 고정된 random_state를 지정해야 동일 결과를 얻을 수 있습니다.
📊 기본 예제
아래 예제는 random_state를 지정했을 때와 지정하지 않았을 때의 차이를 보여줍니다.
같은 데이터셋이라도 시드를 고정하면 항상 동일한 표본이 선택되며, 반대로 생략하면 호출할 때마다 결과가 달라집니다.
import pandas as pd
df = pd.DataFrame({'A': range(10), 'B': range(10, 20)})
# 시드 없이 샘플링
print(df.sample(3))
# 시드를 고정한 샘플링
print(df.sample(3, random_state=42))
결과를 보면 첫 번째 호출은 실행할 때마다 다른 행이 선택되고, 두 번째는 항상 같은 3개 행이 선택됩니다.
이처럼 random_state는 재현 가능한 무작위 표본을 만드는 핵심 역할을 합니다.
🧮 frac과 weights를 함께 사용하는 경우
특정 열을 기준으로 가중치 샘플링을 수행할 수도 있습니다.
이 경우에도 random_state를 지정해야 매번 동일한 확률 분포로 결과가 유지됩니다.
df = pd.DataFrame({'value': range(5), 'weight': [0.1, 0.2, 0.3, 0.25, 0.15]})
sampled = df.sample(frac=0.4, weights='weight', random_state=0)
print(sampled)
가중치 샘플링에서는 난수 발생 순서에 따라 추출되는 행이 달라질 수 있습니다.
따라서 재현 가능한 결과를 원한다면 항상 random_state를 포함해야 합니다.
특히 weights 인자를 사용할 때는 이 점을 놓치면 같은 비율로도 결과가 달라집니다.
💎 핵심 포인트:
pandas의 무작위 표본 함수들은 대부분 random_state를 지원합니다.
DataFrame.sample뿐 아니라 DataFrameGroupBy.sample(), Series.sample() 등도 동일한 방식으로 시드를 고정할 수 있습니다.
⚠️ 주의: pandas의 sample은 NumPy의 전역 시드 설정과 무관하게 동작합니다.
즉, np.random.seed()를 설정해도 random_state를 지정하지 않으면 결과가 매번 달라질 수 있습니다.
- 📌표본추출 시에는 항상 random_state 지정
- 🧮가중치 샘플링에서도 시드 필수
- ✅데이터 검증 및 리포트용 표본은 항상 시드 고정
💬 샘플링에서 시드 고정은 분석의 신뢰도를 높이는 필수 습관입니다.
pandas에서는 random_state 하나로 모든 결과를 재현할 수 있습니다.
🔤 pd.util.testing.rands로 임의 문자열 생성하기
과거 pandas에서는 pd.util.testing.rands()를 이용해 테스트용 임의 문자열을 간편하게 만들 수 있었습니다.
예를 들어, 무작위로 구성된 5자리 알파벳 문자열을 생성해 더미 데이터 프레임을 테스트할 때 활용했죠.
이 함수는 내부적으로 np.random.choice()를 사용해 랜덤 알파벳을 결합합니다.
그러나 현재는 pandas 1.1 이후로 pd.util.testing 모듈이 pandas._testing으로 변경되면서, 직접 사용은 권장되지 않습니다.
🧾 과거 버전 예제
import pandas as pd
from pandas.util import testing as tm
# 5자리 난수 문자열 3개 생성
for _ in range(3):
print(tm.rands(5))
# 출력 예시:
# 'aBZkx'
# 'qpRWd'
# 'fCnTy'
이처럼 rands()는 임의의 문자열을 테스트용으로 빠르게 생성해 주었지만,
현재는 내부 API로 분류되어 더 이상 문서화되지 않습니다.
대신 파이썬 표준 모듈인 random과 string을 조합하거나, NumPy 기반의 벡터화된 문자열 생성으로 대체할 수 있습니다.
🧠 대체 코드 (추천 방식)
import random, string
def random_string(n=5, seed=42):
random.seed(seed)
return ''.join(random.choices(string.ascii_letters, k=n))
print(random_string())
이 함수는 pd.util.testing.rands의 기능을 그대로 구현하면서,
표준 라이브러리만으로 안전하게 재현 가능한 문자열을 만들어냅니다.
또한 프로젝트 전반에 seed 값을 고정하면 언제 실행해도 동일한 결과를 얻을 수 있습니다.
💡 TIP: pd.util.testing.rands는 현재 비공개 API로 분류되어 버전별로 존재 여부가 다릅니다.
대체로 pandas._testing 또는 커스텀 함수로 전환하는 것이 안전합니다.
| 함수명 | 현재 상태 | 비고 |
|---|---|---|
| pd.util.testing.rands | 비공개, pandas 1.1 이후 비권장 | 테스트용 문자열 생성 |
| random.choices + string.ascii_letters | 권장 방식 | 표준 라이브러리 기반, 시드 제어 가능 |
💎 핵심 포인트:
pandas의 pd.util.testing.rands는 과거 테스트용 API였으며,
현재는 대체 방식을 쓰는 것이 안전합니다.
문자열 난수 생성 시에는 항상 시드를 고정해 재현 가능한 결과를 확보하세요.
💬 테스트용 난수 문자열은 단순한 것 같지만, 버전 호환성과 재현성을 위해 시드와 생성 방식을 명확히 지정해야 합니다.
💡 테스트 시드 패턴 모음과 실전 예제 코드
지금까지 pandas와 NumPy에서 난수 시드를 설정하는 다양한 방법을 살펴봤습니다.
이번에는 실제 프로젝트나 데이터 분석 환경에서 자주 쓰이는 시드 고정 패턴을 정리해 보겠습니다.
다양한 예제 코드를 함께 제시하여 실무에서 바로 적용할 수 있게 구성했습니다.
🧱 프로젝트 전역 시드 패턴
프로젝트 전체의 재현성을 보장하려면 시드 설정을 한 곳에서 관리해야 합니다.
보통 config.py나 settings.yaml 등에 공통 상수로 정의하고, 각 모듈이 이를 불러와 적용하는 형태가 이상적입니다.
# config.py
SEED = 1234
# main.py
import numpy as np
import random
import pandas as pd
from config import SEED
def set_seed(seed=SEED):
np.random.seed(seed)
random.seed(seed)
set_seed()
df = pd.DataFrame({'A': np.random.randint(0, 100, 5)})
print(df.sample(3, random_state=SEED))
이렇게 전역 시드를 한 번에 세팅하면, pandas와 NumPy, random 모듈 모두 동일한 시드로 일관된 결과를 만들어 냅니다.
실험 환경이 달라도 결과 차이가 최소화됩니다.
📘 scikit-learn 및 ML 시드 설정
머신러닝 모델을 학습할 때도 시드 설정은 매우 중요합니다.
scikit-learn, XGBoost, LightGBM 등 대부분의 라이브러리는 random_state 또는 seed 파라미터를 제공합니다.
모델 학습 시 이 값을 고정하면, 데이터 분할과 파라미터 초기화가 일정하게 유지됩니다.
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
import numpy as np
np.random.seed(0)
X = np.random.randn(100, 5)
y = np.random.randint(0, 2, 100)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)
print(model.score(X_test, y_test))
이렇게 하면 학습과 예측 결과가 언제 실행하더라도 일정합니다.
데이터 과학 팀에서는 이 방식을 표준화해 실험 비교 시 오차를 최소화합니다.
🧮 재현성 테스트 자동화 예제
테스트 코드에서도 재현성은 매우 중요합니다.
특히 pandas의 표본추출, 난수 기반 컬럼 계산 등을 점검할 때는 테스트 시드 설정이 자동화되어야 합니다.
import pytest
import numpy as np
import pandas as pd
@pytest.fixture(autouse=True)
def seed_fixture():
np.random.seed(42)
def test_sample_is_reproducible():
df = pd.DataFrame({"x": range(10)})
result1 = df.sample(3, random_state=42)
result2 = df.sample(3, random_state=42)
assert result1.equals(result2)
이처럼 테스트 단계에서 시드를 자동으로 고정하면, 무작위로 보이는 데이터 로직도 예측 가능한 형태로 검증할 수 있습니다.
결과의 일관성은 자동화 테스트 신뢰도의 핵심입니다.
💎 핵심 포인트:
시드는 단순히 난수를 제어하는 값이 아니라, 데이터 재현성과 실험 신뢰도를 보장하는 기반입니다.
NumPy, pandas, random, scikit-learn 모두 동일한 시드 체계를 설정하면 완벽한 실험 반복이 가능합니다.
- 🧩NumPy, random, pandas 모두 동일 시드로 고정
- ⚙️테스트 자동화 시 fixture로 시드 초기화
- 📘모델 학습 시 random_state 필수 지정
- 💡환경별 실행 차이를 줄이기 위해 config 기반 시드 관리
💬 시드는 분석의 품질을 지탱하는 숨은 열쇠입니다.
고정된 난수 환경은 모든 실험을 ‘한 번 더 돌려도 같은 결과’로 만들어 줍니다.
❓ 자주 묻는 질문 (FAQ)
np.random.seed를 여러 번 호출하면 어떻게 되나요?
즉, 시드가 바뀌면 난수 결과도 완전히 달라지고, 같은 시드를 다시 쓰면 동일한 순서로 반복됩니다.
random_state는 왜 꼭 정수여야 하나요?
정수를 전달하면 고정된 RandomState 객체가 만들어지며, 그 결과가 항상 일정하게 유지됩니다.
None을 넘기면 호출할 때마다 다른 난수가 생성됩니다.
pandas sample에서 np.random.seed만 써도 재현이 되지 않는데 이유가 있나요?
따라서 np.random.seed()를 설정하더라도 random_state를 별도로 지정하지 않으면 매번 결과가 달라집니다.
pd.util.testing.rands가 더 이상 동작하지 않는데 대체 방법은?
대신 표준 random 모듈의 random.choices()나 NumPy 기반의 문자열 생성 방식을 사용하는 것이 권장됩니다.
시드 값은 어떤 숫자를 쓰는 게 좋은가요?
팀 내에서 표준 시드를 정하거나, 환경변수로 관리하는 것이 좋은 습관입니다.
random.seed와 np.random.seed를 같이 써야 하나요?
random.seed는 파이썬 표준 random 모듈용, np.random.seed는 NumPy용입니다.
두 라이브러리를 모두 사용하는 경우에는 둘 다 같은 시드 값으로 설정하는 것이 좋습니다.
모델 훈련 시 시드를 고정했는데 결과가 약간씩 다르게 나오는 이유는?
이런 경우 완벽히 동일한 결과를 보장하기 어렵습니다.
가능한 한 deterministic 설정을 켜고, 동일한 환경에서 실행해야 합니다.
DataFrame.sample에서 random_state 대신 np.random.RandomState 객체를 넘겨도 되나요?
random_state는 정수 외에도 np.random.RandomState 객체를 직접 전달받습니다.
이를 활용하면 여러 함수가 같은 난수 시퀀스를 공유하여 더 정교한 실험 제어가 가능합니다.
🧩 pandas 난수 시드 설정으로 완전한 재현성 확보하기
데이터 분석에서 재현성은 단순한 편의가 아니라 품질 관리의 핵심입니다.
pandas와 NumPy의 시드를 올바르게 설정하면, 모든 표본추출과 무작위 연산의 결과를 정확히 반복할 수 있습니다.
이번 글에서 살펴본 np.random.seed(), sample(random_state=…), pd.util.testing.rands 등은 각기 다른 수준의 제어를 제공합니다.
전역 시드는 세션 전체를 고정하고, random_state는 함수 단위로 재현성을 유지하며, 테스트용 문자열 생성은 실험 환경을 완벽히 모사할 때 유용합니다.
결국 가장 중요한 것은 “같은 입력에 같은 결과”를 보장하는 환경을 만드는 일입니다.
프로젝트 전반에서 시드를 일관되게 관리하고, 테스트 코드와 모델 학습 코드에 모두 적용해야 완전한 재현성이 확보됩니다.
시드 값은 단순한 숫자 이상의 의미를 갖습니다.
그것은 신뢰할 수 있는 데이터 분석과 실험의 출발점입니다.
🏷️ 관련 태그 : pandas, numpy, random_state, 데이터재현성, 데이터분석, 파이썬시드, 데이터테스트, np.random.seed, pd.util.testing.rands, 머신러닝재현성