Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

노트북은 예측 → 계산 → 대조 세 부분으로 고정한다. 새 개념은 도입하지 않는다. 본문에서 이미 유도한 것을 수치로 확인할 뿐이다.

1. 예측 (코드를 쓰기 전에)

아래 칸을 먼저 채운다. 계산하지 않는다.

  1. L=100L=100 고정, KK를 100에서 200으로 2배 하면 YY는 몇 배가 되는가. α×100%=30%\alpha\times100\%=30\% 증가인가.

    예측: ____

  2. FKF_K, FLF_L을 전방 유한차분(h=103h=10^{-3})으로 구해 KFK+LFLKF_K+LF_L을 만들면 νY\nu Y와 얼마나, 어느 방향으로 어긋나는가(ν=0.9,1.0,1.1\nu=0.9, 1.0, 1.1).

    예측: ____

  3. KK의 수치를 1/1000로 바꾸면(천 단위) A^\hat A, α^\hat\alpha, sKs_K 중 무엇이 변하는가.

    예측: ____

2. 계산

패키지 호출로 답을 내지 않는다. 생산함수와 차분과 정규방정식을 직접 쌓는다.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import font_manager

# 한국어 글꼴을 후보 목록에서 있는 것으로 고른다
_cands = ['Apple SD Gothic Neo', 'AppleGothic', 'NanumGothic', 'Noto Sans CJK KR', 'Malgun Gothic']
_have = {f.name for f in font_manager.fontManager.ttflist}
for _f in _cands:
    if _f in _have:
        plt.rcParams['font.family'] = _f
        break
plt.rcParams['axes.unicode_minus'] = False

# 생산함수를 손으로 쌓는다
def F(K, L, A=1.0, a=0.3, b=0.7):
    return A * K ** a * L ** b

A0, ALPHA = 1.0, 0.3
print('글꼴:', plt.rcParams['font.family'][0])
print('F(100, 100) =', round(F(100.0, 100.0), 4))
글꼴: Apple SD Gothic Neo
F(100, 100) = 100.0

예측 1. LL을 고정하고 KK를 2배 한다. 배율이 KK의 수준을 아는지도 함께 본다.

# 예측 1 — L을 고정한 채 K를 2배 했을 때의 산출 배율을 쌓는다
L0 = 100.0
K1, K2 = 100.0, 200.0
Y1, Y2 = F(K1, L0), F(K2, L0)
ratio = Y2 / Y1
print(f'Y(K=100) = {Y1:.4f}     Y(K=200) = {Y2:.4f}')
print(f'배율  Y2/Y1    = {ratio:.4f}      2^0.3 = {2.0 ** ALPHA:.4f}')
print(f'증가율         = {100 * (ratio - 1):.2f}%     (30%가 아니다)')
print(f'Δln Y / Δln K  = {(np.log(Y2) - np.log(Y1)) / (np.log(K2) - np.log(K1)):.6f}')
Y(K=100) = 100.0000     Y(K=200) = 123.1144
배율  Y2/Y1    = 1.2311      2^0.3 = 1.2311
증가율         = 23.11%     (30%가 아니다)
Δln Y / Δln K  = 0.300000
# 같은 배율이 K의 수준을 모르는지 여러 자리에서 쌓아 본다
print(f"{'K':>9}{'Y(K)':>13}{'Y(2K)':>13}{'Y(2K)/Y(K)':>14}")
for K in [10.0, 100.0, 1000.0, 10000.0]:
    print(f'{K:9.0f}{F(K, L0):13.4f}{F(2 * K, L0):13.4f}{F(2 * K, L0) / F(K, L0):14.6f}')
print()
print('덧셈 충격 K→K+100의 배율 — 수준에 의존한다')
print(f'  K=100: {F(200.0, L0) / F(100.0, L0):.6f}     K=1000: {F(1100.0, L0) / F(1000.0, L0):.6f}')
        K         Y(K)        Y(2K)    Y(2K)/Y(K)
       10      50.1187      61.7034      1.231144
      100     100.0000     123.1144      1.231144
     1000     199.5262     245.6456      1.231144
    10000     398.1072     490.1274      1.231144

덧셈 충격 K→K+100의 배율 — 수준에 의존한다
  K=100: 1.231144     K=1000: 1.029006

