인지야공

인지야공/인공 지능 공부 치트 시트 정리/5번째 글

SciPy 치트시트를 다시 쓴다 — np.matrix 로 시작하지 않는다

손에 있던 SciPy 치트시트는 첫 줄이 A = np.matrix(...) 로 시작한다. 그런데 np.matrix 는 지금 권장되지 않는 물건이고, 그 위에 쌓인 예제도 함께 낡았다. 전제부터 바꿔서 다시 썼다.

확인 환경은 SciPy 1.15.3 이다.

np.matrix 를 쓰지 않는다

A = np.matrix([[1., 2.], [3., 4.]])
arr = np.array([[1., 2.], [3., 4.]])

A * A      # [[7, 10], [15, 22]]   ← 행렬곱
arr * arr  # [[1, 4], [ 9, 16]]    ← 원소별 곱

같은 * 가 뜻이 다르다. 게다가 A.I(역행렬), A.H(켤레전치)는 np.matrix 에만 있어서, 남의 코드를 배열에 붙이면 바로 AttributeError 가 난다. 공식 문서도 새 코드에서는 쓰지 말라고 적어 두었다.

배열 하나로 통일하면 뜻이 헷갈릴 일이 없다.

np.matrix 표기배열로 쓰면
A * BA @ B
A.Ilinalg.inv(A) — 되도록 linalg.solve
A.HA.conj().T
A.TA.T (같다)

선형대수 — 역행렬을 구하지 말고 풀어라

Ax=bAx = b 를 풀 때 역행렬을 만들어 곱하는 것은 느리고 오차도 더 쌓인다.

from scipy import linalg

x = linalg.inv(M) @ b     # 37.2ms
x = linalg.solve(M, b)    #  4.2ms   ← 400×400 에서 9배

두 결과의 차이는 10−1810^{-18} 수준이라 값은 같다. 그냥 solve 를 쓰면 된다. 역행렬 자체가 답인 문제가 아니라면 inv 를 쓸 이유가 없다.

linalg.det(A)          # 행렬식
linalg.norm(A)         # 크기. ord=1, np.inf 로 종류를 고른다
linalg.eig(A)          # 고윳값·고유벡터 (대칭이면 eigh 가 빠르고 안정적이다)
linalg.svd(A)          # 특이값 분해 — PCA 의 속이 이것이다
linalg.lstsq(A, b)     # 최소제곱해. 정규방정식을 손으로 세우는 것보다 안전하다

scipy.linalg 는 numpy.linalg 를 포함하고 더 넓다. 둘 다 있으면 SciPy 쪽을 쓴다.

희소행렬은 만나게 되어 있다

원핫 인코딩이나 TF-IDF 의 결과는 대부분이 0 이다. sklearn 이 이걸 희소행렬로 돌려주기 때문에, 모르고 .mean() 같은 걸 부르면 이상한 데서 막힌다.

from scipy import sparse

big = sparse.csr_matrix(np.eye(1000))
# 밀집 8.0MB → 희소 0.016MB. 500배다

big.todense()     # 밀집 행렬로 되돌린다. 큰 것에 부르면 메모리가 터진다
big.toarray()     # ndarray 로

csr 은 행 방향 연산에, csc 는 열 방향에 빠르다. 만들 때는 coo 가 편하다. 실기에서는 “희소행렬이면 todense() 하기 전에 크기를 보라” 정도만 지키면 된다.

scipy.stats — 실기에서 실제로 쓰는 곳

치트시트에는 없지만, 시험에서 SciPy 를 부르는 이유의 대부분은 여기다.

분포는 네 글자면 된다

stats.norm.pdf(0)        # 0.3989  확률밀도
stats.norm.cdf(1.96)     # 0.9750  누적확률 (이 값 이하일 확률)
stats.norm.ppf(0.975)    # 1.9600  cdf 의 역함수 — 신뢰구간의 1.96 이 여기서 나온다
stats.norm.rvs(size=100) #         난수
stats.t.ppf(0.975, df=10)  # 2.2281  자유도가 작으면 1.96 보다 크다

