<jupyter_start><jupyter_text>Rain Prediction using ANNAssignment 2 - Set 7Group - 270Ro<NAME> - 2020sc04439<NAME> - 2020sc04853   Importing Libraries<jupyter_code># for data manipulation
import numpy as np 
import pandas as pd 

from sklearn.model_selection import train_test_split # for splitting the data into train and test samples
from sklearn.metrics import classification_report # for model evaluation metrics
from sklearn.preprocessing import LabelEncoder # for encoding categorical features from strings to number arrays
from sklearn.metrics import confusion_matrix # for model confusion matrix
from sklearn.impute import SimpleImputer # for Missing value imputation
from sklearn.decomposition import PCA # for dimensions reduction

# for data visualization
import matplotlib.pyplot as plt
import seaborn as sns 
%matplotlib inline

from IPython.display import display # for object display

# for ANN modelling
import tensorflow as tf
from keras.models import Sequential
from keras.layers import Dense, Flatten, Dropout
from tensorflow.keras.optimizers import Adam<jupyter_output><empty_output><jupyter_text>Defining Utility function<jupyter_code># Function to get categorical column volumetric analysis
def get_volumetric(dataset, col):
    col_volumetric = dataset[col].value_counts(dropna=False).reset_index()
    col_volumetric.columns = [col, 'volume']
    col_volumetric['%volume'] = ((col_volumetric['volume']*100)/col_volumetric['volume'].sum()).round(2)
    return col_volumetric

# Function to check and get the missingValue volumetric analysis
def check_missingValue(dataset):
    null_volumetric = dataset.isnull().sum().reset_index()
    null_volumetric.columns = ['Column', 'Missing value']
    null_volumetric['%Missing value'] = ((null_volumetric['Missing value']*100)/dataset.shape[0]).round(2)
    return null_volumetric

# Function to plot the confusion matrix
def plot_cm(y_true, y_pred, figsize=(8,6)):
    # get the confusion matrix
    cm = confusion_matrix(y_true, y_pred, labels=np.unique(y_true))
    
    # plotting the heatmap
    cm_sum = np.sum(cm, axis=1, keepdims=True)
    cm_perc = cm / cm_sum.astype(float) * 100
    annot = np.empty_like(cm).astype(str)
    nrows, ncols = cm.shape
    for i in range(nrows):
        for j in range(ncols):
            c = cm[i, j]
            p = cm_perc[i, j]
            if i == j:
                s = cm_sum[i]
                annot[i, j] = '%.1f%%\n%d/%d' % (p, c, s)
            elif c == 0:
                annot[i, j] = ''
            else:
                annot[i, j] = '%.1f%%\n%d' % (p, c)
    cm = pd.DataFrame(cm, index=np.unique(y_true), columns=np.unique(y_true))
    cm.index.name = 'Actual'
    cm.columns.name = 'Predicted'
    fig, ax = plt.subplots(figsize=figsize)
    sns.heatmap(cm, cmap= "Blues", annot=annot, fmt='', ax=ax)<jupyter_output><empty_output><jupyter_text>Importing Dataset  Rain Prediction- Context:    - Predict next-day rain by training classification models on the target variable RainTomorrow.- Content:    - This dataset contains about 10 years of daily weather observations from many locations across Australia.    - RainTomorrow is the target variable to predict. It means -- did it rain the next day, Yes or No? This column is Yes if the rain for that day was 1mm or more.<jupyter_code>dataset = pd.read_csv("weatherAUS.csv", index_col=False)

print("Dataset Shape:", dataset.shape)<jupyter_output>Dataset Shape: (145460, 23)<jupyter_text>Data Visualization and Exploration Printing the first 5 & last 5 rows for sanity check to identify all the features present in the dataset and if the target matches with them.<jupyter_code># First 5 rows
print("First 5 rows of the dataset")
display(dataset.head(5))