예측 2. 한계생산을 전방 유한차분으로 만들어 KFK+LFLKF_K+LF_LνY\nu Y와 겨룬다. 3절 수치 표(A=1A=1, α=0.3\alpha=0.3, K=300K=300, L=100L=100)와 같은 자리를 쓴다.

# 전방 유한차분으로 한계생산을 쌓는다 — 미분 패키지를 쓰지 않는다
def FK_fd(K, L, h, A=1.0, a=0.3, b=0.7):
    return (F(K + h, L, A, a, b) - F(K, L, A, a, b)) / h


def FL_fd(K, L, h, A=1.0, a=0.3, b=0.7):
    return (F(K, L + h, A, a, b) - F(K, L, A, a, b)) / h


K0, Lb = 300.0, 100.0
print(f'F_K 전방차분(h=1e-3) = {FK_fd(K0, Lb, 1e-3):.10f}')
print(f'F_K 정확값 αY/K      = {ALPHA * F(K0, Lb) / K0:.10f}')
print(f'F_L 전방차분(h=1e-3) = {FL_fd(K0, Lb, 1e-3):.10f}')
print(f'F_L 정확값 βY/L      = {0.7 * F(K0, Lb) / Lb:.10f}')
F_K 전방차분(h=1e-3) = 0.1390387548
F_K 정확값 αY/K      = 0.1390389170
F_L 전방차분(h=1e-3) = 0.9732709593
F_L 정확값 βY/L      = 0.9732724192
# 예측 2 — ν별로 KF_K, LF_L, 합, νY, 잔여를 쌓아 3절 표와 대조한다
h = 1e-3
rows = []
print(f"{'ν':>5}{'β':>6}{'Y':>11}{'K·F_K':>11}{'L·F_L':>11}{'합':>11}{'νY':>11}{'잔여':>9}{'상대어긋남':>14}")
for b in [0.6, 0.7, 0.8]:
    nu = ALPHA + b
    Y = F(K0, Lb, A0, ALPHA, b)
    kfk = K0 * FK_fd(K0, Lb, h, A0, ALPHA, b)
    lfl = Lb * FL_fd(K0, Lb, h, A0, ALPHA, b)
    tot = kfk + lfl
    rel = (tot - nu * Y) / (nu * Y)
    rows.append((nu, Y, kfk, lfl, tot, rel))
    print(f'{nu:5.1f}{b:6.1f}{Y:11.4f}{kfk:11.4f}{lfl:11.4f}{tot:11.4f}'
          f'{nu * Y:11.4f}{(1 - nu) * Y:9.2f}{rel:14.3e}')
print()
print('자본의 몫 K·F_K/Y :', [round(r[2] / r[1], 6) for r in rows])
    ν     β          Y      K·F_K      L·F_L          합         νY       잔여         상대어긋남
  0.9   0.6    87.7276    26.3183    52.6365    78.9547    78.9549     8.77    -1.722e-06
  1.0   0.7   139.0389    41.7116    97.3271   139.0387   139.0389     0.00    -1.400e-06
  1.1   0.8   220.3618    66.1085   176.2893   242.3978   242.3980   -22.04    -1.045e-06

자본의 몫 K·F_K/Y : [0.3, 0.3, 0.3]
# h를 10배씩 줄이며 어긋남이 어떻게 주는지 쌓는다 (ν=1)
hs, rels = [1e-1, 1e-2, 1e-3, 1e-4], []
print(f"{'h':>9}{'합 - νY':>15}{'상대어긋남':>17}{'직전 대비':>13}")
for h_ in hs:
    Y = F(K0, Lb)
    tot = K0 * FK_fd(K0, Lb, h_) + Lb * FL_fd(K0, Lb, h_)
    rel = (tot - Y) / Y
    tail = '' if not rels else f'{rel / rels[-1]:13.3f}'
    rels.append(rel)
    print(f'{h_:9.0e}{tot - Y:15.3e}{rel:17.3e}{tail}')
        h         합 - νY            상대어긋남        직전 대비
    1e-01     -1.946e-02       -1.399e-04
    1e-02     -1.946e-03       -1.400e-05        0.100
    1e-03     -1.947e-04       -1.400e-06        0.100
    1e-04     -1.946e-05       -1.400e-07        0.100
