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

# + [markdown] id="view-in-github" colab_type="text"
# <a href="https://colab.research.google.com/github/JRKagumba/Capstone_2/blob/master/LSTM.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>

# + [markdown] id="2sIU-EMdl1kH"
# # 0 Import Libraries and Data

# + id="vxHKQlUJkIL8"
# import libraries 
import pandas as pd # Import Pandas for data manipulation using dataframes
import numpy as np # Import Numpy for data statistical analysis 
import matplotlib.pyplot as plt # Import matplotlib for data visualisation

import random
import seaborn as sns

import torch
import torch.nn as nn

import plotly.offline as py
from plotly.offline import init_notebook_mode, iplot
import plotly.express as px
import plotly.graph_objs as go
from plotly.subplots import make_subplots

# This relates to plotting datetime values with matplotlib:
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()

# + colab={"base_uri": "https://localhost:8080/"} id="7M6bvma6kZCN" outputId="4fb5743d-38c1-4a42-b8c6-544a107100e1"
from google.colab import drive
drive.mount('/content/gdrive')

realestate_df = pd.read_csv("/content/gdrive/MyDrive/ColabNotebooks/RealEstate/data_with_locations_and_ids.csv")
print(f"Length before droping duplicate ids = {len(realestate_df)}")
realestate_df =realestate_df.drop_duplicates(subset=['id'], keep='first')
print(f"Length after droping duplicate ids = {len(realestate_df)}")

# + id="xSoenyGInHRV" colab={"base_uri": "https://localhost:8080/", "height": 398} outputId="3c5653eb-0edd-448f-9451-7e817a4be557"
sample_df=realestate_df.sample(frac=0.95, replace=False, random_state=99)
sample_df["Price"] = pd.to_numeric(sample_df["Price"], downcast="float")
sample_df['Time_Posted'] = sample_df['Time_Posted'].values.astype('datetime64[ns]')
sample_df.head(3)

# + id="vv72mqTBzpGx" colab={"base_uri": "https://localhost:8080/"} outputId="b66b1973-dca0-4ce1-e3dd-09826891ccd1"
print(f"Length before removing outliers = {len(sample_df)}")

listings=sample_df['Listing_Type'].unique()
dataframe_list=[]

for value in listings:
    df = sample_df[sample_df.Listing_Type==value]
    q_low = df["Price"].quantile(0.05)
    q_hi  = df["Price"].quantile(0.95)
    df = df[(df["Price"] < q_hi) & (df["Price"] > q_low)]
    
    dataframe_list.append(df)
    
sample_df = pd.concat(dataframe_list, axis=0, ignore_index=True) 

print(f"Length after removing outliers = {len(sample_df)}")

# + id="8edzFR3lyEgW" colab={"base_uri": "https://localhost:8080/"} outputId="67e9897a-f8b5-4645-cf21-9bf0e9d86278"
listing_type_dict={}

listing_types=sample_df['Listing_Type'].unique()

for type in listing_types:
    listing_type_dict[type]=sample_df[sample_df['Listing_Type']==type]

print(listing_type_dict.keys())

# + [markdown] id="ZdbQs3lCl7hV"
# # 1 EDA

# + id="km7vVg55s4So" colab={"base_uri": "https://localhost:8080/", "height": 1000} outputId="39141460-3aca-4a35-a3ef-98d73d6461da"
fig = make_subplots(rows=len(listing_types),subplot_titles=[listing for listing in listing_types])

for index, listing in enumerate(listing_types):


    df=listing_type_dict[listing][['Time_Posted', 'Price']].groupby(pd.Grouper(key="Time_Posted", freq="1W")).agg({'Price': ['median', 'mean']}).dropna()
    df.columns=df.columns.map('_'.join)
    df=df.reset_index()

    data1=go.Scatter(x=df['Time_Posted'], y=df['Price_median'],
                        mode='lines',
                        name='median',
                        line=dict(color='#abd7eb'))
    data2=go.Scatter(x=df['Time_Posted'], y=df['Price_mean'],
                        mode='lines',
                        name='mean',
                        line=dict(color='#F47174'))

    fig.add_traces([data1,data2],rows=(index+1),cols=1)




fig.update_layout(title_text=f"Listing Price and Time", height=2000)
fig.show()

# + id="VJwJRDw01_Ct" colab={"base_uri": "https://localhost:8080/"} outputId="61c53bfc-790f-43bc-e6e8-25e60ac6c494"
print('Listing Types')
print(sample_df['Listing_Type'].unique())
print()
print('Sub Regions')
print(sample_df['Sub_Region'].value_counts().head(20).index)

# + id="PHVIWVJ93bst"
_specify= (sample_df['Listing_Type']=='Apartments-Condos') & (sample_df['Sub_Region']=='Toronto')

# + id="NzAFM6kzj68t" colab={"base_uri": "https://localhost:8080/", "height": 237} outputId="855b70db-efb0-4f35-9870-7d7ccc8128c2"
df=sample_df[_specify][['Time_Posted', 'Price']].groupby(pd.Grouper(key="Time_Posted", freq="1W")).agg({'Price': ['median', 'mean']}).dropna()
df.columns=df.columns.map('_'.join)
mean_df=df[['Price_mean']]
median_df=df[['Price_median']]

