import math import numpy as np import pandas as pd y = [1.55, 3.80, 5.40, 2.60, 5.60, 8.30, 7.30, 8.40, 4.20, 5.60] x1 = [0.30, 0.60, 1.10, 0.20, 0.80, 1.60, 1.50, 0.90, 0.90, 0.80] x2 = [0.80, 1.90, 2.70, 1.30, 2.80, 4.10, 3.60, 4.20, 2.10, 2.80] def _col(v): v = np.asarray(v).reshape(-1) return v[:, None] def design_matrix(x1, x2, intercept=True): x1c = _col(x1) x2c = _col(x2) if intercept: ones = np.ones_like(x1c) X = np.hstack([ones, x1c, x2c]) else: X = np.hstack([x1c, x2c]) return X def safe_inv(M): try: return np.linalg.inv(M) except np.linalg.LinAlgError: return np.linalg.pinv(M) def _log_beta(a, b): return math.lgamma(a) + math.lgamma(b) - math.lgamma(a + b) def _betacf(a, b, x, max_iter=200, eps=3e-14): am, bm = 1.0, 1.0 az = 1.0 qab = a + b qap = a + 1.0 qam = a - 1.0 bz = 1.0 - qab * x / qap if abs(bz) < 1e-300: bz = 1e-300 em, tem = 0.0, 0.0 d = 0.0 ap, bp = 0.0, 0.0 for m in range(1, max_iter + 1): em = float(m) tem = em + em d = em * (b - em) * x / ((qam + tem) * (a + tem)) ap = az + d * am bp = bz + d * bm if abs(bp) < 1e-300: bp = 1e-300 d = -(a + em) * (qab + em) * x / ((a + tem) * (qap + tem)) app = ap + d * az bpp = bp + d * bz if abs(bpp) < 1e-300: bpp = 1e-300 am, bm = ap / bpp, bp / bpp az, bz = app / bpp, 1.0 if abs(app - ap) < eps * abs(app): return az return az def betainc_regularized(a, b, x): if x <= 0.0: return 0.0 if x >= 1.0: return 1.0 ln_bt = a * math.log(x) + b * math.log(1.0 - x) - _log_beta(a, b) if x < (a + 1.0) / (a + b + 2.0): cf = _betacf(a, b, x) return math.exp(ln_bt) * cf / a else: cf = _betacf(b, a, 1.0 - x) return 1.0 - math.exp((b * math.log(x) + a * math.log(1.0 - x)) - _log_beta(b, a)) * cf / b def t_cdf(t, v): if v <= 0: return float("nan") if t == 0.0: return 0.5 x = v / (v + t * t) ib = betainc_regularized(v / 2.0, 0.5, x) if t > 0: return 1.0 - 0.5 * ib else: return 0.5 * ib def t_ppf(p, v, tol=1e-10, max_iter=200): if not (0.0 < p < 1.0): return float("nan") if p == 0.5: return 0.0 lo, hi = -50.0, 50.0 for _ in range(max_iter): mid = (lo + hi) / 2.0 c = t_cdf(mid, v) if abs(c - p) < tol: return mid if c < p: lo = mid else: hi = mid return (lo + hi) / 2.0 def f_cdf(x, df1, df2): if x <= 0.0: return 0.0 z = (df1 * x) / (df1 * x + df2) return betainc_regularized(df1 / 2.0, df2 / 2.0, z) def f_ppf(p, df1, df2, tol=1e-10, max_iter=200): if not (0.0 < p < 1.0): return float("nan") lo, hi = 0.0, 1.0 while f_cdf(hi, df1, df2) < p and hi < 1e8: hi *= 2.0 for _ in range(max_iter): mid = (lo + hi) / 2.0 c = f_cdf(mid, df1, df2) if abs(c - p) < tol: return mid if c < p: lo = mid else: hi = mid return (lo + hi) / 2.0 def ols_fit(X, y): y = _col(y) n, p = X.shape XtX = X.T @ X XtX_inv = safe_inv(XtX) Xty = X.T @ y beta = XtX_inv @ Xty yhat = X @ beta e = y - yhat RSS = float((e.T @ e).ravel()[0]) ybar = float(np.mean(y)) TSS = float(((y - ybar) ** 2).sum()) df = n - p if df <= 0: raise ValueError("Недостатньо ступенів вільності (n - p має бути > 0).") s2 = RSS / df cov_beta = s2 * XtX_inv se = np.sqrt(np.diag(cov_beta)).reshape(-1, 1) with np.errstate(divide="ignore", invalid="ignore"): tvals = beta / se tvals = np.where(np.isfinite(tvals), tvals, np.nan) pvals = np.empty_like(tvals) for i in range(tvals.size): ti = float(abs(tvals[i, 0])) pvals[i, 0] = 2.0 * (1.0 - t_cdf(ti, df)) tcrit = t_ppf(0.975, df) ci_low = beta - tcrit * se ci_high = beta + tcrit * se R2 = 1.0 - RSS / TSS if TSS > 0 else float("nan") k = p - 1 denom = (1.0 - R2) / (n - p) if (n - p) > 0 else float("nan") numer = R2 / k if k > 0 else float("nan") F = numer / denom if denom not in (None, 0.0) else float("nan") F_pvalue = 1.0 - f_cdf(F, k, n - p) if math.isfinite(F) else float("nan") F_crit = f_ppf(0.95, k, n - p) if k > 0 else float("nan") return dict( beta=beta, yhat=yhat, e=e, RSS=RSS, TSS=TSS, s2=s2, se=se, tvals=tvals, pvals=pvals, ci_low=ci_low, ci_high=ci_high, XtX=XtX, XtX_inv=XtX_inv, cov_beta=cov_beta, R2=R2, F=F, F_pvalue=F_pvalue, F_crit=F_crit, df_resid=df, k=k, p=p, n=n, tcrit=tcrit ) def standardized_betas(y, x1, x2, beta): y = np.asarray(y).reshape(-1) x1 = np.asarray(x1).reshape(-1) x2 = np.asarray(x2).reshape(-1) sy = np.std(y, ddof=1) sx1 = np.std(x1, ddof=1) sx2 = np.std(x2, ddof=1) b1, b2 = float(beta[1, 0]), float(beta[2, 0]) beta1_std = b1 * (sx1 / sy) if sy > 0 else float("nan") beta2_std = b2 * (sx2 / sy) if sy > 0 else float("nan") return beta1_std, beta2_std def elasticities(y, x1, x2, beta): y = np.asarray(y).reshape(-1) x1 = np.asarray(x1).reshape(-1) x2 = np.asarray(x2).reshape(-1) my = float(np.mean(y)) mx1 = float(np.mean(x1)) mx2 = float(np.mean(x2)) b1, b2 = float(beta[1, 0]), float(beta[2, 0]) E1 = b1 * (mx1 / my) if my != 0 else float("nan") E2 = b2 * (mx2 / my) if my != 0 else float("nan") return E1, E2 def prediction_intervals(x_new, fit): x_new = np.asarray(x_new).reshape(-1, 1) beta = fit["beta"] XtX_inv = fit["XtX_inv"] s2 = float(fit["s2"]) s = math.sqrt(s2) tcrit = fit["tcrit"] df = int(fit["df_resid"]) yhat_new = float((x_new.T @ beta).ravel()[0]) leverage = float((x_new.T @ XtX_inv @ x_new).ravel()[0]) stderr_mean = float(s * math.sqrt(leverage)) CI_low = yhat_new - tcrit * stderr_mean CI_high = yhat_new + tcrit * stderr_mean stderr_pred = float(s * math.sqrt(1.0 + leverage)) PI_low = yhat_new - tcrit * stderr_pred PI_high = yhat_new + tcrit * stderr_pred return dict( yhat=yhat_new, CI95_low=CI_low, CI95_high=CI_high, PI95_low=PI_low, PI95_high=PI_high, df=df, tcrit=float(tcrit) ) def fit_and_report(y, x1, x2): src_df = pd.DataFrame({"y": y, "x1": x1, "x2": x2}) print("=== Вихідні дані (Варіант 2) ===") print(src_df.round(4).to_string(index=True)) print(f"n = {len(y)} спостережень") X = design_matrix(x1, x2, intercept=True) fit = ols_fit(X, y) print("\n--- Матриця X'X ---") print(pd.DataFrame(fit["XtX"], index=["1","x1","x2"], columns=["1","x1","x2"]).round(6).to_string()) print("\n--- (X'X)^(-1) ---") print(pd.DataFrame(fit["XtX_inv"], index=["a0","a1","a2"], columns=["a0","a1","a2"]).round(6).to_string()) a0, a1, a2 = (float(fit["beta"][0,0]), float(fit["beta"][1,0]), float(fit["beta"][2,0])) print("\n=== (1) Вибіркове рівняння множинної регресії ===") print(f"ŷ = {a0:.6f} + {a1:.6f}·x1 + {a2:.6f}·x2") print("\n=== (2) Дисперсія збурень та коваріаційна матриця ===") print(f"s_e^2 = {fit['s2']:.6f} (df = {fit['df_resid']})") print("Cov(a) = s_e^2 · (X'X)^(-1):") print(pd.DataFrame(fit["cov_beta"], index=["a0","a1","a2"], columns=["a0","a1","a2"]).round(6).to_string()) print("\n=== (3) t-тести для коефіцієнтів (α=0.05) та 95% ДІ ===") coef_tbl = pd.DataFrame({ "coef":[a0, a1, a2], "SE": fit["se"].reshape(-1), "t": fit["tvals"].reshape(-1), "p": fit["pvals"].reshape(-1), "CI95_low": fit["ci_low"].reshape(-1), "CI95_high": fit["ci_high"].reshape(-1), }, index=["a0","a1","a2"]) print(coef_tbl.round(6).to_string()) R2 = float(fit["R2"]) R = float(math.sqrt(R2)) if R2 >= 0 else float("nan") print("\n=== (4) Дисперсія та значущість моделі ===") print(f"R^2 = {R2:.6f}, R = {R:.6f}") print(f"F = {fit['F']:.6f} (df1 = {fit['k']}, df2 = {fit['df_resid']}), p-value = {fit['F_pvalue']:.6g}") print(f"F_crit (α=0.05) = {fit['F_crit']:.6f}") b1_std, b2_std = standardized_betas(y, x1, x2, fit["beta"]) E1, E2 = elasticities(y, x1, x2, fit["beta"]) comp_df = pd.DataFrame({"std_beta":[b1_std, b2_std], "elasticity":[E1, E2]}, index=["x1 (тис. м²)", "x2 (тис. люд/день)"]) print("\n=== (5) Порівняння роздільного впливу факторів ===") print(comp_df.round(6).to_string()) stronger_std = "x1" if abs(b1_std) > abs(b2_std) else "x2" stronger_el = "x1" if abs(E1) > abs(E2) else "x2" print(f"→ За |std_beta| сильніший вплив: {stronger_std}; за |elasticity|: {stronger_el}.") x_new = np.array([1.0, 1.2, 15.0]) pred = prediction_intervals(x_new, fit) print("\n=== (6) Прогноз у точці x1=1.2, x2=15 з 95% інтервалами ===") print(f"ŷ_new = {pred['yhat']:.6f}") print(f"95% CI (середній відгук): [{pred['CI95_low']:.6f}; {pred['CI95_high']:.6f}]") print(f"95% PI (нове спостереження): [{pred['PI95_low']:.6f}; {pred['PI95_high']:.6f}]") print(f"(t_crit = {pred['tcrit']:.4f}, df = {pred['df']})") print("\n=== ПІДСУМОК ===") print(f"Модель: ŷ = {a0:.4f} + {a1:.4f}·x1 + {a2:.4f}·x2") print(f"R^2 = {R2:.4f}, F({fit['k']},{fit['df_resid']}) = {fit['F']:.4f} (F_crit={fit['F_crit']:.4f})") print(f"Прогноз у (1.2; 15): ŷ = {pred['yhat']:.4f}, 95% PI = [{pred['PI95_low']:.4f}; {pred['PI95_high']:.4f}]") print("x1 — тис. м², x2 — тис. людей/день; y — млн грн.") if __name__ == "__main__": fit_and_report(y, x1, x2)