# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# Imports
import pandas as pd
from pathlib import Path
import tensorflow as tf
import numpy as np
from tensorflow.keras.layers import Dense
from tensorflow.keras.models import Sequential
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler,OneHotEncoder

# Read the .csv file from the Resources folder into a Pandas DataFrame
bitcoin_data_df =pd.read_csv(Path('./Resources/Bitcoin_Historical.csv'))

# Review the DataFrame
print(bitcoin_data_df.head())
print(bitcoin_data_df.tail())

# Review the data types associated with the columns
bitcoin_data_df.dtypes

# +
# Drop unnecessary information from the dataframe
bitcoin_data_df = bitcoin_data_df.drop(columns=['Date'])

# Review the DataFrame
bitcoin_data_df

# +
# Apply a binary "signal" where positive changes are to labeled as 1, all other to be labeled as 0
bitcoin_data_df['Signal'] = bitcoin_data_df['Change %'].apply(lambda x: '1' if x >= '0' else '0')

# Review the DataFrame
bitcoin_data_df

# +
# Review the data types associated with the columns
bitcoin_data_df.dtypes

# Reassign datatype for 
bitcoin_data_df = bitcoin_data_df.astype({'Signal':np.float})

# Review the data types associated with the columns
bitcoin_data_df.dtypes

# +
# Create a list of categorical variables 
categorical_variables = list(bitcoin_data_df.dtypes[bitcoin_data_df.dtypes == "object"].index)

# Display the categorical variables list
categorical_variables


# +
# Create a OneHotEncoder instance
enc = OneHotEncoder(sparse=False)

# Encode the categorcal variables using OneHotEncoder
encoded_data = enc.fit_transform(bitcoin_data_df[categorical_variables])

# Create a DataFrame with the encoded variables
encoded_variables_df = pd.DataFrame(
    encoded_data,
    columns= enc.get_feature_names(categorical_variables)
)

# Review the DataFrame
encoded_variables_df

# +
# Add the numerical variables from the original DataFrame to the one-hot encoding DataFrame
numerical_variables_df = bitcoin_data_df.drop(columns=categorical_variables)
encoded_df = pd.concat(
    [
        numerical_variables_df,
        encoded_variables_df
    ],
    axis=1
)

# Review the Dataframe
encoded_df.head()

# +
# Define target variable y
y = encoded_df['Signal']

# Display sample of target data
y[:5]

# +
# Define test variable x
X = encoded_df.drop(columns=["Signal"]).copy()

# Display sample of testing data
X.head()
# -

# Split the preprocessed data into a training and testing dataset
X_train, X_test, y_train, y_test = train_test_split(X,y,random_state = 1)

# +
# Create a StandardScaler instance
X_scaler = StandardScaler()

# Fit the scaler to the features training dataset
X_scaler.fit(X_train)

# Fit the scaler to the features training dataset
X_train_scaled = X_scaler.transform(X_train)
X_test_scaled = X_scaler.transform(X_test)

# +
# Define the the number of inputs (features) to the model
number_input_features = len(X_train.iloc[0])

# Review the number of features
number_input_features
# -

# Define the number of neurons in the output layer
number_output_neurons = 1

# +
# Define the number of hidden nodes for the first hidden layer
hidden_nodes_layer1 =  (number_input_features +1) // 2

# Review the number hidden nodes in the first layer
hidden_nodes_layer1

# +
# Define the number of hidden nodes for the second hidden layer
hidden_nodes_layer2 =  (hidden_nodes_layer1 +1) //2

# Review the number hidden nodes in the second layer
hidden_nodes_layer2
# -

# Create the Sequential model instance
nn = Sequential()

# Add the first hidden layer
nn.add(Dense(units=hidden_nodes_layer1, input_dim = number_input_features, activation='relu'))

# Add the second hidden layer
nn.add(Dense(units=hidden_nodes_layer2, activation='selu'))

# Add the output layer to the model specifying the number of output neurons and activation function
nn.add(Dense(units=1, activation = 'linear'))

# Display the Sequential model summary
nn.summary()

# Compile the Sequential model
nn.compile(loss='binary_crossentropy', optimizer = 'adam', metrics=['accuracy'])

# Fit the model using 100 epochs and the training data
fit_model = nn.fit(X_train_scaled, y_train, epochs=100)

# Evaluate the model loss and accuracy metrics using the evaluate method and the test data
model_loss, model_accuracy = nn.evaluate(X_test_scaled, y_test, verbose=2)

# Display the model loss and accuracy results
print(f"Loss: {model_loss}, Accuracy: {model_accuracy}")

# +
print("Test Model Results")

# Evaluate the model loss and accuracy metrics using the evaluate method and the test data
model_loss, model_accuracy = nn.evaluate(X_test_scaled, y_test, verbose=2)

# Display the model loss and accuracy results
print(f"Loss: {model_loss}, Accuracy: {model_accuracy}")

# +
### Develop a secondary model for comparison ###

# +
# Define the the number of inputs (features) to the model
number_input_features = len(X_train.iloc[0])

# Review the number of features
number_input_features
# -

# Define the number of neurons in the output layer
number_output_neurons_A1 = 1

# +
# Define the number of hidden nodes for the first hidden layer
hidden_nodes_layer1_A1 = (number_input_features + 1) // 2

# Review the number of hidden nodes in the first layer
hidden_nodes_layer1_A1

# +
# Define the number of hidden nodes for the second hidden layer
hidden_nodes_layer2_A1 = (hidden_nodes_layer1_A1 + 1) // 2

# Review the number of hidden nodes in the second layer
hidden_nodes_layer2_A1

# +
# Define the number of hidden nodes for the third hidden layer
hidden_nodes_layer3_A1 = (hidden_nodes_layer2_A1 + 1) // 2

# Review the number of hidden nodes in the third layer
hidden_nodes_layer3_A1

# +
# Define the number of hidden nodes for the fourth hidden layer
hidden_nodes_layer4_A1 = (hidden_nodes_layer3_A1 + 1) // 2

# Review the number of hidden nodes in the fourth layer
hidden_nodes_layer4_A1
# -

# Create the Sequential model instance
nn_A1 = Sequential()

# +
# First hidden layer
nn_A1.add(Dense(units=hidden_nodes_layer1_A1, input_dim=number_input_features, activation="relu"))

# Second hidden layer
nn_A1.add(Dense(units=hidden_nodes_layer2_A1, activation="selu"))

# Third hidden layer
nn_A1.add(Dense(units=hidden_nodes_layer3_A1, activation="gelu"))

# Fourth hidden layer
nn_A1.add(Dense(units=hidden_nodes_layer4_A1, activation="relu"))

# Output layer
nn_A1.add(Dense(units=1, activation="linear"))

# Check the structure of the model
nn_A1.summary()
# -

# Compile the model
nn_A1.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])

# Fit the model
fit_model_A1 = nn_A1.fit(X_train_scaled, y_train, epochs=100)

# +
print("Alternative Model 1 Results")

# Evaluate the model loss and accuracy metrics using the evaluate method and the test data
model_loss, model_accuracy = nn_A1.evaluate(X_test_scaled, y_test, verbose=2)

# Display the model loss and accuracy results
print(f"Loss: {model_loss}, Accuracy: {model_accuracy}")
# -



StarcoderdataJupyterScriptsDedupFiltered