# 생산물 대비 요소지급을 쌓아 그린다
sk = [r[2] / r[1] for r in rows]
sl = [r[3] / r[1] for r in rows]
x = np.arange(3)
fig, ax = plt.subplots(figsize=(5.4, 3.4))
ax.bar(x, sk, 0.5, color='#3b6ea5', label='자본 몫 $KF_K/Y$')
ax.bar(x, sl, 0.5, bottom=sk, color='#d98c3f', label='노동 몫 $LF_L/Y$')
ax.axhline(1.0, ls='--', lw=1.0, color='k')
for i, (u, v) in enumerate(zip(sk, sl)):
    ax.text(i, u + v + 0.03, f'{u + v:.2f}', ha='center', fontsize=9)
ax.set_xticks(x)
ax.set_xticklabels([f'ν={r[0]:.1f}' for r in rows])
ax.set_ylabel('생산물 대비 요소지급')
ax.set_ylim(0, 1.35)
ax.legend(loc='lower right', fontsize=8)
ax.set_title('합이 생산물과 만나는 것은 ν=1뿐이다')
plt.tight_layout()
plt.show()
<Figure size 540x340 with 1 Axes>

예측 3. 아홉 점 격자 K{100,300,1000}K\in\{100,300,1000\}, L{50,100,200}L\in\{50,100,200\}에서 lnY=c+αlnK+βlnL\ln Y=c+\alpha\ln K+\beta\ln L의 정규방정식을 직접 세운다. LL을 하나로 고정하면 lnL\ln L 열이 절편 열과 겹쳐 풀리지 않으므로 LL도 세 값을 쓴다.

# 예측 3 — 아홉 점 격자 자료와 정규방정식을 직접 세운다
Ks, Ls = np.array([100.0, 300.0, 1000.0]), np.array([50.0, 100.0, 200.0])
KK, LL = np.meshgrid(Ks, Ls, indexing='ij')
Kg, Lg = KK.ravel(), LL.ravel()
Yg = F(Kg, Lg)


def ols(K_col, L_col, y):
    X = np.column_stack([np.ones_like(K_col), np.log(K_col), np.log(L_col)])
    return np.linalg.solve(X.T @ X, X.T @ np.log(y))


c1, a1, b1 = ols(Kg, Lg, Yg)
print('격자 아홉 점 (K, L, Y)')
for K, L, Y in zip(Kg, Lg, Yg):
    print(f'  {K:7.0f}{L:7.0f}{Y:11.4f}')
print(f'원 단위: ĉ = {c1:+.6f}  α̂ = {a1:.12f}  β̂ = {b1:.12f}  Â = {np.exp(c1):.6f}')
격자 아홉 점 (K, L, Y)
      100     50    61.5572
      100    100   100.0000
      100    200   162.4505
      300     50    85.5885
      300    100   139.0389
      300    200   225.8694
     1000     50   122.8228
     1000    100   199.5262
     1000    200   324.1313
원 단위: ĉ = -0.000000  α̂ = 0.300000000000  β̂ = 0.700000000000  Â = 1.000000
# 같은 자료를 K/1000으로 다시 재서 추정한다
c2, a2, b2 = ols(Kg / 1000.0, Lg, Yg)
print(f'천 단위: ĉ = {c2:+.6f}  α̂ = {a2:.12f}  β̂ = {b2:.12f}  Â = {np.exp(c2):.6f}')
print(f'ĉ 이동량 = {c2 - c1:.6f}      α·ln1000 = {ALPHA * np.log(1000.0):.6f}')
print(f'Â 배율   = {np.exp(c2) / np.exp(c1):.4f}         1000^0.3 = {1000.0 ** ALPHA:.4f}')
print(f'α̂ 변화   = {a2 - a1:+.3e}      β̂ 변화 = {b2 - b1:+.3e}')

# 분배율은 단위에 비례하는 증분으로 쌓는다
sK = {}
for nm, K_, A_ in [('원 단위', 300.0, 1.0), ('천 단위', 0.3, 1000.0 ** ALPHA)]:
    sK[nm] = K_ * FK_fd(K_, Lb, 1e-6 * K_, A_) / F(K_, Lb, A_)
    print(f'{nm}: K = {K_:8.4f}  Y = {F(K_, Lb, A_):.4f}  s_K = {sK[nm]:.6f}')
