# -*- coding: utf-8 -*-
"""P9-B-Loess Regression.ipynb

Automatically generated by Colab.

Original file is located at
    https://colab.research.google.com/drive/1acJ-zD2I0flDn0hYujYD4B6NI2hEALAS
"""

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
def kernel(point, xmat, k):
    m,n = np.shape(xmat)
    weights = np.asmatrix(np.eye((m)))
    for j in range(m):
        diff = point - xmat[j]
        weights[j,j] = np.exp(diff*diff.T/(-2.0*k**2))
    return weights

def localWeight(point, xmat, ymat, k):
    wei = kernel(point,xmat,k)
    W = (xmat.T*(wei*xmat)).I*(xmat.T*(wei*ymat.T))
    return W

def localWeightRegression(xmat, ymat, k):
    m,n = np.shape(xmat) #Determine the dimensions of xmat(X)
    ypred = np.zeros(m) #Set ypred
    for i in range(m):
        ypred[i] = xmat[i]*localWeight(xmat[i],xmat,ymat,k)
    return ypred

# load data points
data = pd.read_csv('/content/10-dataset.csv')
bill = np.array(data.total_bill)
tip = np.array(data.tip)

#`np.mat` was removed in the NumPy 2.0 release. Use `np.asmatrix` instead.

#preparing and add 1 in bill
mbill = np.asmatrix(bill)
mtip = np.asmatrix(tip)

m= np.shape(mbill)[1]
one = np.asmatrix(np.ones(m))
X = np.hstack((one.T,mbill.T))

#set k here
ypred = localWeightRegression(X,mtip,0.4)
SortIndex = X[:,1].argsort(0)
xsort = X[SortIndex][:,0]

fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(bill,tip, color='green')
ax.plot(xsort[:,1],ypred[SortIndex], color = 'red', linewidth=5)
plt.xlabel('Total bill')
plt.ylabel('Tip')
plt.show();

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Load dataset
data = pd.read_csv('/content/10-dataset.csv')
bill = data['total_bill'].values
tip = data['tip'].values

# Prepare X matrix with intercept term
X = np.column_stack((np.ones(len(bill)), bill))
y = tip.reshape(-1, 1)

# Gaussian Kernel function to calculate weights
def kernel(point, X, k):
    m = X.shape[0]
    W = np.eye(m)
    for i in range(m):
        diff = point - X[i]
        W[i,i] = np.exp(-(diff @ diff.T) / (2 * k**2))
    return W

# Calculate weights and regression coefficients for a point
def lwlr_point(point, X, y, k):
    W = kernel(point, X, k)
    theta = np.linalg.inv(X.T @ W @ X) @ (X.T @ W @ y)
    return point @ theta

# Predict for all points
def lwlr(X, y, k):
    y_pred = np.zeros(len(X))
    for i in range(len(X)):
        y_pred[i] = lwlr_point(X[i], X, y, k)
    return y_pred

# Apply LWLR with bandwidth k=0.4
k = 0.4
y_pred = lwlr(X, y, k)

# Sort X for plotting smooth curve
sort_idx = X[:,1].argsort()
X_sorted = X[sort_idx]
y_pred_sorted = y_pred[sort_idx]

# Plot results
plt.scatter(bill, tip, color='green', label='Data points')
plt.plot(X_sorted[:,1], y_pred_sorted, color='red', linewidth=2, label='LWLR fit')
plt.xlabel('Total bill')
plt.ylabel('Tip')
plt.title('Locally Weighted Linear Regression')
plt.legend()
plt.show()

