<jupyter_start><jupyter_text>Import libraries<jupyter_code># import tensorflow 
import tensorflow as tf 
from tensorflow import keras
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
print(tf.__version__)
#import additional libraries
import numpy as np
import pandas as pd
# For visualizations
import matplotlib.pyplot as plt
import seaborn as sns
#for splitting the data into training and test set 
from sklearn.model_selection import train_test_split
# For Normalization
from sklearn.preprocessing import MinMaxScaler<jupyter_output><empty_output><jupyter_text>Load data<jupyter_code>#Loading data from a csv file 
df=pd.read_csv('/content/salary_dataset.csv')
df.head()
#Loaing from the course github account 
df=pd.read_csv('https://raw.githubusercontent.com/oluwole-packt/datasets/main/salary_dataset.csv')
df.head()<jupyter_output><empty_output><jupyter_text>Data preprocessing<jupyter_code>#check some random samples 
df.sample(10)

#check the data for any missing values 
df.isnull().sum()
#drop the null values 
df=df.dropna()<jupyter_output><empty_output><jupyter_text>The number of missing values are quite small, in this scenario we drop the missing values. There are other methods of handling missing values. Although the exam will focus more on testing your modelling skills, data preprocessing will come in handy as a data professional, so I will refer you to this excellent book on data preprocessing by packt, Hands-On Data Preprocessing in Python: Learn how to effectively prepare data for successful data analytics by <NAME>.<jupyter_code>#check for null values 
df.isnull().sum()
df.columns
#drop irrelevant columns 
df =df.drop(columns =['Name', 'Phone_Number','Date_Of_Birth'])
#its good practice to check your data
df.head()
#Converting categorical variables to numeric values 
df = pd.get_dummies(df, drop_first=True)
df.head()

#checking for correlation in the data 
df.corr()<jupyter_output><empty_output><jupyter_text>Modelling<jupyter_code># We split the attributes and labels into X and y variables 
X = df.drop("Salary", axis=1)
y = df["Salary"]
# Create training and test sets
#We set the random state to ensure reproduciblility 

X_train, X_test, y_train, y_test = train_test_split(X, 
                                                    y, 
                                                    test_size=0.2, 
                                                    random_state=10) 
#Set random set for reproducibility  
tf.random.set_seed(10)
#create a model using the Keras API 
model =Sequential([Dense(units=1,input_shape=[len(X_train.columns)])])
#compile the model 
model.compile(loss=tf.keras.losses.mae, optimizer=tf.keras.optimizers.SGD(), metrics = ['mae'])
#Fit the model 
model.fit(X_train,y_train, epochs =50)<jupyter_output>Epoch 1/50
6/6 [==============================] - 0s 2ms/step - loss: 99116.2109 - mae: 99116.2109
Epoch 2/50
6/6 [==============================] - 0s 2ms/step - loss: 99115.3672 - mae: 99115.3672
Epoch 3/50
6/6 [==============================] - 0s 3ms/step - loss: 99114.5391 - mae: 99114.5391
Epoch 4/50
6/6 [==============================] - 0s 3ms/step - loss: 99113.7109 - mae: 99113.7109
Epoch 5/50
6/6 [==============================] - 0s 2ms/step - loss: 99112.8516 - mae: 99112.8516
Epoch 6/50
6/6 [==============================] - 0s 3ms/step - loss: 99112.0234 - mae: 99112.0234
Epoch 7/50
6/6 [==============================] - 0s 2ms/step - loss: 99111.1797 - mae: 99111.1797
Epoch 8/50
6/6 [==============================] - 0s 3ms/step - loss: 99110.3359 - mae: 99110.3359
Epoch 9/50
6/6 [==============================] - 0s 2ms/step - loss: 99109.5000 - mae: 99109.5000
Epoch 10/50
6/6 [==============================] - 0s 2ms/step - loss: 99108.6562 - mae: 99108.6562
Epoch 11/[...]<jupyter_text>Model 1 We build a model with a single layer for 500 epochs<jupyter_code>#Set the random seed
tf.random.set_seed(10)
#create a model 
model1 =Sequential([Dense(units=1,input_shape=[len(X_train.columns)])])
#compile the model 
model1.compile(loss="mae", optimizer="SGD", metrics ="mae")
#fit the model 
history1= model1.fit(X_train,y_train, epochs =500) #number of times the model will go through training examples 