천 단위: ĉ = +2.072327  α̂ = 0.300000000000  β̂ = 0.700000000000  Â = 7.943282
ĉ 이동량 = 2.072327      α·ln1000 = 2.072327
 배율   = 7.9433         1000^0.3 = 7.9433
α̂ 변화   = -7.938e-15      β̂ 변화 = +3.442e-15
원 단위: K = 300.0000  Y = 139.0389  s_K = 0.300000
천 단위: K =   0.3000  Y = 139.0389  s_K = 0.300000
# 같은 자료를 semi-log와 log-log 두 축에 찍는다
Kc = np.logspace(1, 3, 200)
m = Lg == 100.0
fig, axes = plt.subplots(1, 2, figsize=(9.6, 3.6))
axes[0].plot(Kc, np.log(F(Kc, 100.0)), color='k')
axes[0].scatter(Kg[m], np.log(Yg[m]), s=20, color='k', zorder=3)
axes[0].set_xlabel('자본 $K$')
axes[0].set_ylabel('$\\ln Y$')
axes[0].set_title('(a) semi-log — 오목 곡선')
axes[1].plot(np.log(Kc), np.log(F(Kc, 100.0)), color='#3b6ea5', label='원 단위')
axes[1].plot(np.log(Kc / 1000.0), np.log(F(Kc, 100.0)), ls='--', color='#c0392b', label='천 단위')
axes[1].scatter(np.log(Kg[m]), np.log(Yg[m]), s=20, color='k', zorder=3)
axes[1].annotate('', xy=(np.log(100.0), np.log(F(100.0, 100.0))),
                 xytext=(np.log(0.1), np.log(F(100.0, 100.0))),
                 arrowprops=dict(arrowstyle='<->', lw=0.9))
axes[1].text(np.log(3.0), np.log(F(100.0, 100.0)) + 0.08, 'ln1000 = 6.91', ha='center', fontsize=8)
axes[1].set_xlabel('$\\ln K$')
axes[1].set_ylabel('$\\ln Y$')
axes[1].set_title('(b) log-log — 기울기 0.3, 단위 변경은 평행이동')
axes[1].legend(loc='lower right', fontsize=8)
plt.tight_layout()
plt.show()
<Figure size 960x360 with 2 Axes>
# 예측 항목 세 개에 대응하는 수치를 한자리에 모은다
d_ln = (np.log(Y2) - np.log(Y1)) / (np.log(K2) - np.log(K1))
print(f'[예측 1] Y 배율 {ratio:.4f} (= 2^0.3), 증가율 {100 * (ratio - 1):.2f}%, Δln Y/Δln K = {d_ln:.6f}')
print('[예측 2] h=1e-3 상대 어긋남  ' + ',  '.join(f'ν={r[0]:.1f}: {r[5]:+.3e}' for r in rows))
print(f'         h 10배 축소 시 오차 비 {rels[1] / rels[0]:.3f}, {rels[2] / rels[1]:.3f}, '
      f'{rels[3] / rels[2]:.3f}')
print(f'[예측 3] Â {np.exp(c1):.4f} → {np.exp(c2):.4f} ({np.exp(c2) / np.exp(c1):.4f}배), '
      f'α̂ 변화 {a2 - a1:+.2e}, s_K {sK["원 단위"]:.6f} → {sK["천 단위"]:.6f}')
[예측 1] Y 배율 1.2311 (= 2^0.3), 증가율 23.11%, Δln Y/Δln K = 0.300000
[예측 2] h=1e-3 상대 어긋남  ν=0.9: -1.722e-06,  ν=1.0: -1.400e-06,  ν=1.1: -1.045e-06
         h 10배 축소 시 오차 비 0.100, 0.100, 0.100
[예측 3] Â 1.0000 → 7.9433 (7.9433배), α̂ 변화 -7.94e-15, s_K 0.300000 → 0.300000

3. 대조

예측과 계산이 어긋난 지점을 적는다. 어느 쪽이 틀렸는지 판정한다.

예측결과어긋남원인

본문 확인: 어긋났으면 (eq-w02-6)·(eq-w02-11)·(eq-w02-7)로 돌아간다.