본문으로 건너뛰기
김신건의 로그

[Python] random, statistics, math

· 수정 · 📖 약 1분 · 338자/단어 #python #random #statistics #math #stdlib
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+ 빠름.

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기