#Model summary 
model1.summary()
def visualize_model(history):
  #Lets visualize our model
  print(history.history.keys())
  # Lets plot the loss
  plt.plot(history.history['loss'])
  plt.title('Model loss')
  plt.ylabel('Loss')
  plt.xlabel('Number of epochs')
  plt.legend(['loss plot'], loc='upper right')
  plt.show()  
visualize_model(history)<jupyter_output>dict_keys(['loss', 'mae'])<jupyter_text>We have this straight line showing the loss dropped all the way, perhaps we need to train it for more epochs to get a better result? Lets try 1000 epochs.   Model 2 We build a model with a single layer for 1000 epochs<jupyter_code>#Set the random seed
tf.random.set_seed(10)
#create a model 
model2 =Sequential([Dense(units=1,input_shape=[len(X_train.columns)])])
#compile the model 
model2.compile(loss="mae", optimizer="SGD", metrics ="mae")
#fit the model 
history2= model2.fit(X_train,y_train, epochs =1000) #number of times the model will go through training examples 

#Lets visualize our result 
visualize_model(history2)<jupyter_output>dict_keys(['loss', 'mae'])<jupyter_text>Dont believe anything, try it for 5000 epochs and see if you could make any progress.   Model 3 Lets add an extra layer at 500 epochs<jupyter_code>#Set random set 
tf.random.set_seed(10)

#create a model 
model3 =Sequential([
                   Dense(units=64, activation='relu', input_shape=[len(X_train.columns)]),
                   Dense(units=1)
                   
                   ])
#compile the model 
model3.compile(loss="mae", optimizer="SGD", metrics = ['mae'])

#Fit the model 
history3 =model3.fit(
    X_train, y_train, epochs=500)
#Model summary 
model3.summary()
#Lets visualize our result 
visualize_model(history3)<jupyter_output>dict_keys(['loss', 'mae'])<jupyter_text>Wow! The loss dropped to 3955.2666, after about 100 epochs nothing much seems to be happening. What if we add another extra layer? What do you think?   Model 4 3 layers at 500 epochs<jupyter_code>#Set random set 
tf.random.set_seed(25)

#create a model
model4 =Sequential([
                   Dense(units=64, activation='relu', input_shape=[len(X_train.columns)]),
                    Dense(units=32, activation='relu'),
                    Dense(units=1)
                   
                   ])
#compile the model 
model4.compile(loss="mae", optimizer="SGD", metrics = "mae")
#fit the model 

history4 =model4.fit(
    X_train, y_train, epochs=500)
#Model summary 
model4.summary()<jupyter_output>Model: "sequential_35"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_70 (Dense)            (None, 64)                576       
                                                                 
 dense_71 (Dense)            (None, 32)                2080      
                                                                 
 dense_72 (Dense)            (None, 1)                 33        
                                                                 
=================================================================
Total params: 2,689
Trainable params: 2,689
Non-trainable params: 0
_________________________________________________________________<jupyter_text>Wow seems our model didnt perform any better than model 3  Improving our prediction model To improve our model we apply normalization to bring all the attributes to scale so as not to mislead the model into thinking some attributes are of greater importance as this may not be the case. To understand this, lets look at the scale of our data again<jupyter_code>df.describe()<jupyter_output><empty_output><jupyter_text>We can see experience is on a different scale while all the other values expect our target label are on a scale of 0 to 1 after we used one hot encoding. So lets normalize the data using the scikit learn library and see what happens Normalization<jupyter_code># create a scaler object
scaler = MinMaxScaler()
# fit and transform the data
X_norm = pd.DataFrame(scaler.fit_transform(X), columns=X.columns)