norm 자리에 t, chi2, f, binom, poisson, expon 을 넣으면 전부 같은 네 글자가 붙는다. 분포 정리 글과 같이 보면 외울 것이 확 준다.

검정 지도

무엇을 묻나함수
한 집단의 평균이 μ 인가ttest_1samp
두 집단의 평균이 같은가ttest_ind
같은 대상의 전후가 같은가ttest_rel
세 집단 이상의 평균이 같은가f_oneway (일원분산분석)
정규분포를 따르는가shapiro (n 작을 때) · normaltest
분산이 같은가levene · bartlett
두 범주형이 독립인가chi2_contingency
분포가 이론값과 맞는가chisquare
정규성을 못 믿을 때 (비모수)mannwhitneyu(2집단) · kruskal(3집단↑) · wilcoxon(대응)
두 변수의 상관pearsonr(선형) · spearmanr(순위) · kendalltau

ttest_ind 의 기본은 등분산 가정(equal_var=True)이다. 분산이 다르면 Welch 검정을 써야 하는데, 기본값이라 그냥 지나치기 쉽다.

stats.levene(g1, g2).pvalue          # 먼저 등분산부터 확인하고
stats.ttest_ind(g1, g2)              # p = 0.153   등분산 가정 (Student)
stats.ttest_ind(g1, g2, equal_var=False)  # p = 0.157   Welch

순서는 정규성 → 등분산 → 검정 선택이다. 이 흐름은 ADP 통계 검정 글에 자세히 적어 두었다.

결과는 이름으로 꺼낸다

r = stats.pearsonr(x, y)
r.statistic; r.pvalue            # PearsonRResult — 이름으로 꺼내는 쪽이 안 헷갈린다
stat, p = stats.pearsonr(x, y)   # 튜플 언패킹도 그대로 된다

chi2, p, dof, expected = stats.chi2_contingency(table)   # 값이 4개다

chi2_contingency 의 네 번째 반환값 expected(기대도수)는 답안에 쓸 일이 많다. 기대도수가 5 미만인 칸이 있으면 카이제곱 대신 Fisher 정확검정(fisher_exact)으로 가야 한다는 근거가 된다.

최적화

from scipy import optimize

res = optimize.minimize(lambda v: (v[0]-3)**2 + (v[1]+1)**2, x0=[0, 0])
res.x        # [3., -1.]   res.success 로 수렴 여부를 확인한다

# 선형계획: 3x + 5y 를 최대로 (제약 아래)
lp = optimize.linprog(c=[-3, -5],
                      A_ub=[[1, 0], [0, 2], [3, 2]], b_ub=[4, 12, 18],
                      bounds=(0, None))
lp.x         # [2., 6.]    목적함수 36

linprog 는 최소화만 한다. 최대화 문제는 c 에 음수를 넣고, 답은 -lp.fun 으로 읽는다. 여기서 부호를 놓치면 답이 통째로 뒤집힌다. 시험장에는 PuLP 도 깔려 있으니 손에 익은 쪽을 쓰면 된다.

없어졌거나 이름이 바뀐 것

치트시트·옛 코드1.15.3 에서대신
linalg.expm2, linalg.expm3없다linalg.expm 하나로 통합됐다
integrate.simps없다(1.14 에서 제거)integrate.simpson
integrate.trapz없다(1.14 에서 제거)integrate.trapezoid
np.matrix, A.I, A.H돌지만 권장하지 않는다배열 + @, linalg.solve

출처

DataCamp 의 Python For Data Science Cheat Sheet — SciPy (Linear Algebra) 를 보고 다시 쓴 것이다. 원본은 DataCamp 치트시트 페이지에서, 공식 문서는 docs.scipy.org에서 볼 수 있다. 검정 부분은 원본에 없어 내 ADP 정리에서 필요한 것만 끌어와 붙였다.

표시는 이 브라우저에만 남는다. 서버로 가는 것은 없다.