# Last rows
print("Last 5 rows of the dataset")
display(dataset.tail(5))<jupyter_output>First 5 rows of the dataset<jupyter_text>Univariate & Multivariate Descriptive Analysis  Target Column Distribution - RainTomorrow<jupyter_code># Getting the RainTomorrow class distribution 
target_volumetric =  get_volumetric(dataset, 'RainTomorrow')
display(target_volumetric)

# Plotting a pie chart
colors = sns.color_palette('pastel')[0:5]
plt.figure(figsize=(7,7))
plt.title("RainTomorrow distribution")
plt.pie(target_volumetric['%volume'], 
        labels = target_volumetric['RainTomorrow'], 
        colors = colors, autopct='%.0f%%')
plt.show();
# Printing a concise summary of a DataFrame.
dataset.info()
# Creating column's subsets as per the datatype
dataset_dtypes = dataset.dtypes.reset_index()
dataset_dtypes.columns = ['variable', 'dtype']
# Getting the categorical columns
cat_cols = dataset_dtypes[dataset_dtypes['dtype']=='object']['variable'].tolist()
# Getting the continuos columns
cont_cols = dataset_dtypes[dataset_dtypes['dtype']!='object']['variable'].tolist()

print("Categorical Columns:", cat_cols)
print()
print("Continuos Columns:", cont_cols)<jupyter_output>Categorical Columns: ['Date', 'Location', 'WindGustDir', 'WindDir9am', 'WindDir3pm', 'RainToday', 'RainTomorrow']

Continuos Columns: ['MinTemp', 'MaxTemp', 'Rainfall', 'Evaporation', 'Sunshine', 'WindGustSpeed', 'WindSpeed9am', 'WindSpeed3pm', 'Humidity9am', 'Humidity3pm', 'Pressure9am', 'Pressure3pm', 'Cloud9am', 'Cloud3pm', 'Temp9am', 'Temp3pm']<jupyter_text>Categorical Columns<jupyter_code># Descriptive statistics include those that summarize the count, unique and top category freq of a dataset’s distribution.
dataset[cat_cols].describe().T
# Getting the category volume distribution and cardinality
for col in cat_cols:
    cat_volumteric_t = get_volumetric(dataset, col)
    print(col)
    print(f"Unique Category preset: {cat_volumteric_t.shape[0]}")
    display(cat_volumteric_t)
    print()<jupyter_output>Date
Unique Category preset: 3436<jupyter_text>Bi-Variate EDA on Categorical Attributes (Fetaures) w.r.t RainTomorrow<jupyter_code># Cross table plot

ns = int(dataset.shape[0]*.90)
dataset_sample = dataset.sample(n = ns).fillna('Null')

for col in cat_cols:
    if col not in ["RainTomorrow", "Date"]:
        fig = plt.figure(figsize=(14, 6));
        ax = fig.gca();
        ax.tick_params(axis='x', rotation=90)
        sns.countplot(x=col, hue="RainTomorrow", data=dataset_sample, palette="Set2", ax = ax)<jupyter_output><empty_output><jupyter_text>Continuos Columns<jupyter_code># Descriptive statistics include those that summarize the central tendency, dispersion and shape of a dataset’s distribution.
dataset[cont_cols].describe(percentiles=[.05,.25,.50,.75,.95]).round(2).T<jupyter_output><empty_output><jupyter_text>Bi-Variate EDA on Continuos Attributes (Features) w.r.t to RainTomorrow<jupyter_code>for col in cont_cols:
    fig = plt.figure(figsize=(12, 5))
    ax = fig.gca()
    plt.title(f"Box plot for {col} w.r.t RainTomorrow")
    sns.boxplot( x = col, y = 'RainTomorrow', data=dataset, ax = ax);<jupyter_output><empty_output><jupyter_text>Correlation Analysis<jupyter_code>fig = plt.figure(figsize=(16, 10));
