import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from scipy import stats

# === ЗАГРУЗКА ДАННЫХ ===
columns = ['Position', 'Height(inches)', 'Weight(pounds)', 'Age']
df = pd.read_csv('SOCR_Data_MLB_HeightsWeights.txt', sep='\t', nrows=115, usecols=columns)

# === ПАРНАЯ РЕГРЕССИЯ ===
# Выходная переменная — вес, входная — рост
X_single = df['Height(inches)'].values.reshape(-1, 1)
y = df['Weight(pounds)'].values

lr = LinearRegression().fit(X_single, y)
y_pred_single = lr.predict(X_single)
res_single = y - y_pred_single

# Визуализация
fig1, axes = plt.subplots(1, 3, figsize=(15, 5))
fig1.suptitle('Парная регрессия')

# 1. Линия регрессии
axes[0].scatter(df['Height(inches)'], df['Weight(pounds)'], color='blue', alpha=0.6)
axes[0].plot(df['Height(inches)'], y_pred_single, color='red', linewidth=2)
axes[0].set_xlabel('Height (inches)')
axes[0].set_ylabel('Weight (pounds)')
axes[0].set_title('Линейная зависимость')

# 2. Остатки
axes[1].scatter(y_pred_single, res_single, color='green', alpha=0.6)
axes[1].axhline(y=0, color='red', linestyle='--')
axes[1].set_xlabel('Предсказанные значения')
axes[1].set_ylabel('Остатки')
axes[1].set_title('Анализ остатков')

# 3. Гистограмма остатков
axes[2].hist(res_single, bins=15, color='gray', edgecolor='black')
axes[2].set_xlabel('Остатки')
axes[2].set_ylabel('Количество точек')
axes[2].set_title('Распределение остатков')

# Метрики
Qreg = np.sum((y_pred_single - y.mean()) ** 2)
Qres = np.sum((y - y_pred_single) ** 2)
Qtotal = np.sum((y - y.mean()) ** 2)

R2 = r2_score(y, y_pred_single)
AdjR2 = 1 - (1 - R2) * (115 - 1) / (115 - 1 - 1)
R = np.sqrt(R2)
StdErr = np.sqrt(Qres / (115 - 2))

print('\n=== Парная регрессия ===')
print('Коэффициент детерминации R²:', round(R2, 4))
print('Скорректированный R²:', round(AdjR2, 4))
print('Множественный коэффициент корреляции R:', round(R, 4))
print('Стандартная ошибка регрессии:', round(StdErr, 4))
print('Коэффициенты модели (b0 + b1*x):', lr.intercept_, lr.coef_)

# === МНОЖЕСТВЕННАЯ РЕГРЕССИЯ ===
# Кодируем категориальный признак Position в числовой формат
position_mapping = {pos: i for i, pos in enumerate(df['Position'].unique())}
df['Position_num'] = df['Position'].map(position_mapping)

# Входные переменные — позиция, рост и возраст
X_multi = df[['Position_num', 'Height(inches)', 'Age']].values

mr = LinearRegression().fit(X_multi, y)
y_pred_multi = mr.predict(X_multi)
res_multi = y - y_pred_multi

# Визуализация
fig2, axes = plt.subplots(1, 2, figsize=(12, 5))
fig2.suptitle('Множественная регрессия')

# Остатки
axes[0].scatter(y_pred_multi, res_multi, color='purple', alpha=0.6)
axes[0].axhline(y=0, color='red', linestyle='--')
axes[0].set_xlabel('Предсказанные значения')
axes[0].set_ylabel('Остатки')
axes[0].set_title('Анализ остатков')

# Гистограмма остатков
axes[1].hist(res_multi, bins=15, color='orange', edgecolor='black')
axes[1].set_xlabel('Остатки')
axes[1].set_ylabel('Количество точек')
axes[1].set_title('Распределение остатков')

# Метрики
Qreg_m = np.sum((y_pred_multi - y.mean()) ** 2)
Qres_m = np.sum((y - y_pred_multi) ** 2)

R2_m = r2_score(y, y_pred_multi)
AdjR2_m = 1 - (1 - R2_m) * (115 - 1) / (115 - 3 - 1)
R_m = np.sqrt(R2_m)
StdErr_m = np.sqrt(Qres_m / (115 - 3 - 1))

print('\n=== Множественная регрессия ===')
print('Коэффициент детерминации R²:', round(R2_m, 4))
print('Скорректированный R²:', round(AdjR2_m, 4))
print('Множественный коэффициент корреляции R:', round(R_m, 4))
print('Стандартная ошибка регрессии:', round(StdErr_m, 4))
print('Коэффициенты модели:', mr.intercept_, mr.coef_)

plt.tight_layout()
plt.show()

# === КРАТКИЕ ВЫВОДЫ ===
print('\n=== ВЫВОДЫ ===')
print('1. Парная регрессия показывает умеренную связь между ростом и весом (R ≈', round(R, 2), ').')
print('2. Множественная регрессия с учётом возраста и позиции улучшает качество модели (R² выше).')
print('3. Остатки распределены примерно нормально, значимых выбросов немного.')
print('4. Наиболее информативные переменные: рост и возраст.')



