Week 02 : Fitting¶
In [92]:
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import seaborn as snb
In [93]:
# Import file from kaggel database online
import kagglehub
from kagglehub import KaggleDatasetAdapter
# Set the path to the file you'd like to load
file_path = "StudentsPerformance.csv"
# Load the latest version
df = kagglehub.load_dataset(
KaggleDatasetAdapter.PANDAS,
"sadiajavedd/students-academic-performance-dataset",
file_path,
)
/tmp/ipykernel_24512/615150558.py:9: DeprecationWarning: Use dataset_load() instead of load_dataset(). load_dataset() will be removed in a future version. df = kagglehub.load_dataset(
In [94]:
df.head(2)
Out[94]:
| gender | race/ethnicity | parental level of education | lunch | test preparation course | math score | reading score | writing score | |
|---|---|---|---|---|---|---|---|---|
| 0 | female | group B | bachelor's degree | standard | none | 72 | 72 | 74 |
| 1 | female | group C | some college | standard | completed | 69 | 90 | 88 |
In [95]:
df.shape
Out[95]:
(1000, 8)
In [96]:
df.columns
Out[96]:
Index(['gender', 'race/ethnicity', 'parental level of education', 'lunch',
'test preparation course', 'math score', 'reading score',
'writing score'],
dtype='object')
In [97]:
# Polynomial Fit (polyfit)
x = df['reading score'].sort_values(ascending=True)
y = df['writing score'].sort_values()
c1 = np.polyfit(x,y,1) # fit first-order polynomial
c2 = np.polyfit(x,y,2) # fit second-order polynomial
# evaluate first-order fit
xfit = np.linspace(min(x),max(x),1000)
p1 = np.poly1d(c1)
y1 = p1(xfit)
# evaluate second-order fit
p2 = np.poly1d(c2)
y2 = p2(xfit)
plt.figure()
plt.plot(x,y,'o')
plt.plot(xfit,y1,'g-',label='linear')
plt.plot(xfit,y2,'r-',label='quadratic')
plt.legend()
plt.show()
In [98]:
df.head(2)
Out[98]:
| gender | race/ethnicity | parental level of education | lunch | test preparation course | math score | reading score | writing score | |
|---|---|---|---|---|---|---|---|---|
| 0 | female | group B | bachelor's degree | standard | none | 72 | 72 | 74 |
| 1 | female | group C | some college | standard | completed | 69 | 90 | 88 |
In [99]:
df_new.head()
Out[99]:
| gender | race/ethnicity | parental level of education | lunch | test preparation course | math score | reading score | writing score | |
|---|---|---|---|---|---|---|---|---|
| 59 | female | group C | some high school | free/reduced | none | 0 | 17 | 10 |
| 327 | male | group A | some college | free/reduced | none | 28 | 23 | 19 |
| 596 | male | group B | high school | free/reduced | none | 30 | 24 | 15 |
| 980 | female | group B | high school | free/reduced | none | 8 | 24 | 23 |
| 76 | male | group E | some high school | standard | none | 30 | 26 | 22 |
In [100]:
# 1. Sort the DataFrame by the reading score
df_new = df.sort_values(by='reading score', ascending=True)
npts = 200 # Example number of points you want to generate
c = [0.01, 0.01, 20] # Example coefficients for the quadratic
noise = 10 # Example noise level
# 3. FIX: Use the actual column data to find min/max, not the string 'df_new'
min_x = min(df_new['reading score'])
max_x = max(df_new['reading score'])
x = min_x + (max_x - min_x) * np.random.rand(npts)
y = c[2] + c[1] * x + c[0] * x * x + np.random.normal(0, noise, npts)
# The rest of your script follows here:
# Polynomial Fit (polyfit)
c1 = np.polyfit(x, y, 1) # fit first-order polynomial
c2 = np.polyfit(x, y, 2) # fit second-order polynomial
# evaluate fits
xfit = np.linspace(min(x), max(x), 100)
p1 = np.poly1d(c1)
y1 = p1(xfit)
p2 = np.poly1d(c2)
y2 = p2(xfit)
plt.figure()
plt.plot(x, y, 'o')
plt.plot(xfit, y1, 'g-', label='linear')
plt.plot(xfit, y2, 'r-', label='quadratic')
plt.xlabel(" X Values (based on Reading Score range)") # Set X-axis label
plt.ylabel("Y Values (Quadratic Model)")
plt.legend()
plt.title("Polynomial Fit")
plt.savefig("fig1.png", dpi=300, bbox_inches='tight', transparent=True)
plt.show()
In [101]:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import kagglehub # Ensure this library is installed: pip install kagglehub
from kagglehub import KaggleDatasetAdapter
# --- Data Loading (from your previous prompt) ---
try:
dataset_handle = "sadiajavedd/students-academic-performance-dataset"
file_path = "StudentsPerformance.csv"
df = kagglehub.load_dataset(KaggleDatasetAdapter.PANDAS, dataset_handle, file_path)
except Exception as e:
print(f"Could not load data from KaggleHub: {e}")
# Fallback: if you have the file locally, use this:
# df = pd.read_csv("StudentsPerformance.csv")
# If the above fails, you can't run the script.
# --- Data Preparation ---
# We will use 'reading score' as the input (x) and 'writing score' as the output (y)
# It is important that x and y are aligned. Sort the DataFrame first for consistent plotting.
df_sorted = df.sort_values(by='reading score', ascending=True)
# Convert pandas Series to numpy arrays for the RBF calculations
x = df_sorted['reading score'].values
y = df_sorted['writing score'].values
npts = len(x) # Total number of data points (should be 1000)
ncenters = 20 # Number of RBF centers you want to use
xtest = np.linspace(min(x), max(x), 1000) # Points for the smooth fitted line
# --- RBF Calculation (Corrected and Aligned) ---
indices = np.random.uniform(low=0, high=npts, size=ncenters).astype(int)
centers = x[indices]
# Construct matrix M (uses len(x) for alignment)
M = np.abs(np.outer(x, np.ones(ncenters)) - np.outer(np.ones(npts), centers))**3
# Perform the Least Squares Fit
coeff, residuals, rank, values = np.linalg.lstsq(M, y, rcond=None)
# Evaluate the fit at the test points (uses len(xtest) for alignment)
yfit = (np.abs(np.outer(xtest, np.ones(ncenters)) - np.outer(np.ones(len(xtest)), centers))**3) @ coeff
# --- Plotting ---
plt.figure(figsize=(10, 6))
# Plot actual data points
plt.plot(x, y, 'o', label='Student Data (Reading vs Writing)')
# Plot the RBF fit line
plt.plot(xtest, yfit, 'g-', label='RBF fit interpolation', linewidth=2)
plt.xlabel("Reading Score") # Set appropriate label
plt.ylabel("Writing Score") # Set appropriate label
plt.title("Radial Basis Function (RBF) Fit on Student Scores")
plt.legend()
plt.savefig("fig1.png", dpi=300, bbox_inches='tight', transparent=True)
plt.show()
/tmp/ipykernel_24512/856572227.py:11: DeprecationWarning: Use dataset_load() instead of load_dataset(). load_dataset() will be removed in a future version. df = kagglehub.load_dataset(KaggleDatasetAdapter.PANDAS, dataset_handle, file_path)
In [102]:
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 1000 entries, 0 to 999 Data columns (total 8 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 gender 1000 non-null object 1 race/ethnicity 1000 non-null object 2 parental level of education 1000 non-null object 3 lunch 1000 non-null object 4 test preparation course 1000 non-null object 5 math score 1000 non-null int64 6 reading score 1000 non-null int64 7 writing score 1000 non-null int64 dtypes: int64(3), object(5) memory usage: 62.6+ KB
In [3]:
import numpy as np
%matplotlib ipympl
np.set_printoptions(precision=3)
z = df['math score'].values
M = np.c_[np.ones(1000),x,y,x*y,x*x,y*y] # construct Vandermonde matrix
cfit,residuals,rank,values = np.linalg.lstsq(M,z) # do least-squares fit
fig = plt.figure()
fig.canvas.header_visible = False
ax = fig.add_subplot(projection='3d') # add 3D axes
ax.scatter(x,y,z)
xfit = np.linspace(min(x),max(x),1000)
yfit = np.linspace(min(y),max(y),1000)
Xfit,Yfit = np.meshgrid(xfit,yfit)
Zfit = cfit[0]+cfit[1]*Xfit+cfit[2]*Yfit+cfit[3]*Xfit*Yfit+cfit[4]*Xfit*Xfit+cfit[5]*Yfit*Yfit # evaluate fit surface
ax.plot_surface(Xfit,Yfit,Zfit,cmap='gray',alpha=0.5) # plot fit surface
plt.show()
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[3], line 4 2 get_ipython().run_line_magic('matplotlib', 'ipympl') 3 np.set_printoptions(precision=3) ----> 4 z = df['math score'].values 5 M = np.c_[np.ones(1000),x,y,x*y,x*x,y*y] # construct Vandermonde matrix 6 cfit,residuals,rank,values = np.linalg.lstsq(M,z) # do least-squares fit NameError: name 'df' is not defined
In [104]:
# nonlinear least squares
xplot = np.linspace(min(x)-0.01,max(x)+0.01,100)
coeff1 = np.polyfit(x,y,3) # fit and evaluate order 3 polynomial
pfit1 = np.poly1d(coeff1)
yfit1 = pfit1(xplot)
coeff2 = np.polyfit(x,y,5) # fit and evaluate order 5 polynomial
pfit2 = np.poly1d(coeff2)
yfit2 = pfit2(xplot)
coeff15 = np.polyfit(x,y,15) # fit and evaluate order 15 polynomial
pfit15 = np.poly1d(coeff15)
yfit15 = pfit15(xplot)
fig = plt.figure()
fig.canvas.header_visible = False
plt.plot(x,y,'go',label='data')
plt.plot(xplot,yfit1,'b-',label='order 3')
plt.plot(xplot,yfit2,'c-',label='order 2')
plt.plot(xplot,yfit15,'r-',label='order 15')
plt.title('Nonlinear least squares')
plt.legend()
plt.savefig("fig4.png", dpi=300, bbox_inches='tight', transparent=True)
plt.show()
/tmp/ipykernel_24512/3147249277.py:9: RankWarning: Polyfit may be poorly conditioned coeff15 = np.polyfit(x,y,15) # fit and evaluate order 15 polynomial
In [ ]:
In [ ]:
In [82]:
# Overfitting and cross-validation
npts = 1000
c = [-3,2,1]
xtest = min(x)+(max(x)-min(x))*np.random.rand(npts)
ytest = c[2]+c[1]*xtest+c[0]*xtest*xtest
#
# loop over number of centers, fit, and save
#
errors = []
coeffs = []
centers = []
ncenters = np.arange(1,101,1)
for ncenter in ncenters:
indices = np.random.uniform(low=0,high=len(x),size=ncenter).astype(int)
center = x[indices]
M = np.abs(np.outer(x,np.ones(ncenter))
-np.outer(np.ones(npts),center))**3
coeff,residuals,rank,values = np.linalg.lstsq(M,y)
yfit = (np.abs(np.outer(xtest,np.ones(ncenter))-np.outer(np.ones(npts),center))**3)@coeff
errors.append(np.mean(np.abs(yfit-ytest)))
coeffs.append(coeff)
centers.append(center)
#
# plot data, fits, and errors
#
fig,axs = plt.subplots(2,1)
fig.canvas.header_visible = False
axs[0].plot(x,y,'o',alpha=0.5)
xplot = np.linspace(min(x),max(x),npts)
n = 1
yplot = (np.abs(np.outer(xplot,np.ones(n))-
np.outer(np.ones(npts),centers[n-1]))**3)@coeffs[n-1]
axs[0].plot(xplot,yplot,'g-',label='1 anchor')
n = 10
yplot = (np.abs(np.outer(xplot,np.ones(n))-
np.outer(np.ones(npts),centers[n-1]))**3)@coeffs[n-1]
axs[0].plot(xplot,yplot,'k-',label='10 anchors')
n = 100
yplot = (np.abs(np.outer(xplot,np.ones(n))-
np.outer(np.ones(npts),centers[n-1]))**3)@coeffs[n-1]
axs[0].plot(xplot,yplot,'r-',label='100 anchors')
axs[0].legend()
axs[1].plot(ncenters,errors)
axs[1].set_ylabel('error')
axs[1].set_xlabel('number of centers')
plt.show()
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[82], line 16 14 indices = np.random.uniform(low=0,high=len(x),size=ncenter).astype(int) 15 center = x[indices] ---> 16 M = np.abs(np.outer(x,np.ones(ncenter)) 17 -np.outer(np.ones(npts),center))**3 18 coeff,residuals,rank,values = np.linalg.lstsq(M,y) 19 yfit = (np.abs(np.outer(xtest,np.ones(ncenter))-np.outer(np.ones(npts),center))**3)@coeff ValueError: operands could not be broadcast together with shapes (200,1) (1000,1)
In [89]:
# Regularization
npts =1000
ncenters = 100
indices = np.random.uniform(low=0,high=len(x),size=ncenters).astype(int)
centers = x[indices]
M = np.abs(np.outer(x,np.ones(ncenters))
-np.outer(np.ones(npts),centers))**3
# invert matrices to find weight-regularized coefficients
Lambda = 1
left = (M.T)@M+Lambda*np.eye(ncenters)
right = (M.T)@y
coeff1 = np.linalg.pinv(left)@right
Lambda = 0
left = (M.T)@M+Lambda*np.eye(ncenters)
right = (M.T)@y
coeff0 = np.linalg.pinv(left)@right
# plot fits
xfit = np.linspace(min(x),max(y),npts)
yfit0 = (np.abs(np.outer(xfit,np.ones(ncenters))-np.outer(np.ones(npts),centers))**3)@coeff0
yfit1 = (np.abs(np.outer(xfit,np.ones(ncenters))-np.outer(np.ones(npts),centers))**3)@coeff1
plt.figure()
plt.plot(x,y,'o',alpha=0.8)
plt.plot(xfit,yfit0,'y-',label=r'$\lambda=0$')
plt.plot(xfit,yfit1,'r-',label=r'$\lambda=1$')
plt.legend()
plt.show()
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[89], line 6 4 indices = np.random.uniform(low=0,high=len(x),size=ncenters).astype(int) 5 centers = x[indices] ----> 6 M = np.abs(np.outer(x,np.ones(ncenters)) 7 -np.outer(np.ones(npts),centers))**3 9 # invert matrices to find weight-regularized coefficients 10 Lambda = 1 ValueError: operands could not be broadcast together with shapes (200,100) (1000,100)
Week 02 : Machine Learning¶
In [73]:
from sklearn.neural_network import MLPRegressor # Changed from MLPClassifier
X = df['math score'].values.reshape(-1, 1) # Reshaped X to 2D array
y = df['reading score'].values # Changed y to a 1D array of values
# Use MLPRegressor for regression tasks
classifier = MLPRegressor(solver='lbfgs', hidden_layer_sizes=(4,), activation='tanh', random_state=1)
classifier.fit(X, y)
print(f"score: {classifier.score(X, y)}")
print("Predictions:")
# Combine X and predictions into a 2-column array for display
predictions = classifier.predict(X)
np.c_[X, predictions]
score: 0.6684056165455765 Predictions:
Out[73]:
array([[72. , 74.01255763],
[69. , 71.61480505],
[90. , 87.78166976],
...,
[59. , 63.5923443 ],
[68. , 70.81412301],
[77. , 77.98023341]], shape=(1000, 2))
In [80]:
from sklearn.neural_network import MLPRegressor
from sklearn.model_selection import train_test_split
# Data Preparation
# Extract values initially as 1D arrays
X = df['math score'].values
y = df['reading score'].values
# Split the data into training and testing sets (still 1D after the split)
xtrain, xtest, ytrain, ytest = train_test_split(X, y, test_size=0.2, random_state=45)
# RESHAPE X arrays to be 2D (n_samples, 1_feature)
# This is required by scikit-learn's fit() and predict() methods.
xtrain = xtrain.reshape(-1, 1)
xtest = xtest.reshape(-1, 1)
# --- Model Definition and Training ---
# Use MLPRegressor for continuous output data
classifier = MLPRegressor(solver='adam', hidden_layer_sizes=(100,), activation='relu',
random_state=1, verbose=True, tol=0.005, max_iter=500)
classifier.fit(xtrain, ytrain) # The fit now uses correctly shaped data
# --- Evaluation and Prediction ---
print(f"\ntrain score (R^2): {classifier.score(xtrain, ytrain)}")
print(f"test score (R^2): {classifier.score(xtest, ytest)}\n")
predictions = classifier.predict(xtest)
# --- Visualization ---
plt.figure(figsize=(8, 5))
# We must use the 1D ytest for plotting the actual points, not the reshaped xtest
plt.scatter(xtest.flatten(), ytest, color='blue', label='Actual Data')
plt.scatter(xtest.flatten(), predictions, color='red', s=10, label='Predictions')
plt.xlabel('Math Score (X_test)')
plt.ylabel('Reading Score (y_test/predictions)')
plt.title('MLPRegressor: Actual vs. Predicted Scores')
plt.legend()
plt.show()
Iteration 1, loss = 1861.77510605 Iteration 2, loss = 1671.55175838 Iteration 3, loss = 1491.14062201 Iteration 4, loss = 1325.79640679 Iteration 5, loss = 1170.11462558 Iteration 6, loss = 1026.77137077 Iteration 7, loss = 895.43188041 Iteration 8, loss = 774.18684861 Iteration 9, loss = 664.97871938 Iteration 10, loss = 567.38852212 Iteration 11, loss = 480.47156771 Iteration 12, loss = 403.50065064 Iteration 13, loss = 336.36357108 Iteration 14, loss = 277.86509966 Iteration 15, loss = 228.06640828 Iteration 16, loss = 186.55478457 Iteration 17, loss = 151.89716954 Iteration 18, loss = 123.83705438 Iteration 19, loss = 101.41941020 Iteration 20, loss = 83.71928341 Iteration 21, loss = 70.14751375 Iteration 22, loss = 60.07142052 Iteration 23, loss = 52.91214605 Iteration 24, loss = 48.07593891 Iteration 25, loss = 45.02853007 Iteration 26, loss = 43.20921645 Iteration 27, loss = 42.27232612 Iteration 28, loss = 42.07927626 Iteration 29, loss = 42.04561021 Iteration 30, loss = 42.18735787 Iteration 31, loss = 42.21977731 Iteration 32, loss = 42.20198007 Iteration 33, loss = 42.15749181 Iteration 34, loss = 42.09480763 Iteration 35, loss = 42.02062349 Iteration 36, loss = 41.97812405 Iteration 37, loss = 41.94974857 Iteration 38, loss = 41.94013208 Iteration 39, loss = 41.91895591 Iteration 40, loss = 41.91136536 Iteration 41, loss = 41.87193005 Iteration 42, loss = 41.86989075 Iteration 43, loss = 41.85874459 Iteration 44, loss = 41.84549274 Iteration 45, loss = 41.83523652 Iteration 46, loss = 41.81625881 Iteration 47, loss = 41.81237856 Iteration 48, loss = 41.79442547 Iteration 49, loss = 41.78649000 Iteration 50, loss = 41.78400974 Iteration 51, loss = 41.75529667 Iteration 52, loss = 41.74265754 Iteration 53, loss = 41.75342382 Iteration 54, loss = 41.71793121 Iteration 55, loss = 41.70218556 Iteration 56, loss = 41.70828716 Iteration 57, loss = 41.67813927 Iteration 58, loss = 41.66875973 Iteration 59, loss = 41.65061668 Iteration 60, loss = 41.61488733 Iteration 61, loss = 41.57674040 Iteration 62, loss = 41.57663569 Iteration 63, loss = 41.54670981 Iteration 64, loss = 41.52823131 Iteration 65, loss = 41.50198661 Iteration 66, loss = 41.48868737 Iteration 67, loss = 41.49086132 Iteration 68, loss = 41.48856988 Iteration 69, loss = 41.49010156 Iteration 70, loss = 41.41905242 Iteration 71, loss = 41.42953781 Iteration 72, loss = 41.36901600 Iteration 73, loss = 41.33253714 Iteration 74, loss = 41.27345260 Iteration 75, loss = 41.24979610 Iteration 76, loss = 41.21827755 Iteration 77, loss = 41.18257418 Iteration 78, loss = 41.17390978 Iteration 79, loss = 41.14023204 Iteration 80, loss = 41.07093001 Iteration 81, loss = 40.98791083 Iteration 82, loss = 40.95659104 Iteration 83, loss = 40.88577553 Iteration 84, loss = 40.81980929 Iteration 85, loss = 40.82635323 Iteration 86, loss = 40.69802791 Iteration 87, loss = 40.65667785 Iteration 88, loss = 40.53309986 Iteration 89, loss = 40.54455732 Iteration 90, loss = 40.49341714 Iteration 91, loss = 40.39466571 Iteration 92, loss = 40.33292332 Iteration 93, loss = 40.20165517 Iteration 94, loss = 40.03455609 Iteration 95, loss = 40.02063663 Iteration 96, loss = 39.82517517 Iteration 97, loss = 39.78221673 Iteration 98, loss = 39.63966256 Iteration 99, loss = 39.47413844 Iteration 100, loss = 39.38794183 Iteration 101, loss = 39.31880564 Iteration 102, loss = 39.35367467 Iteration 103, loss = 39.14222430 Iteration 104, loss = 39.14350957 Iteration 105, loss = 39.11993410 Iteration 106, loss = 39.02168964 Iteration 107, loss = 38.82639055 Iteration 108, loss = 38.84552368 Iteration 109, loss = 38.65386139 Iteration 110, loss = 38.62802513 Iteration 111, loss = 38.57554291 Iteration 112, loss = 38.65117338 Iteration 113, loss = 38.72987072 Iteration 114, loss = 38.75500753 Iteration 115, loss = 38.30144577 Iteration 116, loss = 38.41980796 Iteration 117, loss = 38.12510837 Iteration 118, loss = 38.10474815 Iteration 119, loss = 38.13235537 Iteration 120, loss = 37.99407933 Iteration 121, loss = 37.96341766 Iteration 122, loss = 37.84885800 Iteration 123, loss = 37.92460335 Iteration 124, loss = 37.79891674 Iteration 125, loss = 37.67646966 Iteration 126, loss = 37.76382143 Iteration 127, loss = 37.58385282 Iteration 128, loss = 37.60387721 Iteration 129, loss = 37.49787954 Iteration 130, loss = 37.53434801 Iteration 131, loss = 37.47946338 Iteration 132, loss = 37.55388778 Iteration 133, loss = 37.34361772 Iteration 134, loss = 37.28880645 Iteration 135, loss = 37.21489094 Iteration 136, loss = 37.20822750 Iteration 137, loss = 37.22272365 Iteration 138, loss = 37.02552684 Iteration 139, loss = 37.04591462 Iteration 140, loss = 37.08112126 Iteration 141, loss = 36.87793029 Iteration 142, loss = 36.99002441 Iteration 143, loss = 36.92720937 Iteration 144, loss = 36.87315693 Iteration 145, loss = 37.00348292 Iteration 146, loss = 36.76510341 Iteration 147, loss = 36.70642450 Iteration 148, loss = 36.67401618 Iteration 149, loss = 36.70522557 Iteration 150, loss = 36.60104859 Iteration 151, loss = 36.59553060 Iteration 152, loss = 36.60171476 Iteration 153, loss = 36.54166683 Iteration 154, loss = 36.48685763 Iteration 155, loss = 36.45799298 Iteration 156, loss = 36.41558134 Iteration 157, loss = 36.76386817 Iteration 158, loss = 36.65861018 Iteration 159, loss = 36.75320253 Iteration 160, loss = 36.50754475 Iteration 161, loss = 36.47818889 Iteration 162, loss = 36.32474619 Iteration 163, loss = 36.20293346 Iteration 164, loss = 36.40591748 Iteration 165, loss = 36.25848627 Iteration 166, loss = 36.19557422 Iteration 167, loss = 36.46695759 Iteration 168, loss = 36.18940699 Iteration 169, loss = 36.23257971 Iteration 170, loss = 36.12632192 Iteration 171, loss = 36.10076827 Iteration 172, loss = 36.04230606 Iteration 173, loss = 36.01909091 Iteration 174, loss = 36.03365291 Iteration 175, loss = 36.02167175 Iteration 176, loss = 35.97395368 Iteration 177, loss = 35.94030248 Iteration 178, loss = 35.94889417 Iteration 179, loss = 35.93580638 Iteration 180, loss = 35.99471921 Iteration 181, loss = 35.86506013 Iteration 182, loss = 35.99484516 Iteration 183, loss = 35.82348854 Iteration 184, loss = 35.90413687 Iteration 185, loss = 35.90059002 Iteration 186, loss = 35.84184624 Iteration 187, loss = 35.79234494 Iteration 188, loss = 35.91091047 Iteration 189, loss = 35.90329188 Iteration 190, loss = 35.85692480 Iteration 191, loss = 35.77094931 Iteration 192, loss = 35.92212758 Iteration 193, loss = 35.75849316 Iteration 194, loss = 35.74307913 Iteration 195, loss = 35.75588410 Iteration 196, loss = 35.82005077 Iteration 197, loss = 35.90671606 Iteration 198, loss = 35.72120628 Iteration 199, loss = 35.79364459 Iteration 200, loss = 35.92405168 Iteration 201, loss = 35.77121319 Iteration 202, loss = 35.83433186 Iteration 203, loss = 35.68931695 Iteration 204, loss = 35.62676256 Iteration 205, loss = 35.65133549 Iteration 206, loss = 35.65308270 Iteration 207, loss = 35.72335664 Iteration 208, loss = 35.62883655 Iteration 209, loss = 35.63700450 Iteration 210, loss = 35.69390717 Iteration 211, loss = 35.79592656 Iteration 212, loss = 35.83932202 Iteration 213, loss = 35.53784873 Iteration 214, loss = 35.67490193 Iteration 215, loss = 35.59583209 Iteration 216, loss = 35.69231922 Iteration 217, loss = 35.53245641 Iteration 218, loss = 35.67799064 Iteration 219, loss = 35.63981981 Iteration 220, loss = 35.54789363 Iteration 221, loss = 35.57795741 Iteration 222, loss = 35.57091164 Iteration 223, loss = 35.57376481 Iteration 224, loss = 35.64295973 Iteration 225, loss = 35.63722379 Iteration 226, loss = 35.51604812 Iteration 227, loss = 35.57540510 Iteration 228, loss = 35.62862141 Iteration 229, loss = 35.56795235 Iteration 230, loss = 35.82853498 Iteration 231, loss = 35.74660778 Iteration 232, loss = 35.51853506 Iteration 233, loss = 35.60593800 Iteration 234, loss = 35.47592702 Iteration 235, loss = 35.51672760 Iteration 236, loss = 35.53534289 Iteration 237, loss = 35.56686274 Iteration 238, loss = 35.51925134 Iteration 239, loss = 35.53393225 Iteration 240, loss = 35.57491588 Iteration 241, loss = 35.84630941 Iteration 242, loss = 35.54117336 Iteration 243, loss = 35.75057199 Iteration 244, loss = 35.48274974 Iteration 245, loss = 35.50896942 Training loss did not improve more than tol=0.005000 for 10 consecutive epochs. Stopping. train score (R^2): 0.6700737163322125 test score (R^2): 0.6563594585175452