df.head()

# + id="ZbUPpMx6kqaN" colab={"base_uri": "https://localhost:8080/", "height": 228} outputId="9fe9e59b-a08d-44b0-c4f7-13069c612b8e"
df.plot(figsize=(24,4))

# + [markdown] id="9BYpaQXam4hQ"
# # 2 Setting Up for Modeling

# + id="UjXLnl7alM0S"
y=df['Price_median'].values

test_size=4
train_set=y[:-test_size]
test_set=y[-test_size:]

# + id="taIvpApRnfUc" colab={"base_uri": "https://localhost:8080/"} outputId="1c4aa0c7-ffb4-45af-c77c-c883c979113c"
from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler(feature_range=(-1,1))
scaler.fit(train_set.reshape(-1,1))
train_norm=scaler.transform(train_set.reshape(-1,1))
train_norm

# + id="JBERon4QniWr" colab={"base_uri": "https://localhost:8080/"} outputId="1bcb3fe4-29e2-42ab-f20b-951baa5462ab"
train_norm = torch.FloatTensor(train_norm).view(-1)
train_norm

# + id="6Uo9MvtHpLXl" colab={"base_uri": "https://localhost:8080/"} outputId="b312439b-8f34-4fc0-9b89-8b1edacd6793"
window_size=4

# Define function to create seq/label tuples
def input_data(_sequence,_windowsize):
    out = []
    L = len(_sequence)

    for i in range(L-_windowsize):
        window = _sequence[i:i+_windowsize]
        label = _sequence[i+_windowsize:i+_windowsize+1]
        out.append((window,label))
    return out

# Apply the input_data function to train_norm
train_data = input_data(train_norm,window_size)
len(train_data)  # this should equal len(original data)-len(test size)-len(window size)


# + [markdown] id="MD-mJdglrJLx"
# # 3 Define Model

# + id="6AFgEup0qN5-"
class LSTMnetwork(nn.Module):
    def __init__(self,input_size=1,hidden_size=100,output_size=1):
        super().__init__()
        self.hidden_size = hidden_size
        
        # Add an LSTM layer:
        self.lstm = nn.LSTM(input_size,hidden_size)
        
        # Add a fully-connected layer:
        self.linear = nn.Linear(hidden_size,output_size)
        
        # Initialize h0 and c0:
        self.hidden = (torch.zeros(1,1,self.hidden_size),
                       torch.zeros(1,1,self.hidden_size))

    def forward(self,seq):
        lstm_out, self.hidden = self.lstm(
            seq.view(len(seq),1,-1), self.hidden)
        pred = self.linear(lstm_out.view(len(seq),-1))
        return pred[-1]  # we only want the last value


# + id="suiTNqvXq4x9" colab={"base_uri": "https://localhost:8080/"} outputId="0ef74ad3-7366-48bd-e8e9-ca944fb6b810"
torch.manual_seed(101)
model = LSTMnetwork()

criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

model

# + id="ifiZXHOjroSC" colab={"base_uri": "https://localhost:8080/"} outputId="46c06c47-7998-4687-e03a-970da69ffae0"
epochs = 20000

import time
start_time = time.time()

for epoch in range(epochs):
    
    # extract the sequence & label from the training data
    for seq, y_train in train_data:
        
        # reset the parameters and hidden states
        optimizer.zero_grad()
        model.hidden = (torch.zeros(1,1,model.hidden_size),
                        torch.zeros(1,1,model.hidden_size))
        
        y_pred = model(seq)
        
        loss = criterion(y_pred, y_train)
        loss.backward()
        optimizer.step()
    
 
    if epoch%1000 == 1:
        
    # print training result
      print(f'Epoch: {epoch+1:2} Loss: {loss.item():10.8f}')
    
print(f'\nDuration: {time.time() - start_time:.0f} seconds')

# + [markdown] id="_XtbfypXskGU"
# # 4 Compare with Test Set

# + id="IUIKLki3sKBh" colab={"base_uri": "https://localhost:8080/"} outputId="11284ba1-926e-49f8-9725-0b3859ae7909"
future = 12

# Add the last window of training values to the list of predictions
preds = train_norm[-window_size:].tolist()

# Set the model to evaluation mode
model.eval()

for i in range(future):
    seq = torch.FloatTensor(preds[-window_size:])
    with torch.no_grad():
        model.hidden = (torch.zeros(1,1,model.hidden_size),
                        torch.zeros(1,1,model.hidden_size))
        preds.append(model(seq).item())


preds[window_size:] 


# + id="cj3Z9mgEs9O9" colab={"base_uri": "https://localhost:8080/"} outputId="a4d1f5c4-ff11-4a2c-d66e-45f4a982e07e"
true_predictions = scaler.inverse_transform(np.array(preds[window_size:]).reshape(-1, 1))
true_predictions