X_norm.head()
#lets check the scale again
X_norm.describe()<jupyter_output><empty_output><jupyter_text>Now the scale are all the same, lets build the model using model 3 (our best model so far)<jupyter_code># Create training and test sets with the normalized data (X_norm)
X_train, X_test, y_train, y_test = train_test_split(X_norm, 
                                                    y, 
                                                    test_size=0.2, 
                                                    random_state=42) # set random state for reproducible splits<jupyter_output><empty_output><jupyter_text>Model 52layers for 1000 epochs and we try a RMSprop optimizer. Also we use callbacks to stop the training when no progress is been made.<jupyter_code>#Set random set 
tf.random.set_seed(10)
#create a model 
model5 =Sequential([
                   Dense(units=64, activation='relu', input_shape=[len(X_train.columns)]),
                    Dense(units=64, activation ="relu"),
                    
                    Dense(units=1)
                   
                   ])
#compile the model 
model5.compile(loss="mae", optimizer=tf.keras.optimizers.RMSprop(0.001), metrics = ['mae'])
#fit the model 
early_stop=keras.callbacks.EarlyStopping(monitor='loss', patience=10)
history5 =model5.fit(
    X_train, y_train, epochs=1000, callbacks=[early_stop])

#Model summary 
model5.summary()
#Lets visualize our result 
visualize_model(history5)<jupyter_output>dict_keys(['loss', 'mae'])<jupyter_text>Model 6 3 layers with Adam , 1000 epochs with callbacks<jupyter_code>#Set random set 
tf.random.set_seed(10)
#create a model 

model6 =Sequential([
                   Dense(units=64, activation='relu', input_shape=[len(X_train.columns)]),
                    Dense(units=64, activation ="relu"),
                    
                    Dense(units=1)
                   
                   ])
#compile the model 
model6.compile(loss="mae", optimizer=tf.keras.optimizers.Adam(), metrics = ['mae'])
#fit the model 
early_stop=keras.callbacks.EarlyStopping(monitor='loss', patience=10)
history6 =model6.fit(
    X_train, y_train, epochs=1000, callbacks=[early_stop])

#Model summary 
model6.summary()
#Lets visualize our result 
visualize_model(history6)<jupyter_output>dict_keys(['loss', 'mae'])<jupyter_text>Model 7 3 layers, 1000 epochs, SGD with callbacks<jupyter_code>#Set random set 
tf.random.set_seed(25)
#create a model 
model7 =Sequential([
                   Dense(units=64, activation='relu', input_shape=[len(X_train.columns)]),
                    Dense(units=64, activation ="relu"),
                   Dense(units=1)
                   
                   ])
#compile the model 
model7.compile(loss="mae", optimizer="SGD", metrics ="mae")
#fit the model 
early_stop=keras.callbacks.EarlyStopping(monitor='loss', patience=10)
history7 =model7.fit(
    X_train, y_train, epochs=1000, callbacks=[early_stop])
#Model summary 
model7.summary()<jupyter_output>Model: "sequential_38"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_79 (Dense)            (None, 64)                576       
                                                                 
 dense_80 (Dense)            (None, 64)                4160      
                                                                 
 dense_81 (Dense)            (None, 1)                 65        
                                                                 
=================================================================
Total params: 4,801
Trainable params: 4,801
Non-trainable params: 0
_________________________________________________________________<jupyter_text>After we normalized the data we recorded amazing results on the training data, now is the moment of truth. Lets evaluate our model on test dat (unseen data). If you are ready? Then lets go!<jupyter_code>def eval_testing(model):
  return model.evaluate(X_test, y_test)
models = [model1, model2, model3, model4, model5, model6, model7]
for x in models: 
  eval_testing(x)<jupyter_output>2/2 [==============================] - 0s 4ms/step - loss: 100566.1562 - mae: 100566.1562
