Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import math
- ALPHA = 0.05
- M = 4
- TRAIN_START, TRAIN_END = 1, 17
- TEST_START, TEST_END = 18, 20
- FORECAST_START, FORECAST_END = 21, 24
- T_CRIT_DF12_A005 = 2.178812829667228
- F_CRIT_4_12_A005 = 3.259166726901247
- DATA = [
- (1, 52.0, 72.0, 13.0, 2.7, 5.0),
- (2, 53.0, 74.0, 12.5, 2.8, 5.5),
- (3, 50.0, 72.0, 12.0, 3.0, 5.0),
- (4, 51.0, 73.0, 11.0, 3.2, 6.0),
- (5, 54.0, 70.0, 10.1, 3.2, 7.0),
- (6, 55.0, 67.0, 9.0, 3.3, 8.0),
- (7, 57.0, 67.0, 8.5, 3.4, 10.0),
- (8, 52.0, 62.0, 8.2, 3.6, 10.0),
- (9, 60.0, 72.0, 8.0, 3.7, 10.5),
- (10, 60.0, 72.0, 5.5, 3.7, 11.0),
- (11, 62.0, 74.0, 5.0, 3.4, 13.0),
- (12, 64.0, 75.0, 4.7, 4.0, 10.0),
- (13, 65.0, 76.0, 4.6, 4.2, 12.0),
- (14, 67.0, 80.0, 4.0, 4.3, 13.0),
- (15, 67.0, 82.0, 4.1, 4.7, 14.0),
- (16, 62.0, 84.0, 4.2, 4.8, 14.5),
- (17, 63.0, 84.0, 4.5, 4.8, 15.5),
- (18, 66.0, 87.0, 4.0, 4.9, 17.0),
- (19, 68.0, 90.0, 4.0, 5.0, 16.5),
- (20, 70.0, 92.0, 3.0, 4.7, 17.5),
- (21, None, 92.0, 4.0, 5.2, 17.6),
- (22, None, 93.0, 5.0, 5.3, 17.7),
- (23, None, 93.0, 5.0, 5.4, 17.8),
- (24, None, 94.0, 6.0, 5.4, 17.9),
- ]
- def fmt(x, nd=6):
- if x is None:
- return "None"
- if isinstance(x, (int,)) and nd == 0:
- return str(x)
- if isinstance(x, float):
- return f"{x:.{nd}f}"
- return str(x)
- def line(title, w=60):
- print("\n" + title)
- print("-" * w)
- def print_table(headers, rows, nd=6):
- srows = []
- for r in rows:
- srows.append([fmt(v, nd) if isinstance(v, float) else fmt(v) for v in r])
- widths = [len(h) for h in headers]
- for r in srows:
- for j, cell in enumerate(r):
- widths[j] = max(widths[j], len(cell))
- def row_to_str(rr):
- return " | ".join(rr[j].rjust(widths[j]) for j in range(len(headers)))
- print(row_to_str(headers))
- print("-+-".join("-" * widths[j] for j in range(len(headers))))
- for r in srows:
- print(row_to_str(r))
- def mat_transpose(A):
- return [list(row) for row in zip(*A)]
- def mat_mul(A, B):
- r, k = len(A), len(A[0])
- k2, c = len(B), len(B[0])
- if k != k2:
- raise ValueError("mat_mul: несумісні розміри")
- C = [[0.0] * c for _ in range(r)]
- for i in range(r):
- for j in range(c):
- s = 0.0
- for t in range(k):
- s += A[i][t] * B[t][j]
- C[i][j] = s
- return C
- def mat_vec_mul(A, v):
- r, c = len(A), len(A[0])
- if len(v) != c:
- raise ValueError("mat_vec_mul: несумісні розміри")
- out = [0.0] * r
- for i in range(r):
- s = 0.0
- for j in range(c):
- s += A[i][j] * v[j]
- out[i] = s
- return out
- def identity(n):
- I = [[0.0] * n for _ in range(n)]
- for i in range(n):
- I[i][i] = 1.0
- return I
- def mat_inverse(A):
- n = len(A)
- if n == 0 or len(A[0]) != n:
- raise ValueError("mat_inverse: матриця має бути квадратною")
- aug = [A[i][:] + identity(n)[i][:] for i in range(n)]
- for col in range(n):
- pivot = col
- best = abs(aug[col][col])
- for r in range(col + 1, n):
- val = abs(aug[r][col])
- if val > best:
- best = val
- pivot = r
- if best < 1e-15:
- raise ValueError("mat_inverse: матриця вироджена або майже вироджена")
- if pivot != col:
- aug[col], aug[pivot] = aug[pivot], aug[col]
- piv = aug[col][col]
- invp = 1.0 / piv
- for j in range(2 * n):
- aug[col][j] *= invp
- for r in range(n):
- if r == col:
- continue
- factor = aug[r][col]
- if abs(factor) < 1e-18:
- continue
- for j in range(2 * n):
- aug[r][j] -= factor * aug[col][j]
- inv = [[aug[i][j] for j in range(n, 2 * n)] for i in range(n)]
- return inv
- def to_rows(data):
- rows = []
- for (month, y, x1, x2, x3, x4) in data:
- rows.append({
- "month": month,
- "Y": y,
- "X1": float(x1),
- "X2": float(x2),
- "X3": float(x3),
- "X4": float(x4),
- })
- return rows
- def slice_rows(rows, a, b):
- return [r for r in rows if a <= r["month"] <= b]
- def mean(vals):
- return sum(vals) / len(vals)
- def build_XY_linear(rows):
- X = []
- y = []
- for r in rows:
- if r["Y"] is None:
- continue
- X.append([1.0, r["X1"], r["X2"], r["X3"], r["X4"]])
- y.append(float(r["Y"]))
- return X, y
- def ols_fit(X, y):
- Xt = mat_transpose(X)
- XtX = mat_mul(Xt, X)
- XtX_inv = mat_inverse(XtX)
- XtY = []
- for i in range(len(Xt)):
- s = 0.0
- for k in range(len(y)):
- s += Xt[i][k] * y[k]
- XtY.append([s])
- beta_col = mat_mul(XtX_inv, XtY)
- beta = [beta_col[i][0] for i in range(len(beta_col))]
- return beta, XtX_inv
- def predict_linear(rows, beta):
- out = []
- for r in rows:
- x = [1.0, r["X1"], r["X2"], r["X3"], r["X4"]]
- yhat = 0.0
- for j in range(len(beta)):
- yhat += beta[j] * x[j]
- out.append(yhat)
- return out
- def regression_stats(y, yhat, m):
- n = len(y)
- ybar = mean(y)
- sst = sum((yi - ybar) ** 2 for yi in y)
- sse = sum((y[i] - yhat[i]) ** 2 for i in range(n))
- ssr = sum((yhat[i] - ybar) ** 2 for i in range(n))
- r2 = 1.0 - (sse / sst) if sst != 0.0 else 0.0
- R = math.sqrt(max(0.0, r2))
- denom = (n - m - 1)
- r2_adj = 1.0 - (1.0 - r2) * (n - 1) / denom if denom > 0 else float("nan")
- Su = math.sqrt(sse / denom) if denom > 0 else float("nan")
- return {
- "n": n, "m": m,
- "ybar": ybar,
- "SST": sst, "SSE": sse, "SSR": ssr,
- "R": R, "R2": r2, "R2_adj": r2_adj,
- "Su": Su
- }
- def anova_and_F(stats):
- n = stats["n"]
- m = stats["m"]
- ssr = stats["SSR"]
- sse = stats["SSE"]
- df_reg = m
- df_res = n - m - 1
- df_tot = n - 1
- msr = ssr / df_reg if df_reg > 0 else float("nan")
- mse = sse / df_res if df_res > 0 else float("nan")
- F = msr / mse if mse != 0.0 else float("inf")
- return {
- "df_reg": df_reg, "df_res": df_res, "df_tot": df_tot,
- "msr": msr, "mse": mse, "F": F
- }
- def t_tests(beta, XtX_inv, Su, df_res):
- se = []
- tvals = []
- for i in range(len(beta)):
- v = Su * math.sqrt(max(0.0, XtX_inv[i][i]))
- se.append(v)
- tvals.append(beta[i] / v if v != 0.0 else float("inf"))
- return se, tvals
- def build_XY_power(rows):
- X = []
- y = []
- for r in rows:
- if r["Y"] is None:
- continue
- X.append([1.0, math.log(r["X1"]), math.log(r["X2"]), math.log(r["X3"]), math.log(r["X4"])])
- y.append(math.log(float(r["Y"])))
- return X, y
- def predict_power(rows, beta_log):
- out = []
- for r in rows:
- lnY = beta_log[0]
- lnY += beta_log[1] * math.log(r["X1"])
- lnY += beta_log[2] * math.log(r["X2"])
- lnY += beta_log[3] * math.log(r["X3"])
- lnY += beta_log[4] * math.log(r["X4"])
- out.append(math.exp(lnY))
- return out
- def econ_linear(train_rows, beta):
- y = [r["Y"] for r in train_rows]
- ybar = mean(y)
- xbar = {
- "X1": mean([r["X1"] for r in train_rows]),
- "X2": mean([r["X2"] for r in train_rows]),
- "X3": mean([r["X3"] for r in train_rows]),
- "X4": mean([r["X4"] for r in train_rows]),
- }
- P = {k: (ybar / xbar[k]) for k in xbar}
- marg = {"X1": beta[1], "X2": beta[2], "X3": beta[3], "X4": beta[4]}
- E = {k: (marg[k] * xbar[k] / ybar) for k in xbar}
- A = sum(E[k] for k in ["X1", "X2", "X3", "X4"])
- return ybar, xbar, P, marg, E, A
- def econ_power(train_rows, beta_log):
- y = [r["Y"] for r in train_rows]
- ybar = mean(y)
- xbar = {
- "X1": mean([r["X1"] for r in train_rows]),
- "X2": mean([r["X2"] for r in train_rows]),
- "X3": mean([r["X3"] for r in train_rows]),
- "X4": mean([r["X4"] for r in train_rows]),
- }
- E = {"X1": beta_log[1], "X2": beta_log[2], "X3": beta_log[3], "X4": beta_log[4]}
- marg = {k: (E[k] * ybar / xbar[k]) for k in xbar}
- P = {k: (ybar / xbar[k]) for k in xbar}
- A = E["X1"] + E["X2"] + E["X3"] + E["X4"]
- return ybar, xbar, P, marg, E, A
- def substitution_linear(beta):
- a = {"X1": beta[1], "X2": beta[2], "X3": beta[3], "X4": beta[4]}
- keys = ["X1", "X2", "X3", "X4"]
- hk = {}
- for k in keys:
- for j in keys:
- if k == j:
- continue
- denom = a[k]
- hk[f"h{k[-1]}{j[-1]}"] = (-a[j] / denom) if denom != 0.0 else float("nan")
- return hk
- def substitution_power(beta_log, train_rows):
- E = {"X1": beta_log[1], "X2": beta_log[2], "X3": beta_log[3], "X4": beta_log[4]}
- xbar = {
- "X1": mean([r["X1"] for r in train_rows]),
- "X2": mean([r["X2"] for r in train_rows]),
- "X3": mean([r["X3"] for r in train_rows]),
- "X4": mean([r["X4"] for r in train_rows]),
- }
- keys = ["X1", "X2", "X3", "X4"]
- hk = {}
- for k in keys:
- for j in keys:
- if k == j:
- continue
- denom = E[k]
- hk[f"h{k[-1]}{j[-1]}"] = (-(E[j] / denom) * (xbar[k] / xbar[j])) if denom != 0.0 else float("nan")
- return hk
- def forecast_metrics(y_true, y_pred):
- n = len(y_true)
- err = [y_pred[i] - y_true[i] for i in range(n)]
- mae = sum(abs(e) for e in err) / n
- mse = sum(e * e for e in err) / n
- mape = (sum(abs(err[i]) / y_true[i] for i in range(n)) / n) * 100.0
- rmse = math.sqrt(sum((y_pred[i] - y_true[i]) ** 2 for i in range(n)) / n)
- denom = math.sqrt(sum(y_true[i] ** 2 for i in range(n)) / n) + math.sqrt(sum(y_pred[i] ** 2 for i in range(n)) / n)
- theil = rmse / denom if denom != 0.0 else float("nan")
- return mae, mse, mape, theil
- def main():
- rows_all = to_rows(DATA)
- print("=== ЕКОНОМЕТРИЧНА МОДЕЛЬ ПРОДУКТИВНОСТІ ПРАЦІ ===")
- print("Y – продуктивність праці")
- print("X1 – фондомісткість продукції")
- print("X2 – коефіцієнт плинності робочої сили")
- print("X3 – процент втрат робочого часу")
- print("X4 – стаж роботи")
- train_rows = slice_rows(rows_all, TRAIN_START, TRAIN_END)
- test_rows = slice_rows(rows_all, TEST_START, TEST_END)
- future_rows = slice_rows(rows_all, FORECAST_START, FORECAST_END)
- line("Вихідні дані (перші/останні рядки)")
- head = rows_all[:6]
- tail = rows_all[-6:]
- out = []
- for r in head + tail:
- out.append([r["month"], r["Y"], r["X1"], r["X2"], r["X3"], r["X4"]])
- print_table(["month", "Y", "X1", "X2", "X3", "X4"], out, nd=3)
- line("Лінійна модель (МНК) на 1–17")
- X_lin, y_lin = build_XY_linear(train_rows)
- beta_lin, XtX_inv_lin = ols_fit(X_lin, y_lin)
- yhat_lin_train = mat_vec_mul(X_lin, beta_lin)
- stats_lin = regression_stats(y_lin, yhat_lin_train, M)
- anova_lin = anova_and_F(stats_lin)
- se_lin, t_lin = t_tests(beta_lin, XtX_inv_lin, stats_lin["Su"], anova_lin["df_res"])
- print("Рівняння:")
- print(f"Ŷ = {fmt(beta_lin[0], 4)} + {fmt(beta_lin[1], 4)}·X1 {fmt(beta_lin[2], 4)}·X2 {fmt(beta_lin[3], 4)}·X3 {fmt(beta_lin[4], 4)}·X4")
- print("\nРегресійна статистика:")
- print_table(
- ["Показник", "Значення"],
- [
- ["R", stats_lin["R"]],
- ["R^2", stats_lin["R2"]],
- ["R^2 (Амемія)", stats_lin["R2_adj"]],
- ["n", stats_lin["n"]],
- ["m", stats_lin["m"]],
- ["S_u", stats_lin["Su"]],
- ],
- nd=9
- )
- print("\nДисперсійний аналіз (ANOVA):")
- print_table(
- ["Джерело", "df", "SS", "MS"],
- [
- ["Регресії", anova_lin["df_reg"], stats_lin["SSR"], anova_lin["msr"]],
- ["Залишків", anova_lin["df_res"], stats_lin["SSE"], anova_lin["mse"]],
- ["Загальна", anova_lin["df_tot"], stats_lin["SST"], ""],
- ],
- nd=9
- )
- print("\nПеревірка значущості моделі (F-тест):")
- print(f"F = {fmt(anova_lin['F'], 6)}; F_кр(α=0.05, df1=4, df2=12) = {fmt(F_CRIT_4_12_A005, 6)}")
- print("Висновок:", "модель значуща" if anova_lin["F"] > F_CRIT_4_12_A005 else "модель незначуща")
- print("\nЗначущість параметрів (t-тест, df=12):")
- print(f"t_кр(α=0.05, df=12) = {fmt(T_CRIT_DF12_A005, 6)}")
- trows = []
- for i, name in enumerate(["a0", "a1", "a2", "a3", "a4"]):
- sig = "значущий" if abs(t_lin[i]) > T_CRIT_DF12_A005 else "незначущий"
- trows.append([name, beta_lin[i], se_lin[i], t_lin[i], sig])
- print_table(["парам", "оцінка", "S(a)", "t", "висновок"], trows, nd=9)
- line("Степенева модель через логарифмування (МНК) на 1–17")
- X_log, y_log = build_XY_power(train_rows)
- beta_log, XtX_inv_log = ols_fit(X_log, y_log)
- yhat_log_train = mat_vec_mul(X_log, beta_log)
- stats_log = regression_stats(y_log, yhat_log_train, M)
- anova_log = anova_and_F(stats_log)
- se_log, t_log = t_tests(beta_log, XtX_inv_log, stats_log["Su"], anova_log["df_res"])
- a0_pow = math.exp(beta_log[0])
- print("Рівняння (у логарифмах):")
- print(f"lnŶ = {fmt(beta_log[0], 6)} + {fmt(beta_log[1], 6)}·lnX1 + {fmt(beta_log[2], 6)}·lnX2 + {fmt(beta_log[3], 6)}·lnX3 + {fmt(beta_log[4], 6)}·lnX4")
- print("Еквівалент у вихідному масштабі:")
- print(f"Ŷ = {fmt(a0_pow, 6)} · X1^{fmt(beta_log[1], 6)} · X2^{fmt(beta_log[2], 6)} · X3^{fmt(beta_log[3], 6)} · X4^{fmt(beta_log[4], 6)}")
- print("\nРегресійна статистика (для lnY):")
- print_table(
- ["Показник", "Значення"],
- [
- ["R", stats_log["R"]],
- ["R^2", stats_log["R2"]],
- ["R^2 (Амемія)", stats_log["R2_adj"]],
- ["n", stats_log["n"]],
- ["m", stats_log["m"]],
- ["S_u", stats_log["Su"]],
- ],
- nd=9
- )
- print("\nПеревірка значущості моделі (F-тест):")
- print(f"F = {fmt(anova_log['F'], 6)}; F_кр(α=0.05, df1=4, df2=12) = {fmt(F_CRIT_4_12_A005, 6)}")
- print("Висновок:", "модель значуща" if anova_log["F"] > F_CRIT_4_12_A005 else "модель незначуща")
- print("\nЗначущість параметрів (t-тест, df=12):")
- print(f"t_кр(α=0.05, df=12) = {fmt(T_CRIT_DF12_A005, 6)}")
- trows = []
- for i, name in enumerate(["b0", "b1", "b2", "b3", "b4"]):
- sig = "значущий" if abs(t_log[i]) > T_CRIT_DF12_A005 else "незначущий"
- trows.append([name, beta_log[i], se_log[i], t_log[i], sig])
- print_table(["парам", "оцінка", "S(b)", "t", "висновок"], trows, nd=9)
- line("Економічні характеристики (на середніх значеннях 1–17)")
- ybar_l, xbar_l, P_l, marg_l, E_l, A_l = econ_linear(train_rows, beta_lin)
- print("Лінійна модель:")
- rows_e = []
- for k in ["X1", "X2", "X3", "X4"]:
- rows_e.append([k, xbar_l[k], P_l[k], marg_l[k], E_l[k]])
- print_table(["чинник", "X̄", "Pj=Ȳ/X̄", "dY/dX", "E (на середніх)"], rows_e, nd=9)
- print(f"Загальна еластичність A = ΣE = {fmt(A_l, 6)}")
- print(f"Інтерпретація: якщо всі чинники зростають на 1%, Y зміниться приблизно на {fmt(A_l, 4)}% (для лінійної).")
- sub_l = substitution_linear(beta_lin)
- print("\nНорми заміщення (лінійна): hk_j = -a_j/a_k")
- keys_order = ["h12", "h13", "h14", "h21", "h23", "h24", "h31", "h32", "h34", "h41", "h42", "h43"]
- sub_rows = [[k, sub_l[k]] for k in keys_order]
- print_table(["показник", "значення"], sub_rows, nd=6)
- ybar_p, xbar_p, P_p, marg_p, E_p, A_p = econ_power(train_rows, beta_log)
- print("\nСтепенева модель:")
- rows_e = []
- for k in ["X1", "X2", "X3", "X4"]:
- rows_e.append([k, xbar_p[k], P_p[k], marg_p[k], E_p[k]])
- print_table(["чинник", "X̄", "Pj=Ȳ/X̄", "dY/dX (на середніх)", "E=a_j"], rows_e, nd=9)
- print(f"Загальна еластичність A = Σa_j = {fmt(A_p, 6)}")
- print(f"Інтерпретація: якщо всі чинники зростають на 1%, Y зміниться приблизно на {fmt(A_p, 4)}% (для степеневої).")
- sub_p = substitution_power(beta_log, train_rows)
- print("\nНорми заміщення (степенева, на середніх): hk_j = -(a_j/a_k) * (X̄k/X̄j)")
- sub_rows = [[k, sub_p[k]] for k in keys_order]
- print_table(["показник", "значення"], sub_rows, nd=6)
- line("Перевірка прогнозу на 18–20 (MAE, MSE, MAPE, Тейл)")
- y_test = [r["Y"] for r in test_rows]
- yhat_test_lin = predict_linear(test_rows, beta_lin)
- yhat_test_pow = predict_power(test_rows, beta_log)
- cmp_rows = []
- for i in range(len(test_rows)):
- r = test_rows[i]
- cmp_rows.append([
- r["month"],
- y_test[i],
- yhat_test_lin[i],
- (yhat_test_lin[i] - y_test[i]),
- yhat_test_pow[i],
- (yhat_test_pow[i] - y_test[i]),
- ])
- print_table(["month", "Y", "Ŷ_lin", "u_lin", "Ŷ_pow", "u_pow"], cmp_rows, nd=6)
- mae_l, mse_l, mape_l, theil_l = forecast_metrics(y_test, yhat_test_lin)
- mae_p, mse_p, mape_p, theil_p = forecast_metrics(y_test, yhat_test_pow)
- print("\nПоказники якості прогнозу:")
- print_table(
- ["Модель", "MAE", "MSE", "MAPE,%", "Тейл"],
- [
- ["Лінійна", mae_l, mse_l, mape_l, theil_l],
- ["Степенева", mae_p, mse_p, mape_p, theil_p],
- ],
- nd=9
- )
- line("Прогноз Ŷ на 21–24 (за очікуваними X)")
- yhat_future_lin = predict_linear(future_rows, beta_lin)
- yhat_future_pow = predict_power(future_rows, beta_log)
- out_rows = []
- for i in range(len(future_rows)):
- r = future_rows[i]
- out_rows.append([
- r["month"], r["X1"], r["X2"], r["X3"], r["X4"],
- yhat_future_lin[i], yhat_future_pow[i], (yhat_future_pow[i] - yhat_future_lin[i])
- ])
- print_table(["month", "X1", "X2", "X3", "X4", "Ŷ_lin", "Ŷ_pow", "Δ(pow-lin)"], out_rows, nd=6)
- line("Висновки")
- print("1) Значущість моделей (F):")
- print(f" Лінійна: F={fmt(anova_lin['F'], 4)} > Fкр={fmt(F_CRIT_4_12_A005, 4)} -> значуща")
- print(f" Степенева: F={fmt(anova_log['F'], 4)} > Fкр={fmt(F_CRIT_4_12_A005, 4)} -> значуща")
- print("\n2) Значущі параметри (t, α=0.05, df=12):")
- sig_lin = [("a"+str(i), abs(t_lin[i]) > T_CRIT_DF12_A005) for i in range(5)]
- sig_pow = [("b"+str(i), abs(t_log[i]) > T_CRIT_DF12_A005) for i in range(5)]
- print(" Лінійна:", ", ".join([f"{n}:{'+' if ok else '-'}" for n, ok in sig_lin]))
- print(" Степенева:", ", ".join([f"{n}:{'+' if ok else '-'}" for n, ok in sig_pow]))
- print("\n3) Загальна еластичність:")
- print(f" Лінійна A = {fmt(A_l, 6)} (≈ {fmt(A_l, 4)}% при +1% усіх X)")
- print(f" Степенева A = {fmt(A_p, 6)} (≈ {fmt(A_p, 4)}% при +1% усіх X)")
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment