[Python] random, statistics, math
python random, python statistics, python math, random seed, Mersenne Twister
random: 의사 난수
random은 Mersenne Twister 기반 PRNG. 통계·시뮬레이션·게임용. 보안엔 secrets 사용.
기본 함수
import random
random.random() # [0.0, 1.0) float
random.uniform(1.0, 10.0) # [1.0, 10.0] float
random.randint(1, 10) # [1, 10] int (양 끝 포함)
random.randrange(0, 10, 2) # range처럼 (start, stop, step)
random.choice(["a", "b", "c"]) # 단일 선택
random.choices(["a", "b", "c"], k=5) # 복원 추출
random.choices(["a", "b", "c"], weights=[1, 2, 7], k=10) # 가중치
random.sample(["a", "b", "c", "d"], k=2) # 비복원
xs = [1, 2, 3, 4, 5]
random.shuffle(xs) # in-place
random.gauss(mu=0, sigma=1) # 정규 분포
random.triangular(0, 10, mode=3) # 삼각 분포
random.expovariate(lambd=1.0) # 지수 분포
seed: 재현 가능
random.seed(42)
print(random.random()) # 항상 같은 값
# 테스트에서 결정적 동작 보장
seed 없으면 OS의 random source 사용. 보통 매 실행마다 다름.
독립 generator
rng = random.Random(42) # 별도 인스턴스
print(rng.randint(1, 10))
# 모듈 함수 (random.random())는 글로벌 인스턴스 사용
테스트 격리, 멀티스레드 안전성에 유용.
보안 vs random
import random
import secrets
random.choice(...) # 예측 가능 (시드 추측 → 다음 값 예측)
secrets.choice(...) # 안전
세션 토큰, 비밀번호, CSRF 토큰은 반드시 secrets.
statistics: 기초 통계
import statistics
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(statistics.mean(data)) # 5.5 (평균)
print(statistics.median(data)) # 5.5
print(statistics.mode([1, 1, 2, 3])) # 1 (최빈값)
print(statistics.stdev(data)) # 표준편차 (sample)
print(statistics.pstdev(data)) # 표준편차 (population)
print(statistics.variance(data))
print(statistics.quantiles(data, n=4)) # 사분위 [Q1, Q2, Q3]
가중 평균
statistics.fmean(data) # 빠른 float 평균 (3.8+)
statistics.geometric_mean([2, 4, 8]) # 기하 평균
statistics.harmonic_mean([1, 2, 4]) # 조화 평균
정규 분포
nd = statistics.NormalDist(mu=100, sigma=15)
print(nd.cdf(120)) # P(X <= 120)
print(nd.pdf(100)) # density
print(nd.quantiles(n=4)) # 사분위
# 표본 생성
print(nd.samples(10, seed=42))
본격 통계는 SciPy/pandas/numpy가 더 풍부.
math: 수학 함수
import math
# 상수
math.pi
math.e
math.tau # 2π
math.inf
math.nan
# 기본 함수
math.sqrt(16) # 4.0
math.isqrt(15) # 3 (integer sqrt, 3.8+)
math.pow(2, 10) # 1024.0
math.exp(1) # e
math.log(100, 10) # log_10(100) = 2.0
math.log2(8) # 3.0
math.log10(100) # 2.0
# 삼각
math.sin(math.pi)
math.cos(0)
math.atan2(y, x) # 사분면 고려한 arctan
# 반올림
math.floor(3.7) # 3
math.ceil(3.2) # 4
math.trunc(-3.7) # -3 (0 방향 잘라냄)
math.round(...) # 빌트인 round() 사용
# 분해/조합
math.factorial(10) # 3628800
math.comb(10, 3) # 120 (조합, nCr)
math.perm(10, 3) # 720 (순열, nPr)
math.gcd(12, 18) # 6
math.lcm(12, 18) # 36 (3.9+)
math.prod([1, 2, 3]) # 6 (3.8+)
# 부동소수 안전
math.isclose(0.1 + 0.2, 0.3) # True
math.isnan(math.nan)
math.isinf(math.inf)
copysign, modf, frexp
math.copysign(3.0, -5) # -3.0
math.modf(3.5) # (0.5, 3.0) 소수/정수 분리
math.frexp(8.0) # (0.5, 4) → 0.5 * 2^4
math.ldexp(0.5, 4) # 8.0
저수준 부동소수 작업.
random.sample vs choices
import random
random.choices(["a", "b", "c"], k=5) # 복원 (중복 가능)
random.sample(["a", "b", "c", "d"], k=2) # 비복원 (중복 X)
# 무작위 인덱스로 행 선택
indices = random.sample(range(len(data)), k=100)
batch = [data[i] for i in indices]
자주 보는 패턴
A/B 테스트 가짜 데이터
import random
random.seed(42)
users = []
for i in range(1000):
users.append({
"id": i,
"group": random.choice(["A", "B"]),
"converted": random.random() < 0.05, # 5% 전환율
})
데이터 셔플 + 분할
import random
random.seed(42)
random.shuffle(data)
split = int(len(data) * 0.8)
train, test = data[:split], data[split:]
또는 sklearn.model_selection.train_test_split.
가중치 샘플링
import random
categories = ["food", "tech", "sports", "music"]
weights = [40, 30, 20, 10]
sample = random.choices(categories, weights=weights, k=1000)
import collections
print(collections.Counter(sample))
# Counter({'food': ~400, 'tech': ~300, ...})
시뮬레이션
import random
import statistics
def monte_carlo_pi(n=10**6):
inside = sum(
1 for _ in range(n)
if random.random() ** 2 + random.random() ** 2 <= 1
)
return 4 * inside / n
trials = [monte_carlo_pi(10**5) for _ in range(20)]
print(f"π ≈ {statistics.mean(trials):.5f} ± {statistics.stdev(trials):.5f}")
Bernoulli, Poisson 등 분포
import random
def bernoulli(p):
return random.random() < p
def poisson(lambd):
L = math.exp(-lambd)
k, p = 0, 1.0
while p > L:
k += 1
p *= random.random()
return k - 1
NumPy/SciPy가 더 빠른 벡터화 버전 제공.
함정
1. 시드 안 정하고 재현성 기대
random.choice([1, 2, 3]) # 매번 다름
# 재현 필요하면
random.seed(42)
2. 보안에 random 사용
세션, 토큰, 비밀번호엔 절대 X. secrets 사용.
3. 글로벌 random과 멀티스레드
random 모듈 함수는 thread-safe하지만 같은 인스턴스 공유로 순서 비결정. 결정적 동작 원하면 스레드별 random.Random 인스턴스.
4. float 정밀도
math.sqrt(2) ** 2 == 2 # False
math.isclose(math.sqrt(2) ** 2, 2) # True
부동소수 비교는 == 대신 isclose.
5. integer division
math.floor(-3.7) # -4 (수학적 floor)
int(-3.7) # -3 (0 방향)
음수에서 다르다.
NumPy / SciPy로 진화
본격 수치 계산은 NumPy.
import numpy as np
rng = np.random.default_rng(seed=42)
samples = rng.normal(0, 1, size=1000000) # 100만 정규 분포 샘플 즉시
# 벡터 연산
np.mean(samples), np.std(samples)
np.percentile(samples, [25, 50, 75])
순수 Python random 대비 100x+ 빠름.
💬 댓글