# Univerzitet u Novom Sadu, Fakultet tehničkih nauka, Novi Sad, Srbija
# Studijski program OAS Informacioni inženjering
# Predmet Metode i tehnike nauke o podacima

# Pomoćni sadržaj

# Korišćeni podaci
#
# Skup podataka "Fremont Bridge Bicycle Counter"
# - portal otvorenih podataka Sijetla (SAD)
# - podaci o detektovanom broju prelazaka bicikala preko mosta Frimont 
#   u Sijetlu (SAD)
#   - vlasnik podataka: Jennifer.Manu@seattle.gov
#   - odeljenje koje je objavilo podatke: Seattle Department of Transportation
#   - datum kreiranja: 14. 3. 2013.
#   - datum najnovijeg ažuriranja: 13. 5. 2025.
#   - format podataka: CSV i drugi
#
# Internet strana:
# https://data.seattle.gov/Transportation/Fremont-Bridge-Bicycle-Counter/65db-xm6k/about_data


# %% Biblioteke

import pandas as pd
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Input
from keras.layers import Dense
from tensorflow.keras.preprocessing import timeseries_dataset_from_array


# %% Učitavanje i sređivanje podataka

bicikli = pd.read_csv("Fremont_Bridge_Bicycle_Counter_20250704.csv",
                      parse_dates=["Date"], date_format="mixed", 
                      dayfirst=False)

bicikli.rename(columns={
    "Date": 
        "datum_i_vreme",
    "Fremont Bridge Sidewalks, south of N 34th St Total": 
        "broj_ukupno", 
    "Fremont Bridge Sidewalks, south of N 34th St Cyclist West Sidewalk": 
        "broj_zapad",
    "Fremont Bridge Sidewalks, south of N 34th St Cyclist East Sidewalk": 
        "broj_istok"}, 
    inplace=True)

bicikli["datum_godina"] = bicikli["datum_i_vreme"].dt.year

DANI_U_SEDMICI = {0: "ponedeljak",
                  1: "utorak",
                  2: "sreda",
                  3: "četvrtak",
                  4: "petak",
                  5: "subota",
                  6: "nedelja"}

bicikli["datum_dan_u_sedmici"] = bicikli["datum_i_vreme"].dt.weekday.replace(
    DANI_U_SEDMICI)

bicikli["vreme_sati"] = bicikli["datum_i_vreme"].dt.hour

bicikli = bicikli.loc[:, ["datum_i_vreme", "datum_godina", 
                          "datum_dan_u_sedmici", "vreme_sati", 
                          "broj_ukupno", "broj_zapad", "broj_istok"]]

bicikli.sort_values(by=["datum_i_vreme"], inplace=True, ignore_index=True)

print("Skup podataka:")
print(bicikli)

print("Kolone:")
print(bicikli.dtypes)

print("Nedostajuće vrednosti:")
bicikli[bicikli.isna().any(axis=1)]


# %% Odabir podataka

bicikli_odabir = bicikli.loc[bicikli["vreme_sati"] == 12, :]

print("Nedostajuće vrednosti (za 12 sati):")
print(bicikli_odabir[bicikli_odabir.isna().any(axis=1)])

print("Dostupnost odabranih podataka po godinama:")
print(bicikli_odabir.groupby(["datum_godina"]).size())

bicikli_odabir_2016_2018 = bicikli_odabir.loc[
    (bicikli["datum_godina"] >= 2016) & (bicikli["datum_godina"] <= 2018), 
    ["broj_ukupno"]]

bicikli_odabir_2016_2018.reset_index(drop=True, inplace=True)

bicikli_odabir_2019 = bicikli_odabir.loc[
    (bicikli["datum_godina"] == 2019), ["broj_ukupno"]]

bicikli_odabir_2019.reset_index(drop=True, inplace=True)


# %% Pripremanje podataka za postupke obučavanja i validacije neuronske mreže

veličina_grupe = 32

period_unazad_dužina = 7

obučavanje_n = bicikli_odabir_2016_2018.shape[0]

podaci_obučavanje_ulaz = bicikli_odabir_2016_2018.iloc[
    0:(obučavanje_n - 1), 0].values
podaci_obučavanje_cilj = bicikli_odabir_2016_2018.iloc[
    period_unazad_dužina:, 0].values

podaci_obučavanje = timeseries_dataset_from_array(
    podaci_obučavanje_ulaz, podaci_obučavanje_cilj, 
    sequence_length=period_unazad_dužina, 
    sampling_rate=1, batch_size=veličina_grupe)

validacija_n = bicikli_odabir_2019.shape[0]

podaci_validacija_ulaz = bicikli_odabir_2019.iloc[
    0:(validacija_n - 1), 0].values
podaci_validacija_cilj = bicikli_odabir_2019.iloc[
    period_unazad_dužina:, 0].values

podaci_validacija = timeseries_dataset_from_array(
    podaci_validacija_ulaz, podaci_validacija_cilj, 
    sequence_length=period_unazad_dužina, 
    sampling_rate=1, batch_size=veličina_grupe)


# %% Formiranje, obučavanje i validacija neuronske mreže

broj_epoha = 200

rnm = Sequential()
rnm.add(Input(shape=(period_unazad_dužina, 1)))
rnm.add(LSTM(units=16))
rnm.add(Dense(1))
rnm.compile(loss="mean_squared_error", optimizer="adam")
rnm.summary()

rnm_rezultati = rnm.fit(podaci_obučavanje, epochs=broj_epoha, 
                        validation_data=podaci_validacija)


# %% Analiza performansi neuronske mreže

plt.figure(figsize=(8, 6))
plt.plot(range(1, broj_epoha + 1), 
         rnm_rezultati.history["loss"], 
         "o--", label="obučavanje")
plt.plot(range(1, broj_epoha + 1), 
         rnm_rezultati.history["val_loss"],
         "o--", label="validacija")
plt.xlim(0)
plt.ylim(0)
plt.title("Performanse neuronske mreže")
plt.xticks([i for i in range(1, broj_epoha + 1) if i % 10 == 0])
plt.xlabel("Epoha")
plt.ylabel("Srednja kvadratna greška")
plt.legend(title="Faza")