2/2 [==============================] - 0s 4ms/step - loss: 100438.2969 - mae: 100438.2969
2/2 [==============================] - 0s 4ms/step - loss: 18655.2812 - mae: 18655.2812
2/2 [==============================] - 0s 4ms/step - loss: 100664.0234 - mae: 100664.0234
2/2 [==============================] - 0s 6ms/step - loss: 199.5206 - mae: 199.5206
2/2 [==============================] - 0s 5ms/step - loss: 23.6596 - mae: 23.6596
2/2 [==============================] - 0s 6ms/step - loss: 29844.7852 - mae: 29844.7852<jupyter_text>From our evaluation test, model 6 is the model we will be using to make predictions. Since it has the lowest error on the test set.  Making Predictions<jupyter_code>#Lets make predictions on our test data
y_preds=model6.predict(X_test).flatten()
y_preds
#Lets make a dataframe to compare our prediction with the ground truth
df_predictions = pd.DataFrame({'Ground_Truth': y_test, 'Model_prediction': y_preds}, columns=[ 'Ground_Truth', 'Model_prediction'])
df_predictions['Model_prediction']= df_predictions['Model_prediction'].astype(int)
#Lets see the difference in values 
df_predictions['diff']=df_predictions['Ground_Truth']-df_predictions['Model_prediction']
#Lets look at 10 samples 
df_predictions.sample(10)<jupyter_output><empty_output><jupyter_text>Saving the model  Now we have a model that works really well. How about we save the model?<jupyter_code>#Saving the model in one line of code
model6.save('salarypredictor.h5')
#Alternate method is 
#model6.save('salarypredictor')<jupyter_output><empty_output><jupyter_text>Loading the model<jupyter_code>#loading the model 
saved_model =tf.keras.models.load_model("/content/salarypredictor.h5")
saved_model<jupyter_output><empty_output><jupyter_text>For method 2. you will have to load the file path.<jupyter_code>#View the model summary of our saved model
saved_model.summary()
#testing out our model 
y_preds=saved_model.predict(X_test).flatten()
y_preds
#create a dataframe as before
df_predictions = pd.DataFrame({'Ground_Truth': y_test, 'Model_prediction': y_preds}, columns=[ 'Ground_Truth', 'Model_prediction'])
df_predictions['Model_prediction']= df_predictions['Model_prediction'].astype(int)
df_predictions.tail()<jupyter_output><empty_output><jupyter_text>Everything works perfectly<jupyter_code>#Putting everything into a function for our big task 
def salary_predictor(df):
  df_hires= df.drop(columns=['Name', 'Phone_Number','Date_Of_Birth' ])
  df_hires = pd.get_dummies(df_hires, drop_first=True)
  X_norm = pd.DataFrame(scaler.fit_transform(df_hires), columns=df.columns)
  y_preds=saved_model.predict(X_norm).flatten()
  df_predictions = pd.DataFrame({ 'Model_prediction': y_preds}, columns=[ 'Model_prediction'])
  df_predictions['Model_prediction']= df_predictions['Model_prediction'].astype(int)
  df['Salary']=df_predictions['Model_prediction']
  return df<jupyter_output><empty_output><jupyter_text>Lets load the data for our 7 new hires and see what we should pay them<jupyter_code>#Load the data
df_new=pd.read_csv('https://raw.githubusercontent.com/oluwole-packt/datasets/main/new_hires.csv')
df_new
#Lets see how much
salary_predictor(df_new)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14403837657009405, 'fraction_numerical': 0.042353089692608724, 'mean_word_length': 3.6586298147603644, 'pattern_counts': {'":': 0, '<': 81, '<?xml version=': 0, '>': 81, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '22', 'dir': 'jupyter-structured-clean-dedup', 'id': '215524', 'license': 'MIT', 'n_tokens_mistral': 5343, 'n_tokens_neox': 4752, 'n_words': 1339, 'path': 'Chapter 3/Linear_Regression_with_TensorFlow.ipynb', 'repo_name': 'PacktPublishing/TensorFlow-Developer-Certificate', 'size': '15847'}