sns.heatmap(dataset[cont_cols].corr(), cmap="YlGnBu",  annot=True, linewidths ='.02');<jupyter_output><empty_output><jupyter_text>Data Pre-processing and cleaning<jupyter_code># Creating a copy of dataset
data_raw = dataset.copy()<jupyter_output><empty_output><jupyter_text>Checking for Missing Values<jupyter_code>null_volumetric = check_missingValue(dataset)
null_volumetric.sort_values(by = '%Missing value', ascending=False)<jupyter_output><empty_output><jupyter_text>Missing Value Treatment - Dropping rows where target "RainTomorrow" is null<jupyter_code>data_tw = data_raw.dropna(subset = ["RainTomorrow"])
print("Shape of the data after droping missing value present in RainTomorrow")
print(data_tw.shape)<jupyter_output>Shape of the data after droping missing value present in RainTomorrow
(142193, 23)<jupyter_text>- Dropping columns where "%Missing Value" is more than ~40%* because imputing may add unwanted bias in the data<jupyter_code>cols_to_drop = ['Evaporation', 'Sunshine', 'Cloud9am', 'Cloud3pm']
data_tw = data_raw.drop(columns = cols_to_drop)

print(f"Shape of the data after droping missing value present in {cols_to_drop}")
print(data_tw.shape)<jupyter_output>Shape of the data after droping missing value present in ['Evaporation', 'Sunshine', 'Cloud9am', 'Cloud3pm']
(145460, 19)<jupyter_text>- Imputing the missing values<jupyter_code>imputer = SimpleImputer(strategy="most_frequent")
imputed_array = imputer.fit_transform(data_tw)

data_tw_imputed = pd.DataFrame(imputed_array, columns=data_tw.columns)

print(f"Shape of the data after imputing missing values")
print(data_tw_imputed.shape)<jupyter_output>Shape of the data after imputing missing values
(145460, 19)<jupyter_text>Missing value imputation post check<jupyter_code>null_volumetric = check_missingValue(data_tw_imputed)
null_volumetric.sort_values(by = '%Missing value', ascending=False)<jupyter_output><empty_output><jupyter_text>Extracting Year, Month, Week, Day of the week from "Date"<jupyter_code>data_tw_imputed["Date"] = pd.to_datetime(data_tw_imputed["Date"])

data_tw_imputed['Year'] = data_tw_imputed["Date"].dt.year.astype(object)
data_tw_imputed['Month'] = data_tw_imputed["Date"].dt.month.astype(object)
data_tw_imputed['Week'] = data_tw_imputed["Date"].dt.week.astype(object)
data_tw_imputed['dayofweek'] = data_tw_imputed["Date"].dt.dayofweek.astype(object)
# Getting the feature list 

target = 'RainTomorrow'
cont_cols2 = list(set(cont_cols) - set(cols_to_drop) - set([target]))
cat_cols2 = list(set(cat_cols) - set(cols_to_drop) - set([target, 'Date'])) + ['Year', 'Month', 'Week', 'dayofweek']

for col in cont_cols2:
    data_tw_imputed[col] = data_tw_imputed[col].astype(float)

for col in cat_cols2:
    data_tw_imputed[col] = data_tw_imputed[col].astype(object)
    
print("Features after missing value treatment:\n")
print(f"Target: {target}")
print()
print(f"Continuos Features: {cont_cols2}")
print()
print(f"Categorical Features: {cat_cols2}")
# Creating a copy of imputed dataset for quick rollback
data_tw_level2 = data_tw_imputed.copy()<jupyter_output><empty_output><jupyter_text>Label Encoding the Target Variable "RainTomorrow"<jupyter_code>target_en = LabelEncoder()
data_tw_level2[target] = target_en.fit_transform(data_tw_level2[target])
get_volumetric(data_tw_level2, target)<jupyter_output><empty_output><jupyter_text>Standardizing &  Correcting the skewness of Continous Features by applying log transformation<jupyter_code>for col in cont_cols2:
    print(f"Applying log Transformation {col}")
    data_tw_level2[col] = data_tw_level2[col].apply(lambda x: np.log2(x+0.001))<jupyter_output>Applying log Transformation Temp3pm