# + id="TjeeKSjAtJpk" colab={"base_uri": "https://localhost:8080/"} outputId="c2d3123b-818a-4ea8-d098-f72e2cf45614"
df['Price_median'][-12:]

# + id="-RmczAbOvvnT" colab={"base_uri": "https://localhost:8080/"} outputId="e3bf82ec-33db-42a8-bb3d-fe1fd19d4cef"
time_change = df.index[-1]-df.index[-2]
time_change

# + id="DI83F-4EtmC6" colab={"base_uri": "https://localhost:8080/"} outputId="0030b1b2-6bca-40b6-e32a-47ff53019231"
min_range=df['Price_mean'][-12:].index.min()
max_range=df['Price_mean'][-12:].index.max()

x = np.arange(min_range, max_range+time_change, dtype='datetime64[W]').astype('datetime64[D]')
x

# + id="vnsNIE2Etsg6" colab={"base_uri": "https://localhost:8080/", "height": 211} outputId="5622f75b-6fbb-46c1-f90c-b28fa1af14ac"
plt.figure(figsize=(24,4))
plt.title('Listing Price')
plt.ylabel('Price')
plt.grid(True)
plt.autoscale(axis='x',tight=True)
plt.plot(df['Price_median'])
plt.plot(x,true_predictions)
plt.show()

# + id="yL7FnAZYuwHg" colab={"base_uri": "https://localhost:8080/"} outputId="dabc58c0-3cfe-421a-9eb6-e622abf5d21a"
x.shape

# + [markdown] id="6ppazs0IQ99H"
# # 5 Forecast into unknown future

# + id="1gIMklKwvRo0" colab={"base_uri": "https://localhost:8080/"} outputId="a3ecdf47-9ccd-474d-a06b-a9d11d582c22"
epochs = 20000

# set model back to training mode
model.train()

# feature scale the entire dataset
y_norm = scaler.fit_transform(y.reshape(-1, 1))
y_norm = torch.FloatTensor(y_norm).view(-1)
all_data = input_data(y_norm,window_size)

import time
start_time = time.time()

for epoch in range(epochs):
    
    # train on the full set of sequences
    for seq, y_train in all_data:  
        
        # reset the parameters and hidden states
        optimizer.zero_grad()
        model.hidden = (torch.zeros(1,1,model.hidden_size),
                        torch.zeros(1,1,model.hidden_size))
        
        y_pred = model(seq)
        
        loss = criterion(y_pred, y_train)
        loss.backward()
        optimizer.step()

    if epoch%500 == 1:  
    # print training result
      print(f'Epoch: {epoch+1:2} Loss: {loss.item():10.8f}')
    
print(f'\nDuration: {time.time() - start_time:.0f} seconds')

# + id="HMXWKa16vTvz"
window_size = 12
future = 12
L = len(y)

preds = y_norm[-window_size:].tolist()

model.eval()
for i in range(future):  
    seq = torch.FloatTensor(preds[-window_size:])
    with torch.no_grad():
        # Reset the hidden parameters here!
        model.hidden = (torch.zeros(1,1,model.hidden_size),
                        torch.zeros(1,1,model.hidden_size))  
        preds.append(model(seq).item())

# Inverse-normalize the prediction set
true_predictions = scaler.inverse_transform(np.array(preds).reshape(-1, 1))

# + id="Y2ahuHPnSJlG" colab={"base_uri": "https://localhost:8080/"} outputId="93d7a0de-5af7-4c90-ed5f-54ec2a911d59"
true_predictions.shape

# + id="QJ2EDDWjPxOw" colab={"base_uri": "https://localhost:8080/"} outputId="2e5161e1-de85-4fe5-ff9d-21e55e6ad5d9"
min_range=df['Price_mean'][-window_size:].index.min()
max_range=df['Price_mean'][-window_size:].index.max()

time_change = df.index[-1]-df.index[-2]
time_change

# + id="0MZqqJe9R0vW"
future_min_range=max_range+time_change
future_max_range=max_range+(time_change*(window_size+1))

# + id="t4cV_xSoSYSN" colab={"base_uri": "https://localhost:8080/"} outputId="04ffde57-64f7-4a19-c831-7fbb3984210a"
x = np.arange(future_min_range, future_max_range, dtype='datetime64[W]').astype('datetime64[D]')
x.shape

# + id="0BzZ6aMbOpZg" colab={"base_uri": "https://localhost:8080/", "height": 211} outputId="cb008cdd-231a-45a1-b6c9-6a26d30dd60f"
# PLOT THE RESULT
# Set a data range for the predicted data.
# Remember that the stop date has to be later than the last predicted value.



plt.figure(figsize=(24,4))
plt.title('Listing Price')
plt.ylabel('Price')
plt.grid(True)
plt.autoscale(axis='x',tight=True)
plt.plot(df['Price_median'])
plt.plot(x,true_predictions[window_size:])
plt.show()

# + id="q0uM6XjWPlpy"


StarcoderdataJupyterScriptsDedupFiltered