인지야공/인공 지능 공부 치트 시트 정리/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 * B | A @ B |
A.I | linalg.inv(A) — 되도록 linalg.solve |
A.H | A.conj().T |
A.T | A.T (같다) |
선형대수 — 역행렬을 구하지 말고 풀어라
를 풀 때 역행렬을 만들어 곱하는 것은 느리고 오차도 더 쌓인다.
from scipy import linalg
x = linalg.inv(M) @ b # 37.2ms
x = linalg.solve(M, b) # 4.2ms ← 400×400 에서 9배
두 결과의 차이는 수준이라 값은 같다. 그냥 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 정리에서 필요한 것만 끌어와 붙였다.