Applying log Transformation Temp9am
Applying log Transformation MinTemp
Applying log Transformation Pressure9am
Applying log Transformation WindSpeed3pm
Applying log Transformation Rainfall
Applying log Transformation WindSpeed9am
Applying log Transformation Pressure3pm
Applying log Transformation Humidity9am
Applying log Transformation WindGustSpeed
Applying log Transformation Humidity3pm
Applying log Transformation MaxTemp<jupyter_text>Applying One-hot Encoding on Categorical Features<jupyter_code>data_tw_level2 = pd.get_dummies(data_tw_level2, columns=cat_cols2, drop_first=True)
print("Shape of the dataset after encoding:", data_tw_level2.shape)<jupyter_output>Shape of the dataset after encoding: (145460, 187)<jupyter_text>Data Preparation<jupyter_code>feature_list = set(data_tw_level2.columns) - set([target, 'Date'])

X = data_tw_level2[feature_list].astype(float)
y = data_tw_level2[target].values

print(f"Dataset Shape:\n\nX -> {X.shape}\ny -> {y.shape}")

# Applying PCA to reduce the dimensions and sparsity
pca = PCA(n_components=32)
X_reduced = pca.fit_transform(X.fillna(0.0))

# Keeping 20% of the data aside for testing
X_train, X_test, y_train, y_test = train_test_split(X_reduced, y, test_size = .20, random_state=2020)

print(f"\nTrain-Test Shape:\n \nX_train -> {X_train.shape} \t y_train -> {y_train.shape} \nX_test ->  {X_test.shape} \t y_test -> {y_test.shape}")<jupyter_output>Dataset Shape:

X -> (145460, 185)
y -> (145460,)

Train-Test Shape:
 
X_train -> (116368, 32) 	 y_train -> (116368,) 
X_test ->  (29092, 32) 	 y_test -> (29092,)<jupyter_text>Model Building<jupyter_code># Initialising the ANN

leaky_relu = tf.keras.layers.LeakyReLU(alpha=0.3)

model = Sequential()
model.add(Dense(units = 32, activation = leaky_relu, input_dim = 32))
model.add(Dense(units = 32, activation = leaky_relu))
model.add(Dense(units = 16, activation = leaky_relu))
model.add(Dense(units = 8,  activation = leaky_relu))
model.add(Dense(units = 1, activation = 'sigmoid'))

print("ANN Model Summary:")
model.summary()
print()

# Compiling the ANN
adam = Adam(learning_rate=0.00001)
model.compile(optimizer = adam, loss = 'binary_crossentropy', metrics = ['accuracy'])

# Training the ANN
history = model.fit(X_train,
                    y_train, 
                    batch_size = 128, 
                    epochs = 100, 
                    validation_split=0.2)
history_df = pd.DataFrame(history.history)

plt.figure(figsize= (12,6))
plt.plot(history_df.loc[:, ['accuracy']], color="red", label='Training accuracy')
plt.plot(history_df.loc[:, ['val_accuracy']], color="blue", label='Validation accuracy')
plt.title('Training and Validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
history_df = pd.DataFrame(history.history)

plt.figure(figsize= (12,6))
plt.plot(history_df.loc[:, ['loss']], color="green", label='Training loss')
plt.plot(history_df.loc[:, ['val_loss']], color="orange", label='Validation loss')
plt.title('Training and Validation Loss')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()<jupyter_output><empty_output><jupyter_text>Predicting the test set results<jupyter_code>y_pred = model.predict(X_test)
y_pred = (y_pred > 0.5)
# Classification Report
print(classification_report(y_test, y_pred))
# Confusion Matrix
plot_cm(y_test, y_pred, figsize=(12,8))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11958851264466352, 'fraction_numerical': 0.019502786112301756, 'mean_word_length': 5.978564307078764, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 98, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '23', 'dir': 'jupyter-structured-clean-dedup', 'id': '61103', 'license': 'MIT', 'n_tokens_mistral': 5011, 'n_tokens_neox': 4658, 'n_words': 1118, 'path': 'Modelling v2.ipynb', 'repo_name': 'iamrochit/Australian-Weather-Prediction-Deep-Learning', 'size': '14004'}