# Pomoćni sadržaj

# Korišćeni podaci
# 
# Skup podataka "Wine Data Set"
# - repozitorijum skupova podataka "UC Irvine Machine Learning Repository":
#   Dua, D. and Graff, C. (2019). UCI Machine Learning Repository 
#   [http://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
#   School of Information and Computer Science.
# - podaci o hemijskim analizama vina iz Italije
#   - izvorni vlasnik: Forina, M. et al, PARVUS - An Extendible Package for 
#     Data Exploration, Classification and Correlation. Institute of 
#     Pharmaceutical and Food Analysis and Technologies, Via Brigata Salerno, 
#     16147 Genoa, Italy.
#   - donator: Stefan Aeberhard, email: stefan '@' coral.cs.jcu.edu.au
#   - format podataka: CSV
#
# Internet strana:
# https://archive.ics.uci.edu/ml/datasets/Wine


# %% Biblioteke i inicijalizacija

import numpy as np
import pandas as pd

gpsv = np.random.default_rng(17)


# %% Klasa Perceptron

class Perceptron:
    def __init__(self, obim_ulaza, generator):
        self.W = generator.normal(0.0, 0.01, size=(1, obim_ulaza))
        self.b = generator.normal(0.0, 0.01)
    
    def formiranje_izlaza(self, ulaz):
        q = np.dot(self.W, ulaz) + self.b
        y = 1 if q >= 0 else 0
        return y
    
    def treniranje(self, ulazi, oznake, broj_epoha):
        for n in range(broj_epoha):
            for i in range(ulazi.shape[0]):
                ulaz = ulazi.iloc[i, :]
                izlaz = self.formiranje_izlaza(ulaz)
                e = oznake.iloc[i] - izlaz
                self.W = self.W + e * ulaz.values
                self.b = self.b + e
        return self.W, self.b

    def ispitivanje_performansi(self, ulazi, oznake):
        izlazi = ulazi.apply(self.formiranje_izlaza, axis=1)
        return oznake == izlazi


# %% Zadatak 1

podaci = pd.read_csv("wine.data", header=None, 
                     names=["klasa", "alkohol", "jabučna_kiselina",
                            "pepeo", "alkalnost_pepela", "magnezijum",
                            "ukupno_fenola", "flavanoidi",
                            "neflavanoidni_fenoli", "proantocijanini", 
                            "intenzitet_boje", "nijansa", "OD280_OD315",
                            "prolin"])

podaci = podaci[:130]
podaci["klasa"] = podaci["klasa"].values - 1

atributi_nezavisni = ["alkohol", "jabučna_kiselina", "pepeo", 
                      "alkalnost_pepela", "magnezijum", "ukupno_fenola", 
                      "flavanoidi"]
atribut_zavisni = "klasa"

podaci_obuka = podaci.sample(frac=0.8, random_state=gpsv.bit_generator)
podaci_obuka_ulazi = podaci_obuka[atributi_nezavisni]
podaci_obuka_oznake = podaci_obuka[atribut_zavisni]

perceptron = Perceptron(len(atributi_nezavisni), gpsv)
print("Vrednosti parametara pre obučavanja")
print("  W:", perceptron.W.round(4))
print("  b:", "{:.4f}".format(perceptron.b))

perceptron.treniranje(podaci_obuka_ulazi, podaci_obuka_oznake, 300)
print("Vrednosti parametara nakon obučavanja")
print("  W:", perceptron.W.round(2))
print("  b:", "{:.2f}".format(perceptron.b))

podaci_test = podaci.drop(index=podaci_obuka.index)
podaci_test_ulazi = podaci_test[atributi_nezavisni]
podaci_test_oznake = podaci_test[atribut_zavisni]

performanse = perceptron.ispitivanje_performansi(podaci_test_ulazi, 
                                                 podaci_test_oznake)
print("Performanse nad test podacima")
print("  poklapanje oznake i izlaza:")
print(" ", performanse.values)
print("  tačnost:", "{:.4f}".format(performanse.sum() / performanse.size))


# %% Zadatak 2

podaci_obuka_ulazi_norm = (podaci_obuka[atributi_nezavisni] - 
                           podaci_obuka[atributi_nezavisni].mean()) / (
                               podaci_obuka[atributi_nezavisni].std())

perceptron2 = Perceptron(len(atributi_nezavisni), gpsv)
print("Vrednosti parametara pre obučavanja (normalizacija)")
print("  W:", perceptron2.W.round(4))
print("  b:", "{:.4f}".format(perceptron2.b))

perceptron2.treniranje(podaci_obuka_ulazi_norm, podaci_obuka_oznake, 300)
print("Vrednosti parametara nakon obučavanja (normalizacija)")
print("  W:", perceptron2.W.round(2))
print("  b:", "{:.2f}".format(perceptron2.b))

podaci_test_ulazi_norm = (podaci_test[atributi_nezavisni] - 
                          podaci_test[atributi_nezavisni].mean()) / (
                              podaci_test[atributi_nezavisni].std())

performanse2 = perceptron2.ispitivanje_performansi(podaci_test_ulazi_norm, 
                                                  podaci_test_oznake)
print("Performanse nad test podacima (normalizacija)")
print("  poklapanje oznake i izlaza:")
print(" ", performanse2.values)
print("  tačnost:", "{:.4f}".format(performanse2.sum() / performanse2.size))


# %% Zadatak 3

# prilagoditi delove od Zadataka 1 i 2

