mirosh111000

Прикладна_економетрика_ЛР№11_Мірошниченко

Dec 16th, 2025
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.23 KB | None | 0 0
  1. import math
  2. import matplotlib.pyplot as plt
  3.  
  4. DEFAULT_SEASON_LEN = 4
  5. MAX_LAG_FOR_CORRELOGRAM = 12
  6. DATASETS = {
  7.     "demo": {
  8.         "name": "Демонстраційний приклад (витрати на рекламу, квартали)",
  9.         "y": [375, 371, 869, 1015, 357, 471, 992, 1020, 390, 355, 992, 905, 461, 454, 920, 927],
  10.         "season_len": 4
  11.     },
  12.     "variant2": {
  13.         "name": "Варіант 2",
  14.         "y": [5.8, 4.5, 5.1, 9.1, 7.0, 5.0, 6.0, 10.1, 7.9, 5.5, 6.3, 10.8, 9.0, 6.5, 7.0, 11.1],
  15.         "season_len": 4
  16.     }
  17. }
  18.  
  19. def title(s):
  20.     print("\n" + "=" * 70)
  21.     print(s)
  22.     print("=" * 70)
  23.  
  24. def fmt(x, d=4):
  25.     if x is None:
  26.         return "-"
  27.     try:
  28.         return f"{float(x):.{d}f}"
  29.     except Exception:
  30.         return str(x)
  31.  
  32. def fmt_int_if_close(x, d=4):
  33.     try:
  34.         xf = float(x)
  35.         if abs(xf - round(xf)) < 1e-12:
  36.             return str(int(round(xf)))
  37.         return f"{xf:.{d}f}"
  38.     except Exception:
  39.         return str(x)
  40.  
  41. def print_table(headers, rows):
  42.     cols = len(headers)
  43.     widths = [len(h) for h in headers]
  44.     for r in rows:
  45.         for j in range(cols):
  46.             widths[j] = max(widths[j], len(str(r[j])))
  47.  
  48.     def line():
  49.         s = "+"
  50.         for w in widths:
  51.             s += "-" * (w + 2) + "+"
  52.         return s
  53.  
  54.     print(line())
  55.     hrow = "|"
  56.     for j, h in enumerate(headers):
  57.         hrow += " " + h.ljust(widths[j]) + " |"
  58.     print(hrow)
  59.     print(line())
  60.  
  61.     for r in rows:
  62.         row_s = "|"
  63.         for j in range(cols):
  64.             row_s += " " + str(r[j]).ljust(widths[j]) + " |"
  65.         print(row_s)
  66.     print(line())
  67.  
  68. def season_index(t1, p):
  69.     return ((t1 - 1) % p) + 1
  70.  
  71. def mean(arr):
  72.     return sum(arr) / len(arr) if arr else 0.0
  73.  
  74. def pearson_autocorr_shifted(y, lag):
  75.     n = len(y)
  76.     if lag <= 0 or lag >= n:
  77.         return 0.0
  78.  
  79.     y1 = y[:-lag]
  80.     y2 = y[lag:]
  81.     m1 = mean(y1)
  82.     m2 = mean(y2)
  83.  
  84.     num = 0.0
  85.     s1 = 0.0
  86.     s2 = 0.0
  87.     for a, b in zip(y1, y2):
  88.         da = a - m1
  89.         db = b - m2
  90.         num += da * db
  91.         s1 += da * da
  92.         s2 += db * db
  93.  
  94.     den = math.sqrt(s1 * s2)
  95.     return num / den if den != 0 else 0.0
  96.  
  97. def moving_average(y, p):
  98.     n = len(y)
  99.     return [sum(y[i:i+p]) / p for i in range(n - p + 1)]
  100.  
  101. def centered_moving_average(ma):
  102.     return [(ma[i] + ma[i+1]) / 2 for i in range(len(ma) - 1)]
  103.  
  104. def estimate_seasonals(y, p, kind):
  105.     ma = moving_average(y, p)
  106.     if p % 2 == 0:
  107.         cma = centered_moving_average(ma)
  108.         start_t = p // 2 + 1
  109.     else:
  110.         cma = ma[:]
  111.         start_t = (p + 1) // 2
  112.  
  113.     t_cma = {start_t + i: cma[i] for i in range(len(cma))}
  114.  
  115.     raw_by_season = {i: [] for i in range(1, p + 1)}
  116.     raw_by_t = {}
  117.  
  118.     for t, cm in t_cma.items():
  119.         yt = y[t - 1]
  120.         if kind == "additive":
  121.             s = yt - cm
  122.         else:
  123.             s = yt / cm if cm != 0 else 0.0
  124.         raw_by_t[t] = s
  125.         raw_by_season[season_index(t, p)].append(s)
  126.  
  127.     avg = {}
  128.     for i in range(1, p + 1):
  129.         vals = raw_by_season[i]
  130.         avg[i] = sum(vals) / len(vals) if vals else 0.0
  131.  
  132.     if kind == "additive":
  133.         k = sum(avg.values()) / p
  134.         seasonal = {i: avg[i] - k for i in avg}
  135.     else:
  136.         ssum = sum(avg.values())
  137.         k = (p / ssum) if ssum != 0 else 1.0
  138.         seasonal = {i: avg[i] * k for i in avg}
  139.  
  140.     return {
  141.         "ma": ma,
  142.         "cma": cma,
  143.         "t_cma": t_cma,
  144.         "raw_by_t": raw_by_t,
  145.         "avg_seasonal": avg,
  146.         "seasonal": seasonal
  147.     }
  148.  
  149. def deseasonalize(y, seasonal, p, kind):
  150.     tau = []
  151.     for t in range(1, len(y) + 1):
  152.         s = seasonal[season_index(t, p)]
  153.         if kind == "additive":
  154.             tau.append(y[t - 1] - s)
  155.         else:
  156.             tau.append(y[t - 1] / s if s != 0 else 0.0)
  157.     return tau
  158.  
  159. def fit_linear_trend(tau):
  160.     n = len(tau)
  161.     t_vals = list(range(1, n + 1))
  162.     sum_t = sum(t_vals)
  163.     sum_t2 = sum(v * v for v in t_vals)
  164.     sum_tau = sum(tau)
  165.     sum_ttau = sum(t_vals[i] * tau[i] for i in range(n))
  166.  
  167.     den = n * sum_t2 - sum_t * sum_t
  168.     a1 = (n * sum_ttau - sum_t * sum_tau) / den if den != 0 else 0.0
  169.     a0 = (sum_tau / n) - a1 * (sum_t / n)
  170.     return a0, a1
  171.  
  172. def build_yhat(a0, a1, seasonal, n, p, kind):
  173.     yhat = []
  174.     for t in range(1, n + 1):
  175.         trend = a0 + a1 * t
  176.         s = seasonal[season_index(t, p)]
  177.         if kind == "additive":
  178.             yhat.append(trend + s)
  179.         else:
  180.             yhat.append(trend * s)
  181.     return yhat
  182.  
  183. def r_squared(y, yhat):
  184.     ybar = mean(y)
  185.     sst = sum((v - ybar) ** 2 for v in y)
  186.     sse = sum((y[i] - yhat[i]) ** 2 for i in range(len(y)))
  187.     r2 = 1.0 - (sse / sst) if sst != 0 else 0.0
  188.     return r2, sse, sst
  189.  
  190. def forecast_2(a0, a1, seasonal, n, p, kind):
  191.     out = []
  192.     for h in (1, 2):
  193.         t = n + h
  194.         trend = a0 + a1 * t
  195.         s = seasonal[season_index(t, p)]
  196.         yh = (trend + s) if kind == "additive" else (trend * s)
  197.         out.append((t, trend, s, yh))
  198.     return out
  199.  
  200. def plot_series(y, name):
  201.     t = list(range(1, len(y) + 1))
  202.     plt.figure()
  203.     plt.plot(t, y, marker="o")
  204.     plt.title(f"Кореляційне поле (t–y): {name}")
  205.     plt.xlabel("t")
  206.     plt.ylabel("y")
  207.     plt.grid(True)
  208.  
  209. def plot_correlogram(lags, rvals, name):
  210.     plt.figure()
  211.     plt.bar(lags, rvals)
  212.     plt.title(f"Корелограма (autocorr): {name}")
  213.     plt.xlabel("lag l")
  214.     plt.ylabel("r_l")
  215.     plt.grid(True, axis="y")
  216.  
  217. def plot_fact_vs_theor(y, yhat, name):
  218.     t = list(range(1, len(y) + 1))
  219.     plt.figure()
  220.     plt.plot(t, y, marker="o", label="Факт y_t")
  221.     plt.plot(t, yhat, marker="x", label="Теорія ŷ_t")
  222.     plt.title(name)
  223.     plt.xlabel("t")
  224.     plt.ylabel("y")
  225.     plt.grid(True)
  226.     plt.legend()
  227.  
  228. def run_dataset(ds_key):
  229.     ds = DATASETS[ds_key]
  230.     name = ds["name"]
  231.     y = ds["y"]
  232.     p = ds.get("season_len", DEFAULT_SEASON_LEN)
  233.     n = len(y)
  234.  
  235.     title(f"АНАЛІЗ ДАНИХ: {name}")
  236.     print(f"n = {n}, сезон p = {p}")
  237.  
  238.     print("\n--- 1) Вихідні дані ---")
  239.     rows = [[t, fmt_int_if_close(y[t-1], 4)] for t in range(1, n + 1)]
  240.     print_table(["t", "y_t"], rows)
  241.  
  242.     print("\n--- 2) Кореляційне поле ---")
  243.     plot_series(y, name)
  244.  
  245.     print("\n--- 3) Автокореляція ---")
  246.     max_lag = min(MAX_LAG_FOR_CORRELOGRAM, n - 1)
  247.     lags = list(range(1, max_lag + 1))
  248.     rvals = [pearson_autocorr_shifted(y, lag) for lag in lags]
  249.  
  250.     rows = [[lag, fmt(r, 4), fmt(r, 6)] for lag, r in zip(lags, rvals)]
  251.     print_table(["Lag", "r (4 знаки)", "r (6 знаків)"], rows)
  252.     plot_correlogram(lags, rvals, name)
  253.  
  254.     title("АДИТИВНА МОДЕЛЬ")
  255.     add = estimate_seasonals(y, p, kind="additive")
  256.  
  257.     print("\n--- 4.1) MA(p) та CMA (для p=4) ---")
  258.     ma_rows = [[i, fmt(add["ma"][i-1], 2)] for i in range(1, len(add["ma"]) + 1)]
  259.     print_table([f"MA індекс", f"MA({p})"], ma_rows)
  260.  
  261.     start_t = p // 2 + 1 if p % 2 == 0 else (p + 1) // 2
  262.     cma_rows = [[start_t + i, fmt(add["cma"][i], 2)] for i in range(len(add["cma"]))]
  263.     print_table(["t (для CMA)", "CMA_t"], cma_rows)
  264.  
  265.     print("\n--- 4.2) Оцінки сезонності: s_t = y_t - CMA_t ---")
  266.     raw_rows = [[t, fmt(add["raw_by_t"][t], 2)] for t in sorted(add["raw_by_t"].keys())]
  267.     print_table(["t", "s_t"], raw_rows)
  268.  
  269.     print("\n--- 4.3) Сезонні середні та скориговані S_i (сума = 0) ---")
  270.     s_rows = []
  271.     for i in range(1, p + 1):
  272.         s_rows.append([i, fmt(add["avg_seasonal"][i], 2), fmt(add["seasonal"][i], 2)])
  273.     print_table(["сезон i", "середнє (до корекц.)", "S_i (після корекц.)"], s_rows)
  274.  
  275.     print("S_i:")
  276.     for i in range(1, p + 1):
  277.         print(f"  S{i} = {fmt(add['seasonal'][i], 4)}")
  278.     print("Контроль суми S_i =", fmt(sum(add["seasonal"].values()), 6))
  279.  
  280.     tau_add = deseasonalize(y, add["seasonal"], p, kind="additive")
  281.     a0_add, a1_add = fit_linear_trend(tau_add)
  282.  
  283.     print("\n--- 4.4) Тренд τ̂(t)=a0+a1·t ---")
  284.     print(f"a0 = {fmt(a0_add, 4)}")
  285.     print(f"a1 = {fmt(a1_add, 7)}")
  286.     print(f"Рівняння: τ̂(t) = {fmt(a0_add, 4)} + {fmt(a1_add, 7)}·t")
  287.  
  288.     yhat_add = build_yhat(a0_add, a1_add, add["seasonal"], n, p, kind="additive")
  289.     r2_add, sse_add, sst_add = r_squared(y, yhat_add)
  290.  
  291.     print("\n--- 4.5) Якість (R²) ---")
  292.     print(f"SSE = {fmt(sse_add, 4)}")
  293.     print(f"SST = {fmt(sst_add, 4)}")
  294.     print(f"R²  = {fmt(r2_add, 4)}  (тобто {fmt(r2_add * 100.0, 2)}%)")
  295.  
  296.     print("\n--- 4.6) Прогноз на t=[n+1, n+2] (адитивна) ---")
  297.     fc = forecast_2(a0_add, a1_add, add["seasonal"], n, p, kind="additive")
  298.     fc_rows = [[t, fmt(tr, 4), fmt(s, 4), fmt(yh, 4)] for (t, tr, s, yh) in fc]
  299.     print_table(["t", "τ̂_t", "S_i", "ŷ_t прогноз"], fc_rows)
  300.  
  301.     plot_fact_vs_theor(y, yhat_add, f"Адитивна модель: факт vs теорія ({name})")
  302.  
  303.     title("МУЛЬТИПЛІКАТИВНА МОДЕЛЬ")
  304.     mul = estimate_seasonals(y, p, kind="multiplicative")
  305.  
  306.     print("\n--- 5.1) Оцінки сезонності: s_t = y_t / CMA_t ---")
  307.     raw_rows = [[t, fmt(mul["raw_by_t"][t], 4)] for t in sorted(mul["raw_by_t"].keys())]
  308.     print_table(["t", "s_t"], raw_rows)
  309.  
  310.     print("\n--- 5.2) Сезонні середні та скориговані S_i (сума = p) ---")
  311.     s_rows = []
  312.     for i in range(1, p + 1):
  313.         s_rows.append([i, fmt(mul["avg_seasonal"][i], 4), fmt(mul["seasonal"][i], 4)])
  314.     print_table(["сезон i", "середнє (до корекц.)", "S_i (після корекц.)"], s_rows)
  315.     print("Контроль суми S_i =", fmt(sum(mul["seasonal"].values()), 6))
  316.  
  317.     tau_mul = deseasonalize(y, mul["seasonal"], p, kind="multiplicative")
  318.     a0_mul, a1_mul = fit_linear_trend(tau_mul)
  319.  
  320.     print("\n--- 5.3) Тренд τ̂(t)=a0+a1·t ---")
  321.     print(f"a0 = {fmt(a0_mul, 4)}")
  322.     print(f"a1 = {fmt(a1_mul, 7)}")
  323.     print(f"Рівняння: τ̂(t) = {fmt(a0_mul, 4)} + {fmt(a1_mul, 7)}·t")
  324.  
  325.     yhat_mul = build_yhat(a0_mul, a1_mul, mul["seasonal"], n, p, kind="multiplicative")
  326.     r2_mul, sse_mul, sst_mul = r_squared(y, yhat_mul)
  327.  
  328.     print("\n--- 5.4) Якість (R²) ---")
  329.     print(f"SSE = {fmt(sse_mul, 4)}")
  330.     print(f"SST = {fmt(sst_mul, 4)}")
  331.     print(f"R²  = {fmt(r2_mul, 4)}  (тобто {fmt(r2_mul * 100.0, 2)}%)")
  332.  
  333.     print("\n--- 5.5) Прогноз на t=[n+1, n+2] (мультиплікативна) ---")
  334.     fc = forecast_2(a0_mul, a1_mul, mul["seasonal"], n, p, kind="multiplicative")
  335.     fc_rows = [[t, fmt(tr, 4), fmt(s, 4), fmt(yh, 4)] for (t, tr, s, yh) in fc]
  336.     print_table(["t", "τ̂_t", "S_i", "ŷ_t прогноз"], fc_rows)
  337.  
  338.     plot_fact_vs_theor(y, yhat_mul, f"Мультиплікативна модель: факт vs теорія ({name})")
  339.  
  340.     title("ПОРІВНЯННЯ МОДЕЛЕЙ (за R²)")
  341.     print(f"R² (адитивна)         = {fmt(r2_add, 4)}")
  342.     print(f"R² (мультиплікативна) = {fmt(r2_mul, 4)}")
  343.  
  344.  
  345. def main():
  346.     run_dataset("demo")
  347.     run_dataset("variant2")
  348.     plt.show()
  349.  
  350. if __name__ == "__main__":
  351.     main()
  352.  
Advertisement
Add Comment
Please, Sign In to add comment