mirosh111000

Мірошниченко_ГЙМ_ПР№5-6

Dec 4th, 2025
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.98 KB | None | 0 0
  1. from __future__ import annotations
  2. import math
  3. from dataclasses import dataclass
  4. import numpy as np
  5. import pandas as pd
  6. import matplotlib.pyplot as plt
  7.  
  8.  
  9. def generate_data_var2(n: int = 100, seed: int = 42) -> pd.DataFrame:
  10.  
  11.     rng = np.random.default_rng(seed)
  12.  
  13.     x = rng.uniform(3500, 11000, size=n)
  14.     eps = rng.normal(0.0, 1.0, size=n)
  15.     y = -1000.0 + 0.5 * x + 300.0 * eps
  16.  
  17.     df = pd.DataFrame({"x": x, "y": y})
  18.     return df
  19.  
  20.  
  21. @dataclass
  22. class CorrelationResult:
  23.     r_xy: float
  24.     r_np: float
  25.     sums: dict
  26.  
  27.  
  28. def compute_correlation_and_sums(df: pd.DataFrame) -> CorrelationResult:
  29.  
  30.     x = df["x"].to_numpy()
  31.     y = df["y"].to_numpy()
  32.     n = len(df)
  33.  
  34.     Sx = x.sum()
  35.     Sy = y.sum()
  36.     Sx2 = (x ** 2).sum()
  37.     Sy2 = (y ** 2).sum()
  38.     Sxy = (x * y).sum()
  39.  
  40.     numerator = n * Sxy - Sx * Sy
  41.     denominator = math.sqrt((n * Sx2 - Sx ** 2) * (n * Sy2 - Sy ** 2))
  42.     r_xy = numerator / denominator
  43.  
  44.     r_np = float(np.corrcoef(x, y)[0, 1])
  45.  
  46.     Sx3 = (x ** 3).sum()
  47.     Sx4 = (x ** 4).sum()
  48.     Sx5 = (x ** 5).sum()
  49.     Sx6 = (x ** 6).sum()
  50.     Sx2y = ((x ** 2) * y).sum()
  51.     Sx3y = ((x ** 3) * y).sum()
  52.  
  53.     sums = {
  54.         "n": float(n),
  55.         "Sx": float(Sx),
  56.         "Sx2": float(Sx2),
  57.         "Sx3": float(Sx3),
  58.         "Sx4": float(Sx4),
  59.         "Sx5": float(Sx5),
  60.         "Sx6": float(Sx6),
  61.         "Sy": float(Sy),
  62.         "Sxy": float(Sxy),
  63.         "Sx2y": float(Sx2y),
  64.         "Sx3y": float(Sx3y),
  65.     }
  66.  
  67.     return CorrelationResult(r_xy=r_xy, r_np=r_np, sums=sums)
  68.  
  69.  
  70. def interpret_correlation(r: float) -> str:
  71.  
  72.     r_abs = abs(r)
  73.     if r_abs < 0.3:
  74.         return "майжу відстутній"
  75.     elif r_abs < 0.5:
  76.         return "слабкий"
  77.     elif r_abs < 0.7:
  78.         return "помірний"
  79.     elif r_abs < 1.0:
  80.         return "сильний"
  81.     else:
  82.         return "функціональний"
  83.  
  84.  
  85.  
  86.  
  87. @dataclass
  88. class RegressionModel:
  89.     degree: int
  90.     coeffs: np.ndarray
  91.     coeffs_check: np.ndarray
  92.     rss: float
  93.     sigma2: float
  94.  
  95.     def predict(self, x: np.ndarray) -> np.ndarray:
  96.         powers = np.arange(self.degree + 1)
  97.         return sum(self.coeffs[j] * (x ** powers[j]) for j in range(self.degree + 1))
  98.  
  99.  
  100. def solve_regression_models(df: pd.DataFrame, sums: dict) -> list[RegressionModel]:
  101.  
  102.     x = df["x"].to_numpy()
  103.     y = df["y"].to_numpy()
  104.     n = int(sums["n"])
  105.  
  106.     Sx = sums["Sx"]
  107.     Sx2 = sums["Sx2"]
  108.     Sx3 = sums["Sx3"]
  109.     Sx4 = sums["Sx4"]
  110.     Sx5 = sums["Sx5"]
  111.     Sx6 = sums["Sx6"]
  112.     Sy = sums["Sy"]
  113.     Sxy = sums["Sxy"]
  114.     Sx2y = sums["Sx2y"]
  115.     Sx3y = sums["Sx3y"]
  116.  
  117.     models: list[RegressionModel] = []
  118.  
  119.     A1 = np.array([[n, Sx], [Sx, Sx2]], dtype=float)
  120.     b1 = np.array([Sy, Sxy], dtype=float)
  121.     coeffs1 = np.linalg.solve(A1, b1)
  122.  
  123.     X1 = np.vstack([np.ones_like(x), x]).T
  124.     coeffs1_check, *_ = np.linalg.lstsq(X1, y, rcond=None)
  125.     resid1 = y - (coeffs1[0] + coeffs1[1] * x)
  126.     rss1 = float(np.sum(resid1 ** 2))
  127.     sigma2_1 = rss1 / (n - 2)
  128.  
  129.     models.append(RegressionModel(1, coeffs1, coeffs1_check, rss1, sigma2_1))
  130.  
  131.     A2 = np.array(
  132.         [
  133.             [n, Sx, Sx2],
  134.             [Sx, Sx2, Sx3],
  135.             [Sx2, Sx3, Sx4],
  136.         ],
  137.         dtype=float,
  138.     )
  139.     b2 = np.array([Sy, Sxy, Sx2y], dtype=float)
  140.     coeffs2 = np.linalg.solve(A2, b2)
  141.  
  142.     X2 = np.vstack([np.ones_like(x), x, x ** 2]).T
  143.     coeffs2_check, *_ = np.linalg.lstsq(X2, y, rcond=None)
  144.     y_hat2 = coeffs2[0] + coeffs2[1] * x + coeffs2[2] * x ** 2
  145.     resid2 = y - y_hat2
  146.     rss2 = float(np.sum(resid2 ** 2))
  147.     sigma2_2 = rss2 / (n - 3)
  148.  
  149.     models.append(RegressionModel(2, coeffs2, coeffs2_check, rss2, sigma2_2))
  150.  
  151.     A3 = np.array(
  152.         [
  153.             [n, Sx, Sx2, Sx3],
  154.             [Sx, Sx2, Sx3, Sx4],
  155.             [Sx2, Sx3, Sx4, Sx5],
  156.             [Sx3, Sx4, Sx5, Sx6],
  157.         ],
  158.         dtype=float,
  159.     )
  160.     b3 = np.array([Sy, Sxy, Sx2y, Sx3y], dtype=float)
  161.     coeffs3 = np.linalg.solve(A3, b3)
  162.  
  163.     X3 = np.vstack([np.ones_like(x), x, x ** 2, x ** 3]).T
  164.     coeffs3_check, *_ = np.linalg.lstsq(X3, y, rcond=None)
  165.     y_hat3 = coeffs3[0] + coeffs3[1] * x + coeffs3[2] * x ** 2 + coeffs3[3] * x ** 3
  166.     resid3 = y - y_hat3
  167.     rss3 = float(np.sum(resid3 ** 2))
  168.     sigma2_3 = rss3 / (n - 4)
  169.  
  170.     models.append(RegressionModel(3, coeffs3, coeffs3_check, rss3, sigma2_3))
  171.  
  172.     return models
  173.  
  174.  
  175.  
  176.  
  177. @dataclass
  178. class EmpiricalRegression:
  179.     intervals: pd.DataFrame
  180.     x_mid: np.ndarray
  181.     y_mean: np.ndarray
  182.  
  183.  
  184. def build_empirical_regression(df: pd.DataFrame) -> EmpiricalRegression:
  185.  
  186.     x = df["x"].to_numpy()
  187.     y = df["y"].to_numpy()
  188.     n = len(df)
  189.  
  190.     m = int(round(1 + 3.322 * math.log10(n)))
  191.     m = max(m, 4)
  192.  
  193.     x_min, x_max = float(x.min()), float(x.max())
  194.     h = (x_max - x_min) / m
  195.  
  196.     bounds = [x_min + i * h for i in range(m + 1)]
  197.  
  198.     rows = []
  199.     x_mid_list = []
  200.     y_mean_list = []
  201.  
  202.     for i in range(m):
  203.         a_i = bounds[i]
  204.         b_i = bounds[i + 1] if i < m - 1 else bounds[i + 1] + 1e-6
  205.  
  206.         mask = (x >= a_i) & (x < b_i)
  207.         x_bin = x[mask]
  208.         y_bin = y[mask]
  209.  
  210.         if len(x_bin) == 0:
  211.             continue
  212.  
  213.         mid = 0.5 * (a_i + b_i)
  214.         y_mean = float(y_bin.mean())
  215.  
  216.         rows.append(
  217.             {
  218.                 "Інтервал X": f"[{a_i:8.2f}; {b_i:8.2f})",
  219.                 "Середина X": mid,
  220.                 "N": int(len(x_bin)),
  221.                 "Середнє Y (умовне)": y_mean,
  222.             }
  223.         )
  224.         x_mid_list.append(mid)
  225.         y_mean_list.append(y_mean)
  226.  
  227.     table = pd.DataFrame(rows)
  228.     return EmpiricalRegression(table, np.array(x_mid_list), np.array(y_mean_list))
  229.  
  230.  
  231.  
  232.  
  233. def print_header(title: str) -> None:
  234.     print("\n" + "=" * 3 + f" {title} " + "=" * 3)
  235.  
  236.  
  237. def main():
  238.     print_header("Практична робота №5, 6")
  239.     print("Побудова кореляційного поля і рівняння регресії")
  240.     print("Варіант 2: Дохід (x), Заощадження (y)\n")
  241.  
  242.     df = generate_data_var2(n=100, seed=42)
  243.  
  244.     print("Перші 10 спостережень (округлені значення):")
  245.     print(df.round(0).head(10))
  246.  
  247.     print_header("Коефіцієнт лінійної кореляції")
  248.     corr_res = compute_correlation_and_sums(df)
  249.     print(f"r_xy (за формулою сум) = {corr_res.r_xy: .6f}")
  250.     print(f"r_xy (np.corrcoef)      = {corr_res.r_np: .6f}")
  251.     print(f"Тіснота зв'язку          = {interpret_correlation(corr_res.r_xy)}")
  252.  
  253.     print("\nПроміжні суми (для нормальних рівнянь):")
  254.     for key in ["n", "Sx", "Sx2", "Sx3", "Sx4", "Sx5", "Sx6", "Sy", "Sxy", "Sx2y", "Sx3y"]:
  255.         print(f"  {key:>4} = {corr_res.sums[key]:.4f}")
  256.  
  257.     print_header("Коефіцієнти рівнянь регресії (матричний метод)")
  258.     models = solve_regression_models(df, corr_res.sums)
  259.  
  260.     for model in models:
  261.         a = model.coeffs
  262.         degree = model.degree
  263.  
  264.         if degree == 1:
  265.             print("Лінійна регресія (1-й порядок):")
  266.             print(f"  y = {a[0]: .6f} + {a[1]: .6f} * x")
  267.         elif degree == 2:
  268.             print("Квадратична регресія (2-й порядок):")
  269.             print(f"  y = {a[0]: .6f} + {a[1]: .6f} * x + {a[2]: .10f} * x^2")
  270.         elif degree == 3:
  271.             print("Кубічна регресія (3-й порядок):")
  272.             print(
  273.                 "  y = "
  274.                 f"{a[0]: .6f} + {a[1]: .6f} * x + {a[2]: .10f} * x^2 + {a[3]: .10e} * x^3"
  275.             )
  276.         print()
  277.  
  278.     print_header("Перевірка коефіцієнтів")
  279.     for model in models:
  280.         print(f"Модель ступеня {model.degree}:")
  281.         print(f"  Матричний метод:  {model.coeffs}")
  282.         print(f"  lstsq:            {model.coeffs_check}")
  283.         print()
  284.  
  285.     print_header("Залишкова дисперсія для моделей")
  286.     print(f"{'Порядок':>8}  {'RSS':>15}  {'σ^2_зал':>15}")
  287.     for model in models:
  288.         print(
  289.             f"{model.degree:8d}  "
  290.             f"{model.rss:15.4f}  "
  291.             f"{model.sigma2:15.4f}"
  292.         )
  293.  
  294.     best_model = min(models, key=lambda m: m.sigma2)
  295.     if best_model.degree == 1:
  296.         name_best = "лінійна"
  297.     elif best_model.degree == 2:
  298.         name_best = "квадратична"
  299.     else:
  300.         name_best = "кубічна"
  301.     print(f"\nНайкраща модель за критерієм мінімальної σ^2_зал: {name_best} (ступінь {best_model.degree}).")
  302.  
  303.     print_header("Емпірична регресія (умовне середнє)")
  304.     emp = build_empirical_regression(df)
  305.     print(emp.intervals.to_string(index=False, justify="center", col_space=12))
  306.  
  307.     x = df["x"].to_numpy()
  308.     y = df["y"].to_numpy()
  309.  
  310.     x_grid = np.linspace(x.min(), x.max(), 300)
  311.  
  312.     y1_grid = models[0].predict(x_grid)
  313.     y2_grid = models[1].predict(x_grid)
  314.     y3_grid = models[2].predict(x_grid)
  315.  
  316.     plt.figure(figsize=(10, 6))
  317.  
  318.     plt.scatter(x, y, s=20, alpha=0.7, label="Спостереження (x, y)")
  319.  
  320.     plt.plot(x_grid, y1_grid, label="Лінійна регресія")
  321.     plt.plot(x_grid, y2_grid, linestyle="--", label="Квадратична регресія")
  322.     plt.plot(x_grid, y3_grid, linestyle=":", label="Кубічна регресія")
  323.  
  324.     plt.plot(
  325.         emp.x_mid,
  326.         emp.y_mean,
  327.         "o-",
  328.         linewidth=2,
  329.         markersize=5,
  330.         label="Емпірична регресія (умовне середнє)",
  331.     )
  332.  
  333.     plt.xlabel("x – Дохід, грн")
  334.     plt.ylabel("y – Заощадження, грн")
  335.     plt.title("Кореляційне поле з лініями регресії (варіант 2)")
  336.     plt.grid(True)
  337.     plt.legend()
  338.     plt.tight_layout()
  339.     plt.show()
  340.  
  341.  
  342. if __name__ == "__main__":
  343.     main()
  344.  
Advertisement
Add Comment
Please, Sign In to add comment