Compare commits

..
6 Commits
Author SHA1 Message Date
hoo2 26534006c7 Release all HWs 2025-10-26 22:40:45 +02:00
hoo2 7f33867398 HW4: Scenario 2 source and report added 2025-10-26 22:23:01 +02:00
hoo2 613b21e059 HW4: Scenario1 source code and report added 2025-10-26 20:36:08 +02:00
hoo2 8ced0fd58d HW4: Directory structure preperation 2025-10-26 19:09:32 +02:00
hoo2 4f59ed0e07 HW3: Small changes on the report 2025-10-26 19:09:09 +02:00
hoo2 1ff2384a9e HW1: Small changes on the report 2025-10-26 19:08:38 +02:00
63 changed files with 13439 additions and 9 deletions
+3
View File
@@ -7,3 +7,6 @@
[submodule "Work 3/report/AUThReport"] [submodule "Work 3/report/AUThReport"]
path = Work 3/report/AUThReport path = Work 3/report/AUThReport
url = ssh://git@git.hoo2.net:222/hoo2/AUThReport.git url = ssh://git@git.hoo2.net:222/hoo2/AUThReport.git
[submodule "Work 4/report/AUThReport"]
path = Work 4/report/AUThReport
url = ssh://git@git.hoo2.net:222/hoo2/AUThReport.git
Binary file not shown.
+2
View File
@@ -3,4 +3,6 @@
*.log *.log
*.out *.out
*.synctex.gz *.synctex.gz
_minted*/*
Binary file not shown.
+4 -4
View File
@@ -146,14 +146,14 @@ G_c(s) = K_p + \frac{K_i}{s} = K_p \frac{s+c}{s}
Για τη σχεδίαση του ασαφούς ελεγκτή υλοποιήσαμε τις παρακάτω βασικές συναρτήσεις. Για τη σχεδίαση του ασαφούς ελεγκτή υλοποιήσαμε τις παρακάτω βασικές συναρτήσεις.
\begin{itemize} \begin{itemize}
\item \textit{mkFIS()}: Όπου δηλώσαμε το fuzzy controller καθώς και της συναρτήσεις συμμετοχής και τους κανόνες. \item \textit{mkFIS()}: Όπου δηλώσαμε το fuzzy controller καθώς και της συναρτήσεις συμμετοχής και τους κανόνες.
Ο ελεγκτής μας δέχεται 2 εισόδους, το σφάλμα και την πρώτη χρονική του παράγωγο ($e, \dot{e}$) και επιστρέφει την πρώτη παράγωγο του σήματος ελέγχου $\dot{u}$. Ο ελεγκτής μας δέχεται 2 εισόδους, το σφάλμα και την πρώτη χρονική του παράγωγο ($e, \dot{e}$) και επιστρέφει την διαφορά του σήματος ελέγχου $\Delta u$.
Οι συναρτήσεις συμμετοχής δηλώθηκαν με βάση το σχήμα \ref{fig:member_functions}. Οι συναρτήσεις συμμετοχής δηλώθηκαν με βάση το σχήμα \ref{fig:member_functions}.
\InsertFigure{!ht}{0.7}{fig:member_functions}{img/MemberFunctions.png}{Συναρτήσεις συμμετοχής.} \InsertFigure{!ht}{0.7}{fig:member_functions}{img/MemberFunctions.png}{Συναρτήσεις συμμετοχής.}
Η βάση κανόνων σχεδιάστηκε εμπειρικά. Η βάση κανόνων σχεδιάστηκε εμπειρικά.
Αν και δεν μπορούμε να αναγάγουμε τους εαυτούς μας σε ειδικούς, για την παρούσα εργασία δεν είχαμε άλλη επιλογή. Αν και δεν μπορούμε να αναγάγουμε τους εαυτούς μας σε ειδικούς, για την παρούσα εργασία δεν είχαμε άλλη επιλογή.
Η λογική που χρησιμοποιήσαμε βασίζεται στην παρατήριση πως, όταν το σφάλμα και η μεταβολή του σφάλματος έχουν αντίθετο πρόσημο, τότε το σύστημα τείνει προς ισορροπία. Η λογική που χρησιμοποιήσαμε βασίζεται στην παρατήριση πως, όταν το σφάλμα και η μεταβολή του σφάλματος έχουν αντίθετο πρόσημο, τότε το σύστημα τείνει προς ισορροπία.
Επομένως, δεν αλλάζουνε το σήμα ελέγχου $\dot{u}$. Επομένως, δεν αλλάζουνε το σήμα ελέγχου $\Delta u$.
Αυτό δημιουργεί μια διαγώνιο με τη λεκτική τιμή "ZR", όπως φαίνεται στον πίνακα \ref{tab:ruleTable}. Αυτό δημιουργεί μια διαγώνιο με τη λεκτική τιμή "ZR", όπως φαίνεται στον πίνακα \ref{tab:ruleTable}.
Επιπροσθέτως, όταν το σφάλμα αυξάνεται και είναι ήδη θετικό, ή μειώνεται και είναι ήδη αρνητικό, τότε εντείνουμε την έξοδο με θετικές και αρνητικές τιμές αντίστοιχα. Επιπροσθέτως, όταν το σφάλμα αυξάνεται και είναι ήδη θετικό, ή μειώνεται και είναι ήδη αρνητικό, τότε εντείνουμε την έξοδο με θετικές και αρνητικές τιμές αντίστοιχα.
\begin{table}[!ht] \begin{table}[!ht]
@@ -175,7 +175,7 @@ G_c(s) = K_p + \frac{K_i}{s} = K_p \frac{s+c}{s}
PL & NS & ZR & PS & PM & PL & PV & PV & PV & PV \\ % e = PL PL & NS & ZR & PS & PM & PL & PV & PV & PV & PV \\ % e = PL
PV & ZR & PS & PM & PL & PV & PV & PV & PV & PV % e = PV PV & ZR & PS & PM & PL & PV & PV & PV & PV & PV % e = PV
\end{tabular} \end{tabular}
\caption{Βάση κανόνων (9$\times$9) για $e$ και $\dot{e}$ με έξοδο $ \dot{u}$.} \caption{Βάση κανόνων (9$\times$9) για $e$ και $\dot{e}$ με έξοδο $\Delta u$.}
\label{tab:ruleTable} \label{tab:ruleTable}
\end{table} \end{table}
@@ -244,7 +244,7 @@ Step response:
\section {Συμπεράσματα} \section {Συμπεράσματα}
Στην εργασία συγκρίναμε έναν κλασικό PI με έναν ασαφή Fuzzy–PI για το δορυφορικό μοντέλο. Στην εργασία συγκρίναμε έναν κλασικό PI με έναν ασαφή Fuzzy–PI για το δορυφορικό μοντέλο.
Ο PI, με $c=1$ και βέλτιστο $K$, ικανοποίησε τις προδιαγραφές και έδωσε γρήγορη άνοδο, αλλά με υπερύψωση κοντά στο όριο (10\%). Ο PI, με $c=1$ και βέλτιστο $K$, ικανοποίησε τις προδιαγραφές και έδωσε γρήγορη άνοδο, αλλά με υπερύψωση κοντά στο όριο (10\%).
Ο Fuzzy–PI υλοποιήθηκε ως Mamdani με δύο εισόδους $(e,\dot e)$, έξοδο $\Delta u$, κανόνες 9$\times$9 και εξωτερική κλιμακοποίηση σε $[-1,1]$. Ο Fuzzy–PI υλοποιήθηκε ως Mamdani με δύο εισόδους $(e,\dot e)$, έξοδο $\Delta u$, κανόνες $9\times9$ και εξωτερική κλιμακοποίηση σε $[-1,1]$.
Ο συντονισμός των $K_{de},K_u$ έγινε με αναζήτηση και κριτήριο ITAE, καταλήγοντας σε πολύ μικρή υπερύψωση (1.2\%) και ήπια απόσβεση, με ελαφρώς αργότερο $T_r$/$T_s$. Ο συντονισμός των $K_{de},K_u$ έγινε με αναζήτηση και κριτήριο ITAE, καταλήγοντας σε πολύ μικρή υπερύψωση (1.2\%) και ήπια απόσβεση, με ελαφρώς αργότερο $T_r$/$T_s$.
Πρακτικά, ο PI αποδείχτηκε απλός και αποτελεσματικός για γρήγορη απόκριση, αλλά πιο «επιθετικός». Πρακτικά, ο PI αποδείχτηκε απλός και αποτελεσματικός για γρήγορη απόκριση, αλλά πιο «επιθετικός».
Binary file not shown.
+2
View File
@@ -3,4 +3,6 @@
*.log *.log
*.out *.out
*.synctex.gz *.synctex.gz
_minted*/*
Binary file not shown.
Binary file not shown.
+5 -5
View File
@@ -279,7 +279,7 @@
\subsection{Διαγνωστικά Grid Search} \subsection{Διαγνωστικά Grid Search}
\begin{figure}[!ht] \begin{figure}[!ht]
\centering \centering
\includegraphics[width=0.8\textwidth]{../source/figures_scn2/scn2_cv_heatmap.png} \includegraphics[width=0.85\textwidth]{../source/figures_scn2/scn2_cv_heatmap.png}
\caption{Heatmap μέσου σφάλματος CV ανά $(k\_{\text{feat}}, r_\alpha)$ — με επικάλυψη του \#κανόνων.} \caption{Heatmap μέσου σφάλματος CV ανά $(k\_{\text{feat}}, r_\alpha)$ — με επικάλυψη του \#κανόνων.}
\label{fig:scn2_heatmap} \label{fig:scn2_heatmap}
\end{figure} \end{figure}
@@ -305,27 +305,27 @@
Για το τελικό μοντέλο μετά την εκπαίδευση και αξιολόγηση έχουμε: Για το τελικό μοντέλο μετά την εκπαίδευση και αξιολόγηση έχουμε:
\begin{figure}[H] \begin{figure}[H]
\centering \centering
\includegraphics[width=0.65\textwidth]{../source/figures_scn2/scn2_final_learning_curves.png} \includegraphics[width=0.8\textwidth]{../source/figures_scn2/scn2_final_learning_curves.png}
\caption{Καμπύλες μάθησης του τελικού μοντέλου (train/validation).} \caption{Καμπύλες μάθησης του τελικού μοντέλου (train/validation).}
\end{figure} \end{figure}
\begin{figure}[H] \begin{figure}[H]
\centering \centering
\includegraphics[width=0.65\textwidth]{../source/figures_scn2/scn2_final_pred_vs_actual.png} \includegraphics[width=0.8\textwidth]{../source/figures_scn2/scn2_final_pred_vs_actual.png}
\caption{Σύγκριση \emph{Predicted vs Actual} στο test set.} \caption{Σύγκριση \emph{Predicted vs Actual} στο test set.}
\label{fig:scn2_pred_vs_actual} \label{fig:scn2_pred_vs_actual}
\end{figure} \end{figure}
\begin{figure}[H] \begin{figure}[H]
\centering \centering
\includegraphics[width=0.65\textwidth]{../source/figures_scn2/scn2_final_error_series.png} \includegraphics[width=0.8\textwidth]{../source/figures_scn2/scn2_final_error_series.png}
\caption{Residuals (σειρά σφάλματος) στο test set.} \caption{Residuals (σειρά σφάλματος) στο test set.}
\end{figure} \end{figure}
\subsection{Ενδεικτικές συναρτήσεις συμμετοχής (subset)} \subsection{Ενδεικτικές συναρτήσεις συμμετοχής (subset)}
\begin{figure}[H] \begin{figure}[H]
\centering \centering
\includegraphics[width=0.85\textwidth]{../source/figures_scn2/scn2_final_mfs_subset.png} \includegraphics[width=0.95\textwidth]{../source/figures_scn2/scn2_final_mfs_subset.png}
\caption{Ενδεικτικές MF για επιλεγμένες εισόδους πριν/μετά την εκπαίδευση.} \caption{Ενδεικτικές MF για επιλεγμένες εισόδους πριν/μετά την εκπαίδευση.}
\end{figure} \end{figure}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.
+8
View File
@@ -0,0 +1,8 @@
# LaTeX auxiliary files
*.aux
*.log
*.out
*.synctex.gz
_minted*/*
Binary file not shown.
+402
View File
@@ -0,0 +1,402 @@
%
% !TEX TS-program = xelatex
% !TEX encoding = UTF-8 Unicode
% !TEX spellcheck = el-GR
%
% Fuzzy Systems Assignment 4
%
% Requires compilation with pdfLaTeX or XeLaTeX
%
% authors:
% Χρήστος Χουτουρίδης ΑΕΜ 8997
% cchoutou@ece.auth.gr
%
\documentclass[a4paper, 11pt, mainlang=greek, english]{AUThReport/AUThReport}
\CurrentDate{\today}
% Greek report document setup suggestions
%---------------------------------
% \WorkGroup{Ομάδα Χ}
\AuthorName{Χρήστος Χουτουρίδης}
\AuthorAEM{8997}
\AuthorMail{cchoutou@ece.auth.gr}
%\CoAuthorName{Όνομα Επίθετο}
%\CoAuthorAEM{1234}
%\CoAuthorMail{xxx@ece.auth.gr}
\DocTitle{Εργασία 4}
\DocSubTitle{Επίλυση προβλήματος ταξινόμησης με χρήση μοντέλων TSK}
\Department{Τμήμα ΗΜΜΥ. Τομέας Ηλεκτρονικής}
\ClassName{Ασαφή Συστήματα (Υπολογιστική Νοημοσύνη)}
\InstructorName{Θεοχάρης Ιωάννης}
\InstructorMail{theochar@ece.auth.gr}
\CoInstructorName{Χαδουλός Χρήστος}
\CoInstructorMail{christgc@auth.gr}
% -------------------------------------------------------
% Packages
% -------------------------------------------------------
\usepackage{float}
\usepackage{minted}
\usepackage{xcolor}
\usepackage{amsmath, amssymb, amsfonts}
\usepackage{diagbox}
\usepackage{subcaption} % για υποεικόνες με ξεχωριστά captions
\setminted[cpp]{
fontsize=\small,
breaklines,
autogobble,
baselinestretch=1.1,
tabsize=2,
numbersep=8pt,
gobble=0
}
\newcommand{\repo}{https://git.hoo2.net/hoo2/FuzzySystems/src/branch/master/Work\%204}
\usepackage{hyphenat}
%\hyphenation{Sup-er-con-du-cti-vi-ty}
\begin{document}
% Request a title page or header
\InsertTitle
%\InsertTitle[img/background.png][0.8\textwidth][2cm]
% =====================================================================
\section{Εισαγωγή}
Η παρούσα εργασία εστιάζει στην επίλυση προβλημάτων \textbf{ταξινόμησης} μέσω ασαφών συστημάτων τύπου \textbf{TakagiSugenoKang (TSK)}.
Η ταξινόμηση αποτελεί μια από τις βασικότερες εφαρμογές της υπολογιστικής νοημοσύνης, καθώς συνδυάζει στοιχεία λογικής, στατιστικής και μηχανικής μάθησης για τη λήψη αποφάσεων με αβεβαιότητα.
Τα μοντέλα TSK προσφέρουν ένα ευέλικτο πλαίσιο, στο οποίο η γνώση αναπαρίσταται με τη μορφή κανόνων τύπου \emph{IFTHEN}, ενώ η εκπαίδευση των παραμέτρων μπορεί να γίνει με υβριδικούς αλγορίθμους (Least Squares + Gradient Descent) όπως ο \textsc{anfis}.
Η εργασία χωρίζεται σε δύο πειραματικά σενάρια:
\begin{itemize}
\item \textbf{Σενάριο~1}: Εφαρμογή σε ένα απλό, χαμηλής διαστασιμότητας dataset (Haberman), με στόχο τη σύγκριση των προσεγγίσεων \textit{class-independent} και \textit{class-dependent Subtractive Clustering}.
\item \textbf{Σενάριο~2}: Εφαρμογή σε πιο σύνθετο πρόβλημα ταξινόμησης με δεδομένα υψηλής διαστασιμότητας, όπου αξιολογούνται τεχνικές προ-επεξεργασίας και επιλογής χαρακτηριστικών.
\end{itemize}
Μέσω των δύο σεναρίων εξετάζεται η διαδικασία εκπαίδευσης, αξιολόγησης και βελτιστοποίησης ενός ασαφούς συστήματος, καθώς και ο τρόπος με τον οποίο η παραμετροποίηση επηρεάζει την απόδοση, την ερμηνευσιμότητα και την υπολογιστική πολυπλοκότητα.
\subsection{Παραδοτέα}
Τα παραδοτέα της εργασίας αποτελούνται από:
\begin{itemize}
\item Την παρούσα αναφορά.
\item Τον κατάλογο \textbf{source}, με τον κώδικα της \textsc{Matlab}.
\item Το \href{\repo}{σύνδεσμο με το αποθετήριο} που περιέχει τον κώδικα της \textsc{Matlab} καθώς και αυτόν της αναφοράς.
\end{itemize}
% =====================================================================
\section{Υλοποίηση}
Για την υλοποίηση ακολουθήθηκε μια κοινή ροή επεξεργασίας και ανάλυσης δεδομένων, με στόχο τη μέγιστη επαναχρησιμοποίηση κώδικα μεταξύ των δύο σεναρίων.
Συγκεκριμένα, δημιουργήθηκαν ανεξάρτητες συναρτήσεις για:
\begin{enumerate}
\item Τον διαχωρισμό των δεδομένων (\textit{split\_data}).
\item Την προ-επεξεργασία (\textit{preprocess\_data}).
\item Την αξιολόγηση των αποτελεσμάτων (\textit{evaluate\_classification}).
\item Και τη συστηματική εμφάνιση/αποθήκευση γραφημάτων (\textit{plot\_results1, plot\_results2}).
\end{enumerate}
Έτσι, η εκτέλεση κάθε σεναρίου πραγματοποιείται αυτόνομα μέσω των scripts \texttt{scenario1.m} και \texttt{scenario2.m}, τα οποία συντονίζουν τα παραπάνω στάδια.
Η δομή αυτή εξασφαλίζει καθαρότερο κώδικα, ευκολότερη συντήρηση και πλήρη αναπαραγωγιμότητα των αποτελεσμάτων.
\subsection{Διαχωρισμός δεδομένων — \textit{split\_data()}}
Η συνάρτηση \textit{split\_data()} αναλαμβάνει να διαχωρίσει το αρχικό dataset σε τρία υποσύνολα: εκπαίδευσης, ελέγχου (validation) και δοκιμής (test).
Η διαδικασία βασίζεται σε τυχαία δειγματοληψία με καθορισμένο seed, ώστε τα ίδια σύνολα να μπορούν να αναπαραχθούν σε επόμενες εκτελέσεις.
Ο διαχωρισμός είναι στρωματοποιημένος, ώστε η αναλογία των κλάσεων να παραμένει ίδια σε όλα τα υποσύνολα.
\subsection{Προ-επεξεργασία δεδομένων — \textit{preprocess\_data()}}
Η προ-επεξεργασία εφαρμόζεται για να βελτιωθεί η σταθερότητα της εκπαίδευσης και να εξισορροπηθούν οι τιμές των εισόδων.
Στο πλαίσιο της εργασίας επιλέχθηκε κανονικοποίηση τύπου \textbf{z-score}, δηλαδή:
\[
x_i' = \frac{x_i - \mu_i}{\sigma_i}
\]
όπου $\mu_i$ και $\sigma_i$ είναι ο μέσος και η τυπική απόκλιση κάθε χαρακτηριστικού.
Η συνάρτηση \textit{preprocess\_data()} εφαρμόζει αυτόματα την κανονικοποίηση στα train/validation/test σύνολα και επιστρέφει τα απαραίτητα στατιστικά για τυχόν επαναφορά στις αρχικές κλίμακες.
\subsection{Αξιολόγηση αποτελεσμάτων — \textit{evaluate\_classification()}}
Η συνάρτηση \textit{evaluate\_classification()} συγκρίνει τις προβλέψεις του μοντέλου με τις πραγματικές ετικέτες και υπολογίζει τις μετρικές αξιολόγησης (OA, PA, UA, $\kappa$).
Επιπλέον, παράγει και επιστρέφει τη μήτρα σύγχυσης.
Η υλοποίηση έγινε ώστε να υποστηρίζει οποιονδήποτε αριθμό κλάσεων, ενώ παρέχει και normalized εκδόσεις των μετρικών, διευκολύνοντας τη συγκριτική ανάλυση μεταξύ μοντέλων.
\subsection{Απεικόνιση αποτελεσμάτων}
Για τη γραφική παρουσίαση των αποτελεσμάτων δημιουργήθηκαν οι συναρτήσεις \textit{plot\_results1()} και \textit{plot\_results2()}, οι οποίες παράγουν και αποθηκεύουν αυτόματα όλα τα ζητούμενα γραφήματα κάθε σεναρίου.
Κάθε γράφημα αποθηκεύεται σε υποκατάλογο (\texttt{figures\_scn1}, \texttt{figures\_scn2}) με συνεπή ονοματολογία, ώστε να διευκολύνεται η ενσωμάτωσή τους στην αναφορά.
Η σχεδίαση περιλαμβάνει μήτρες σύγχυσης, καμπύλες εκπαίδευσης, συναρτήσεις συμμετοχής πριν και μετά την εκπαίδευση, καθώς και συγκεντρωτικά διαγράμματα OA–$\kappa$ και RulesAccuracy.
Το επόμενο τμήμα παρουσιάζει το πρώτο σενάριο και τα αποτελέσματά του, εφαρμόζοντας τη μεθοδολογία που περιγράφηκε παραπάνω.
\section{Σενάριο 1 — Εφαρμογή σε απλό Dataset}
Το πρώτο σενάριο αφορά την επίλυση ενός προβλήματος \textbf{δυαδικής ταξινόμησης} χρησιμοποιώντας μοντέλα TSK με σταθερές (singleton) εξόδους.
Ως dataset χρησιμοποιήθηκε το \textit{Habermans Survival Dataset}, το οποίο περιλαμβάνει 306 δείγματα με τρεις αριθμητικές εισόδους (ηλικία, έτος εγχείρησης, αριθμός λεμφαδένων) και μία δυαδική ετικέτα που δηλώνει αν ο ασθενής επέζησε για τουλάχιστον πέντε έτη μετά την εγχείρηση.
Ο στόχος είναι η εκπαίδευση και αξιολόγηση μοντέλων TSK που προκύπτουν μέσω \textbf{Subtractive Clustering (SC)} τόσο στην \textit{class-independent} όσο και στην \textit{class-dependent} παραλλαγή, καθώς και η διερεύνηση της επίδρασης του παραμέτρου ακτίνας $r_a$ στην πολυπλοκότητα και την απόδοση του συστήματος.
\subsection{Πειραματική διαδικασία}
Το σύνολο δεδομένων χωρίστηκε στρωματοποιημένα σε τρία υποσύνολα (60 \% train, 20 \% validation, 20 \% test).
Η κανονικοποίηση των εισόδων έγινε με \textbf{z-score}, ενώ οι ετικέτες παρέμειναν ακέραιες.
Για κάθε mode (class-independent και class-dependent) δοκιμάστηκαν δύο τιμές ακτίνας, $r_a{=}\{0.20,0.80\}$, ώστε να προκύψουν τέσσερα μοντέλα συνολικά.
Η εκπαίδευση πραγματοποιήθηκε με \textbf{anfis} για 100 εποχές και με validation έλεγχο για αποφυγή υπερεκπαίδευσης.
Οι μετρικές αξιολόγησης που χρησιμοποιήθηκαν ήταν:
\begin{itemize}
\item \textbf{Overall Accuracy (OA)},
\item \textbf{Producers Accuracy (PA)} και \textbf{Users Accuracy (UA)} ανά κλάση,
\item και ο \textbf{συντελεστής συμφωνίας $\kappa$ του Cohen}.
\end{itemize}
\subsection{Αποτελέσματα}
\paragraph{Μήτρες σύγχυσης.}
Το σχήμα~\ref{fig:conf_mats} παρουσιάζει τις μήτρες σύγχυσης και για τα τέσσερα μοντέλα.
Και στις δύο προσεγγίσεις, η απόδοση για την κλάση 1 είναι σταθερά υψηλότερη, γεγονός που σχετίζεται με την ανισορροπία του dataset (\textasciitilde 73 \% δείγματα κλάσης 1).
Η αύξηση της ακτίνας μειώνει τον αριθμό κανόνων και οδηγεί σε απλούστερα μοντέλα χωρίς σημαντική απώλεια ακρίβειας.
\begin{figure}[H]
\centering
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/cm_run01_class-independent_r0.20_rules32}
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/cm_run02_class-independent_r0.80_rules3}\\[4pt]
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/cm_run03_class-dependent_r0.20_rules51}
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/cm_run04_class-dependent_r0.80_rules4}
\caption{Μήτρες σύγχυσης για όλα τα μοντέλα (\textit{class-independent} και \textit{class-dependent}, $r_a{=}0.20,0.80$).}
\label{fig:conf_mats}
\end{figure}
\paragraph{Μετρικές PA/UA.}
Το σχήμα~\ref{fig:pa_ua_all} απεικονίζει την ακρίβεια παραγωγού (PA) και χρήστη (UA) ανά κλάση για κάθε μοντέλο.
Η ανισορροπία των δεδομένων οδηγεί σε χαμηλότερες τιμές PA/UA για τη μειοψηφούσα κλάση 2, ωστόσο η συνολική τάση παραμένει σταθερή μεταξύ των modes.
\begin{figure}[H]
\centering
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/pa_ua_run01_class-independent_r0.20_rules32}
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/pa_ua_run02_class-independent_r0.80_rules3}\\[4pt]
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/pa_ua_run03_class-dependent_r0.20_rules51}
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/pa_ua_run04_class-dependent_r0.80_rules4}
\caption{PA (recall) και UA (precision) ανά κλάση για όλα τα μοντέλα.}
\label{fig:pa_ua_all}
\end{figure}
\paragraph{Καμπύλες εκπαίδευσης.}
Οι καμπύλες εκπαίδευσης του σχήματος~\ref{fig:learning_curves_all} δείχνουν τη σύγκλιση του ANFIS για κάθε περίπτωση.
Για μικρό $r_a$, το training error μηδενίζεται γρήγορα (υπερεκπαίδευση), ενώ για μεγάλο $r_a$ η εκπαίδευση είναι πιο ομαλή και το validation error σταθεροποιείται χαμηλότερα, δείχνοντας καλύτερη γενίκευση.
\begin{figure}[H]
\centering
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/learning_run01_class-independent_r0.20_rules32}
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/learning_run02_class-independent_r0.80_rules3}\\[4pt]
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/learning_run03_class-dependent_r0.20_rules51}
\includegraphics[width=0.47\textwidth]{../source/figures_scn1/learning_run04_class-dependent_r0.80_rules4}
\caption{Καμπύλες εκπαίδευσης (training / validation error vs epoch) για όλα τα μοντέλα.}
\label{fig:learning_curves_all}
\end{figure}
\paragraph{Συναρτήσεις συμμετοχής.}
Τα σχήματα~\ref{fig:mfs_indep} και \ref{fig:mfs_dep} απεικονίζει τις MFs πριν και μετά την εκπαίδευση για όλα τα μοντέλα.
Για μικρό $r_a$, παρατηρείται υπερβολική επικάλυψη και πλήθος κανόνων· για μεγάλο $r_a$ λιγότερες MFs και πιο ομαλές μεταβάσεις.
Η μεταβολή των MFs επιβεβαιώνει τη σωστή προσαρμογή των παραμέτρων στο σύνολο εκπαίδευσης.
\begin{figure}[H]
\centering
\includegraphics[width=0.85\textwidth]{../source/figures_scn1/mfs_run01_class-independent_r0.20_rules32}\\[4pt]
\includegraphics[width=0.85\textwidth]{../source/figures_scn1/mfs_run02_class-independent_r0.80_rules3}
\caption{Συναρτήσεις συμμετοχής (before/after) για τα class-independent μοντέλα .}
\label{fig:mfs_indep}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=0.85\textwidth]{../source/figures_scn1/mfs_run03_class-dependent_r0.20_rules51}\\[4pt]
\includegraphics[width=0.85\textwidth]{../source/figures_scn1/mfs_run04_class-dependent_r0.80_rules4}
\caption{Συναρτήσεις συμμετοχής (before/after) για τα class-dependent μοντέλα.}
\label{fig:mfs_dep}
\end{figure}
\paragraph{Συνολικές μετρικές και συσχετίσεις.}
Το σχήμα~\ref{fig:summary_metrics} παρουσιάζει την OA και $\kappa$ για κάθε μοντέλο, ενώ το σχήμα~\ref{fig:rules_accuracy} δείχνει τη σχέση αριθμού κανόνων -- ακρίβειας.
Παρατηρείται ότι η μέγιστη OA ($\approx73\%$) και ο υψηλότερος $\kappa$ προκύπτουν στα μοντέλα με $r_a{=}0.80$ (3–4 κανόνες), επιβεβαιώνοντας ότι η απλούστευση δεν μειώνει την απόδοση.
\begin{figure}[H]
\centering
\includegraphics[width=0.48\textwidth]{../source/figures_scn1/overall_accuracy_across_models}
\includegraphics[width=0.48\textwidth]{../source/figures_scn1/kappa_across_models}
\caption{Συνολική OA και συντελεστής $\kappa$ για όλα τα μοντέλα.}
\label{fig:summary_metrics}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=0.65\textwidth]{../source/figures_scn1/rules_vs_accuracy}
\caption{Σχέση αριθμού κανόνων και Overall Accuracy.}
\label{fig:rules_accuracy}
\end{figure}
\subsection{Συμπεράσματα}
Συνοψίζοντας:
\begin{itemize}
\item Οι TSK μοντελοποιήσεις μέσω SC παρείχαν σταθερή ταξινόμηση ακόμη και σε ανισόρροπα δεδομένα.
\item Η αύξηση του αριθμού κανόνων δεν βελτίωσε σημαντικά την απόδοση αλλά μείωσε την ερμηνευσιμότητα.
\item Η class-dependent εκδοχή δεν υπερείχε σημαντικά, υποδεικνύοντας μικρή διακριτότητα των κλάσεων.
\item Οι καμπύλες εκμάθησης και οι MFs δείχνουν ομαλή εκπαίδευση χωρίς αστάθειες.
\item Το \textbf{class-independent μοντέλο με $r_a{=}0.80$} παρουσιάζει την καλύτερη ισορροπία μεταξύ ακρίβειας, απλότητας και γενίκευσης.
\end{itemize}
% =====================================================================
\section{Σενάριο 2 — Dataset με υψηλή διαστασιμότητα (Epileptic Seizure Recognition)}
\label{sec:scenario2}
\subsection{Περιγραφή και ζητούμενο}
Το δεύτερο σενάριο στοχεύει στην ταξινόμηση εγκεφαλικών σημάτων \textit{EEG} σε πέντε κατηγορίες, στο πλαίσιο του προβλήματος \emph{Epileptic Seizure Recognition}.
Σε αντίθεση με το απλούστερο πρόβλημα του Σενάριου~1, εδώ οι διαστάσεις των δεδομένων είναι υψηλές και οι κλάσεις πολυπληθείς, καθιστώντας το έργο αξιολόγησης σημαντικά πιο απαιτητικό.
Ο στόχος είναι η ανάπτυξη ενός TSK–τύπου μοντέλου που συνδυάζει:
\begin{itemize}
\item επιλογή χαρακτηριστικών με \textbf{ReliefF},
\item αρχικοποίηση κανόνων μέσω \textbf{Subtractive Clustering (SC)},
\item και εκπαίδευση με \textbf{υβριδική μέθοδο} (\emph{gradient descent} + \emph{least squares}).
\end{itemize}
Η διαδικασία επαναλαμβάνεται για διάφορους συνδυασμούς ακτίνας συσσωμάτωσης $r_a$ και αριθμού χαρακτηριστικών που κρατούνται μετά το ReliefF, με στόχο τον εντοπισμό του συνδυασμού που προσφέρει τον βέλτιστο συμβιβασμό μεταξύ ακρίβειας και πολυπλοκότητας (\#Rules).
\subsection{Προσέγγιση και μεθοδολογία}
Για την επιλογή των υπερπαραμέτρων χρησιμοποιήθηκε \textbf{kfold crossvalidation}, ενώ η συνολική διαδικασία αυτοματοποιήθηκε πλήρως μέσα από το script \texttt{scenario2.m}.
Η ροή έχει ως εξής:
\begin{enumerate}
\item Διαβάζονται τα δεδομένα από το αρχείο \texttt{epileptic\_seizure\_data.csv} και κατανέμονται σε train-validation-test σε ποσοστό $60$$20$$20$.
\item Για κάθε συνδυασμό τιμών \texttt{feature\_grid} και \texttt{radii\_grid}, εκτελείται η διαδικασία k-fold CV.
Σε κάθε fold εφαρμόζεται το ReliefF ώστε να επιλεγούν τα πιο σημαντικά χαρακτηριστικά, και στη συνέχεια πραγματοποιείται Subtractive Clustering ανά κλάση (classdependent).
\item Κατασκευάζεται το αρχικό FIS με μία Gaussian MF ανά cluster και constant εξόδους (ένας MF ανά κανόνα).
\item Η εκπαίδευση γίνεται όλες τις εποχές μέσω \texttt{anfis()}, με validation set για έλεγχο γενίκευσης.
\item Μετά από κάθε fold υπολογίζεται ο Cohen’s $\kappa$ και ο αριθμός κανόνων, ώστε να εξαχθεί ο μέσος όρος ανά συνδυασμό παραμέτρων.
\end{enumerate}
\paragraph{Περιορισμοί εκτέλεσης.}
Δυστυχώς, μέχρι της παρούσης, δεν καταφέραμε να τρέξουμε το σενάριο για το μέγιστο αριθμό εποχών ($100$) και με το πλήρες grid σε κανέναν προσωπικό μας υπολογιστή.
Παρόλα αυτά, παραθέτουμε τα αποτελέσματα που λάβαμε από ένα μικρότερο πείραμα όπου τρέξαμε για:
\begin{verbatim}
cfg.feature_grid = [5 8]; % instead of [5 8 11 15]
cfg.radii_grid = [0.5 0.75]; % instead of [0.25 0.50 0.75 1.00]
cfg.kfold = 3; % instead of 5
cfg.maxEpochs = 20; % instead of 100
\end{verbatim}
Από το grid–search προέκυψε ως \textbf{βέλτιστο μοντέλο} το:
\[
\text{features}=5, \quad r_a=0.50, \quad \text{rules}=6, \quad \kappa=0.23
\]
που -- ας υποθέσουμε ότι -- προσφέρει "ικανοποιητική" ισορροπία μεταξύ ακρίβειας και απλότητας.
\subsection{Αποτελέσματα πειράματος}
\paragraph{Αναζήτηση υπερπαραμέτρων (Grid Search).}
Στο σχήμα~\ref{fig:scn2-grid} φαίνονται τα αποτελέσματα του grid–search.
Η μέση τιμή του συντελεστή $\kappa$ παραμένει κοντά στο $0.22$$0.23$ για όλους τους συνδυασμούς, δείχνοντας ότι το μοντέλο είναι σχετικά σταθερό.
Ο αριθμός κανόνων μειώνεται αισθητά με αύξηση του $r_a$, όπως αναμενόταν.
\begin{figure}[H]\centering
\includegraphics[width=.49\textwidth]{../source/figures_scn2/cv_kappa_heatmap.png}
\includegraphics[width=.49\textwidth]{../source/figures_scn2/cv_rules_heatmap.png}
\caption{Grid search: μέση τιμή του Cohen’s $\kappa$ (αριστερά)
και μέσος αριθμός κανόνων (δεξιά) για κάθε συνδυασμό παραμέτρων.}
\label{fig:scn2-grid}
\end{figure}
\paragraph{Απόδοση βέλτιστου μοντέλου.}
Η μήτρα σύγχυσης του βέλτιστου μοντέλου φαίνεται στο σχήμα~\ref{fig:scn2-cm}.
Παρατηρείται ότι οι κλάσεις 3 και 4 αναγνωρίζονται με σχετικά υψηλή ακρίβεια, ενώ η Κλάση~1 συγκεντρώνει τις περισσότερες λανθασμένες προβλέψεις.
Η συνολική ακρίβεια είναι μέτρια, αλλά ικανοποιητική για το συγκεκριμένο dataset.
\begin{figure}[H]\centering
\includegraphics[width=.7\textwidth]{../source/figures_scn2/cm_best_model.png}
\caption{Μήτρα σύγχυσης για το βέλτιστο μοντέλο (features$=5$, $r_a=0.50$, rules$=6$).}
\label{fig:scn2-cm}
\end{figure}
\paragraph{Καμπύλη εκμάθησης.}
Η καμπύλη εκμάθησης (σχήμα~\ref{fig:scn2-learning}) παρουσιάζει σταδιακή μείωση του σφάλματος σε train και validation set, χωρίς σημαντική απόκλιση, γεγονός που δείχνει ότι το μοντέλο γενικεύει καλά και δεν υπερ-προσαρμόζεται.
\begin{figure}[H]\centering
\includegraphics[width=.65\textwidth]{../source/figures_scn2/learning_best_model.png}
\caption{Καμπύλες εκμάθησης (training \& validation error) για το βέλτιστο μοντέλο.}
\label{fig:scn2-learning}
\end{figure}
\paragraph{Συναρτήσεις συμμετοχής.}
Στο σχήμα~\ref{fig:scn2-mfs} απεικονίζονται οι συναρτήσεις συμμετοχής για τα πέντε πιο σημαντικά χαρακτηριστικά, πριν και μετά την εκπαίδευση.
Παρατηρείται ελαφρά προσαρμογή στα πλάτη και στις θέσεις των Gaussian MF, χωρίς παραμόρφωση — κάτι που δείχνει καλή σταθερότητα του μοντέλου.
\begin{figure}[H]\centering
\includegraphics[width=\textwidth]{../source/figures_scn2/mfs_best_model.png}
\caption{MFs πριν και μετά την εκπαίδευση (βέλτιστο μοντέλο, top–5 χαρακτηριστικά).}
\label{fig:scn2-mfs}
\end{figure}
\paragraph{Ανάλυση ανά κλάση.}
Οι μετρικές ακρίβειας ανά κλάση (σχήμα~\ref{fig:scn2-pa-ua}) δείχνουν ικανοποιητική απόδοση για τις Κλάσεις~1 και~3, ενώ οι υπόλοιπες παρουσιάζουν χαμηλότερες τιμές PA και UA.
Αυτό είναι αναμενόμενο λόγω ανισορροπίας δείγματος και επικαλύψεων στα χαρακτηριστικά.
\begin{figure}[H]\centering
\includegraphics[width=.8\textwidth]{../source/figures_scn2/pa_ua_best_model.png}
\caption{Producers (PA) και Users (UA) Accuracy ανά κλάση στο test–set.}
\label{fig:scn2-pa-ua}
\end{figure}
\paragraph{Απόδοση στο test set.}
Η σύγκριση πραγματικών και προβλεπόμενων ετικετών (σχήμα~\ref{fig:scn2-truth}) δείχνει ότι οι περισσότερες προβλέψεις ακολουθούν τη σωστή κλάση, αν και παρατηρείται «θόρυβος» στις μεταβάσεις — ένδειξη περιορισμένης διακριτότητας των clusters.
\begin{figure}[H]\centering
\includegraphics[width=.9\textwidth]{../source/figures_scn2/pred_vs_truth_best_model.png}
\caption{Truth vs Prediction στο testset (βέλτιστο μοντέλο).}
\label{fig:scn2-truth}
\end{figure}
\paragraph{Βάρη ReliefF.}
Τα πέντε επιλεγμένα χαρακτηριστικά είχαν πολύ κοντινά βάρη (σχήμα~\ref{fig:scn2-relief}), γεγονός που δείχνει ότι η πληροφορία κατανέμεται σχετικά ομοιόμορφα -- δεν υπάρχει δηλαδή ένα «κυρίαρχο» χαρακτηριστικό.
\begin{figure}[H]\centering
\includegraphics[width=.65\textwidth]{../source/figures_scn2/relieff_weights_selected.png}
\caption{Βάρη των επιλεγμένων χαρακτηριστικών από το ReliefF (top5).}
\label{fig:scn2-relief}
\end{figure}
\subsection{Συμπεράσματα}
Το μειωμένο πείραμα επιβεβαιώνει τη λειτουργικότητα της ροής και των συναρτήσεων.
Παρά τον περιορισμένο αριθμό εποχών, το σύστημα κατόρθωσε να επιτύχει σταθερό Kappa γύρω στο $0.23$, με μόλις $6$ κανόνες και πέντε χαρακτηριστικά.
Η συμπεριφορά των μετρικών και των MFs δείχνει σωστή προσαρμογή και καλή γενίκευση, ενώ η μείωση του αριθμού κανόνων με αύξηση της ακτίνας επιβεβαιώνει τη θεωρητική αναμενόμενη συμπεριφορά του Subtractive Clustering.
Σε ένα πλήρες πείραμα (με $100$+ εποχές και εκτεταμένο grid), αναμένεται περαιτέρω βελτίωση τόσο στην τιμή του $\kappa$ όσο και στη σταθερότητα των καμπυλών εκμάθησης.
% =====================================================================
\section{Επίλογος}
Στην παρούσα εργασία υλοποιήσαμε μια ολοκληρωμένη ροή για την ανάπτυξη και αξιολόγηση TSK–fuzzy μοντέλων ταξινόμησης με χρήση \textsc{ANFIS}.
Η μεθοδολογία κάλυψε όλα τα στάδια -- από τον διαχωρισμό και την προεπεξεργασία των δεδομένων, μέχρι την επιλογή χαρακτηριστικών, την εκπαίδευση και τη συγκριτική ανάλυση των αποτελεσμάτων.
Στο Σενάριο~1, επιβεβαιώθηκε η σημασία της ακτίνας συσσωμάτωσης και της στρατηγικής αρχικοποίησης (classdependent ή independent) ως προς την ισορροπία μεταξύ πολυπλοκότητας και ακρίβειας.
Τα αποτελέσματα ήταν σταθερά, με συνεπή συμπεριφορά των MFs και των μετρικών.
Το πιο απαιτητικό Σενάριο~2, όπου συνδυάστηκε επιλογή χαρακτηριστικών με ReliefF και Sub. Clustering, δυστοιχώς δεν καταφέραμε να το τρέξουμε όπως θέλαμε.
Παρόλα αυτά παρατηρήθηκε καλή γενίκευση ακόμη και με περιορισμένο grid και λίγες εποχές.
Παρά τους χρονικούς περιορισμούς, η συνολική συμπεριφορά του συστήματος ήταν αξιόπιστη και αναδεικνύει τη δυναμική των TSK–fuzzy μοντέλων για ταξινόμηση υψηλής διάστασης.
Η προσέγγιση αυτή προσφέρει μια σταθερή και επεκτάσιμη βάση για μελλοντική έρευνα σε μεγαλύτερης κλίμακας δεδομένα.
\end{document}
+3
View File
@@ -0,0 +1,3 @@
# Matlab auxiliary files
*.asv
File diff suppressed because it is too large Load Diff
+306
View File
@@ -0,0 +1,306 @@
30,64,1,1
30,62,3,1
30,65,0,1
31,59,2,1
31,65,4,1
33,58,10,1
33,60,0,1
34,59,0,2
34,66,9,2
34,58,30,1
34,60,1,1
34,61,10,1
34,67,7,1
34,60,0,1
35,64,13,1
35,63,0,1
36,60,1,1
36,69,0,1
37,60,0,1
37,63,0,1
37,58,0,1
37,59,6,1
37,60,15,1
37,63,0,1
38,69,21,2
38,59,2,1
38,60,0,1
38,60,0,1
38,62,3,1
38,64,1,1
38,66,0,1
38,66,11,1
38,60,1,1
38,67,5,1
39,66,0,2
39,63,0,1
39,67,0,1
39,58,0,1
39,59,2,1
39,63,4,1
40,58,2,1
40,58,0,1
40,65,0,1
41,60,23,2
41,64,0,2
41,67,0,2
41,58,0,1
41,59,8,1
41,59,0,1
41,64,0,1
41,69,8,1
41,65,0,1
41,65,0,1
42,69,1,2
42,59,0,2
42,58,0,1
42,60,1,1
42,59,2,1
42,61,4,1
42,62,20,1
42,65,0,1
42,63,1,1
43,58,52,2
43,59,2,2
43,64,0,2
43,64,0,2
43,63,14,1
43,64,2,1
43,64,3,1
43,60,0,1
43,63,2,1
43,65,0,1
43,66,4,1
44,64,6,2
44,58,9,2
44,63,19,2
44,61,0,1
44,63,1,1
44,61,0,1
44,67,16,1
45,65,6,2
45,66,0,2
45,67,1,2
45,60,0,1
45,67,0,1
45,59,14,1
45,64,0,1
45,68,0,1
45,67,1,1
46,58,2,2
46,69,3,2
46,62,5,2
46,65,20,2
46,62,0,1
46,58,3,1
46,63,0,1
47,63,23,2
47,62,0,2
47,65,0,2
47,61,0,1
47,63,6,1
47,66,0,1
47,67,0,1
47,58,3,1
47,60,4,1
47,68,4,1
47,66,12,1
48,58,11,2
48,58,11,2
48,67,7,2
48,61,8,1
48,62,2,1
48,64,0,1
48,66,0,1
49,63,0,2
49,64,10,2
49,61,1,1
49,62,0,1
49,66,0,1
49,60,1,1
49,62,1,1
49,63,3,1
49,61,0,1
49,67,1,1
50,63,13,2
50,64,0,2
50,59,0,1
50,61,6,1
50,61,0,1
50,63,1,1
50,58,1,1
50,59,2,1
50,61,0,1
50,64,0,1
50,65,4,1
50,66,1,1
51,59,13,2
51,59,3,2
51,64,7,1
51,59,1,1
51,65,0,1
51,66,1,1
52,69,3,2
52,59,2,2
52,62,3,2
52,66,4,2
52,61,0,1
52,63,4,1
52,69,0,1
52,60,4,1
52,60,5,1
52,62,0,1
52,62,1,1
52,64,0,1
52,65,0,1
52,68,0,1
53,58,4,2
53,65,1,2
53,59,3,2
53,60,9,2
53,63,24,2
53,65,12,2
53,58,1,1
53,60,1,1
53,60,2,1
53,61,1,1
53,63,0,1
54,60,11,2
54,65,23,2
54,65,5,2
54,68,7,2
54,59,7,1
54,60,3,1
54,66,0,1
54,67,46,1
54,62,0,1
54,69,7,1
54,63,19,1
54,58,1,1
54,62,0,1
55,63,6,2
55,68,15,2
55,58,1,1
55,58,0,1
55,58,1,1
55,66,18,1
55,66,0,1
55,69,3,1
55,69,22,1
55,67,1,1
56,65,9,2
56,66,3,2
56,60,0,1
56,66,2,1
56,66,1,1
56,67,0,1
56,60,0,1
57,61,5,2
57,62,14,2
57,64,1,2
57,64,9,1
57,69,0,1
57,61,0,1
57,62,0,1
57,63,0,1
57,64,0,1
57,64,0,1
57,67,0,1
58,59,0,1
58,60,3,1
58,61,1,1
58,67,0,1
58,58,0,1
58,58,3,1
58,61,2,1
59,62,35,2
59,60,0,1
59,63,0,1
59,64,1,1
59,64,4,1
59,64,0,1
59,64,7,1
59,67,3,1
60,59,17,2
60,65,0,2
60,61,1,1
60,67,2,1
60,61,25,1
60,64,0,1
61,62,5,2
61,65,0,2
61,68,1,2
61,59,0,1
61,59,0,1
61,64,0,1
61,65,8,1
61,68,0,1
61,59,0,1
62,59,13,2
62,58,0,2
62,65,19,2
62,62,6,1
62,66,0,1
62,66,0,1
62,58,0,1
63,60,1,2
63,61,0,1
63,62,0,1
63,63,0,1
63,63,0,1
63,66,0,1
63,61,9,1
63,61,28,1
64,58,0,1
64,65,22,1
64,66,0,1
64,61,0,1
64,68,0,1
65,58,0,2
65,61,2,2
65,62,22,2
65,66,15,2
65,58,0,1
65,64,0,1
65,67,0,1
65,59,2,1
65,64,0,1
65,67,1,1
66,58,0,2
66,61,13,2
66,58,0,1
66,58,1,1
66,68,0,1
67,64,8,2
67,63,1,2
67,66,0,1
67,66,0,1
67,61,0,1
67,65,0,1
68,67,0,1
68,68,0,1
69,67,8,2
69,60,0,1
69,65,0,1
69,66,0,1
70,58,0,2
70,58,4,2
70,66,14,1
70,67,0,1
70,68,0,1
70,59,8,1
70,63,0,1
71,68,2,1
72,63,0,2
72,58,0,1
72,64,0,1
72,67,3,1
73,62,0,1
73,68,0,1
74,65,3,2
74,63,0,1
75,62,1,1
76,67,0,1
77,65,3,1
78,65,1,2
83,58,2,2
+22
View File
@@ -0,0 +1,22 @@
=== Run 1: mode=class-independent, radius=0.20 ===
Overall Accuracy: 68.85%
Cohen's Kappa : 0.413
Rules: 32 | OA: 68.85% | Kappa: 0.413
=== Run 2: mode=class-independent, radius=0.80 ===
Overall Accuracy: 73.77%
Cohen's Kappa : 0.617
Rules: 3 | OA: 73.77% | Kappa: 0.617
=== Run 3: mode=class-dependent, radius=0.20 ===
Overall Accuracy: 60.66%
Cohen's Kappa : 0.296
Rules: 51 | OA: 60.66% | Kappa: 0.296
=== Run 4: mode=class-dependent, radius=0.80 ===
Overall Accuracy: 72.13%
Cohen's Kappa : 0.604
Rules: 4 | OA: 72.13% | Kappa: 0.604
Done. Figures saved in: figures_scn1
+235
View File
@@ -0,0 +1,235 @@
Scenario 2 - Epileptic Seizure Classification
================================================
Configuration loaded: 3 folds, 2 feature options, 2 radius options.
Loading dataset from ./Datasets/epileptic_seizure_data.csv ...
Dataset loaded: 11500 samples, 178 features, 5 classes.
Splitting data into train/val/test (60/20/20%)...
-> train: 6900 val: 2300 test: 2300
Applying z-score normalization...
GRID SEARCH (features × radius) using 3-fold CV
[GRID] features= 5, radius=0.50 ...
-> Fold 1/3 ...
ANFIS info:
Number of nodes: 92
Number of linear parameters: 7
Number of nonlinear parameters: 70
Total number of parameters: 77
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 7
Minimal training RMSE = 1.13032
Minimal checking RMSE = 1.13236
Overall Accuracy: 30.61%
Cohen's Kappa : 0.169
kappa=0.169 rules=7
-> Fold 2/3 ...
ANFIS info:
Number of nodes: 140
Number of linear parameters: 11
Number of nonlinear parameters: 110
Total number of parameters: 121
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 11
Minimal training RMSE = 1.12499
Minimal checking RMSE = 1.15105
Overall Accuracy: 39.43%
Cohen's Kappa : 0.289
kappa=0.289 rules=11
-> Fold 3/3 ...
ANFIS info:
Number of nodes: 128
Number of linear parameters: 10
Number of nonlinear parameters: 100
Total number of parameters: 110
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 10
Minimal training RMSE = 1.13166
Minimal checking RMSE = 1.12551
Overall Accuracy: 34.91%
Cohen's Kappa : 0.225
kappa=0.225 rules=10
-> mean Kappa=0.227 mean rules=9
[GRID] features= 5, radius=0.75 ...
-> Fold 1/3 ...
ANFIS info:
Number of nodes: 68
Number of linear parameters: 5
Number of nonlinear parameters: 50
Total number of parameters: 55
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 5
Minimal training RMSE = 1.12389
Minimal checking RMSE = 1.12597
Overall Accuracy: 33.17%
Cohen's Kappa : 0.210
kappa=0.210 rules=5
-> Fold 2/3 ...
ANFIS info:
Number of nodes: 68
Number of linear parameters: 5
Number of nonlinear parameters: 50
Total number of parameters: 55
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 5
Minimal training RMSE = 1.15261
Minimal checking RMSE = 1.16568
Overall Accuracy: 34.30%
Cohen's Kappa : 0.240
kappa=0.240 rules=5
-> Fold 3/3 ...
ANFIS info:
Number of nodes: 68
Number of linear parameters: 5
Number of nonlinear parameters: 50
Total number of parameters: 55
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 5
Minimal training RMSE = 1.14349
Minimal checking RMSE = 1.13975
Overall Accuracy: 34.65%
Cohen's Kappa : 0.226
kappa=0.226 rules=5
-> mean Kappa=0.225 mean rules=5
[GRID] features= 8, radius=0.50 ...
-> Fold 1/3 ...
ANFIS info:
Number of nodes: 209
Number of linear parameters: 11
Number of nonlinear parameters: 176
Total number of parameters: 187
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 11
Minimal training RMSE = 1.11568
Minimal checking RMSE = 1.12592
Overall Accuracy: 35.26%
Cohen's Kappa : 0.224
kappa=0.224 rules=11
-> Fold 2/3 ...
ANFIS info:
Number of nodes: 209
Number of linear parameters: 11
Number of nonlinear parameters: 176
Total number of parameters: 187
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 11
Minimal training RMSE = 1.08705
Minimal checking RMSE = 1.11471
Overall Accuracy: 35.48%
Cohen's Kappa : 0.226
kappa=0.226 rules=11
-> Fold 3/3 ...
ANFIS info:
Number of nodes: 209
Number of linear parameters: 11
Number of nonlinear parameters: 176
Total number of parameters: 187
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 11
Minimal training RMSE = 1.12397
Minimal checking RMSE = 1.12198
Overall Accuracy: 35.65%
Cohen's Kappa : 0.230
kappa=0.230 rules=11
-> mean Kappa=0.227 mean rules=11
[GRID] features= 8, radius=0.75 ...
-> Fold 1/3 ...
ANFIS info:
Number of nodes: 119
Number of linear parameters: 6
Number of nonlinear parameters: 96
Total number of parameters: 102
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 6
Minimal training RMSE = 1.12245
Minimal checking RMSE = 1.12803
Overall Accuracy: 32.70%
Cohen's Kappa : 0.196
kappa=0.196 rules=6
-> Fold 2/3 ...
ANFIS info:
Number of nodes: 173
Number of linear parameters: 9
Number of nonlinear parameters: 144
Total number of parameters: 153
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 9
Minimal training RMSE = 1.10065
Minimal checking RMSE = 1.12512
Overall Accuracy: 37.09%
Cohen's Kappa : 0.251
kappa=0.251 rules=9
-> Fold 3/3 ...
ANFIS info:
Number of nodes: 101
Number of linear parameters: 5
Number of nonlinear parameters: 80
Total number of parameters: 85
Number of training data pairs: 4600
Number of checking data pairs: 2300
Number of fuzzy rules: 5
Minimal training RMSE = 1.13562
Minimal checking RMSE = 1.13557
Overall Accuracy: 33.00%
Cohen's Kappa : 0.196
kappa=0.196 rules=5
-> mean Kappa=0.214 mean rules=7
BEST HYPERPARAMS
features=5 radius=0.50 CV Kappa=0.227 mean rules=9
Training final model on train+val with best params ...
ANFIS info:
Number of nodes: 80
Number of linear parameters: 6
Number of nonlinear parameters: 60
Total number of parameters: 66
Number of training data pairs: 9200
Number of checking data pairs: 2300
Number of fuzzy rules: 6
Minimal training RMSE = 1.14268
Minimal checking RMSE = 1.1463
Final training complete: 6 rules.
Evaluating on TEST set ...
Overall Accuracy: 29.78%
Cohen's Kappa : 0.158
[TEST RESULTS]
OA = 29.78 %
Kappa= 0.158
Rules= 6
Generating figures ...
Done. Figures saved in: figures_scn2
+50
View File
@@ -0,0 +1,50 @@
function results = evaluate_classification(yTrue, yPred, classLabels)
% EVALUATE_CLASSIFICATION Compute OA, PA, UA, Kappa and confusion matrix
%
% results = evaluate_classification(yTrue, yPred, classLabels)
%
% yTrue, yPred : true & predicted class labels
% classLabels : vector with all class IDs (optional)
%
% results struct:
% .confMat
% .OA
% .PA
% .UA
% .Kappa
if nargin < 3
classLabels = unique([yTrue; yPred]);
end
% Ensure column vectors
yTrue = yTrue(:);
yPred = yPred(:);
% Build confusion matrix
confMat = confusionmat(yTrue, yPred, 'Order', classLabels);
% Overall Accuracy
OA = trace(confMat) / sum(confMat(:));
% Producer's & User's Accuracy (per class)
PA = diag(confMat) ./ sum(confMat,2); % Recall per class
UA = diag(confMat) ./ sum(confMat,1)'; % Precision per class
% Cohen's Kappa
n = sum(confMat(:));
po = OA;
pe = sum(sum(confMat,1) .* sum(confMat,2)) / n^2;
Kappa = (po - pe) / (1 - pe);
% Pack results
results.confMat = confMat;
results.OA = OA;
results.PA = PA;
results.UA = UA;
results.Kappa = Kappa;
% Optional display
fprintf('Overall Accuracy: %.2f%%\n', 100*OA);
fprintf('Cohen''s Kappa : %.3f\n', Kappa);
end
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@@ -0,0 +1,5 @@
Run,Mode,Radius,Rules,OA,Kappa
1,class-independent,0.2,32,0.688524590163934,0.412569690826153
2,class-independent,0.8,3,0.737704918032787,0.616502946954813
3,class-dependent,0.2,51,0.60655737704918,0.296492071119654
4,class-dependent,0.8,4,0.721311475409836,0.604349484929416
1 Run Mode Radius Rules OA Kappa
2 1 class-independent 0.2 32 0.688524590163934 0.412569690826153
3 2 class-independent 0.8 3 0.737704918032787 0.616502946954813
4 3 class-dependent 0.2 51 0.60655737704918 0.296492071119654
5 4 class-dependent 0.8 4 0.721311475409836 0.604349484929416
Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

+165
View File
@@ -0,0 +1,165 @@
function plot_results1(results, classLabels, cfg)
% PLOT_RESULTS1 Scenario 1 plotting suite (Classification)
% Generates and saves:
% (A) Confusion matrix per model
% (B) PA/UA bars per model
% (C) Membership functions BEFORE/AFTER training per model
% (D) Learning curves (train/val error) per model
% (E) Predictions vs Truth (test set) per model
% (F) OA and Kappa across models (bars)
% (G) Rules vs Accuracy scatter
%
% All PNGs saved under cfg.outDir.
outDir = cfg.outDir;
if ~exist(outDir,'dir'), mkdir(outDir); end
nRuns = numel(results);
OA = zeros(nRuns,1);
Kap = zeros(nRuns,1);
nRules = zeros(nRuns,1);
modes = strings(nRuns,1);
radii = zeros(nRuns,1);
for i = 1:nRuns
OA(i) = results(i).metrics.OA;
Kap(i) = results(i).metrics.Kappa;
nRules(i) = results(i).nRules;
modes(i) = string(results(i).mode);
radii(i) = results(i).radius;
end
% Per-model plots
for i = 1:nRuns
tag = sprintf('run%02d_%s_r%.2f_rules%d', ...
i, results(i).mode, results(i).radius, results(i).nRules);
% (A) Confusion matrix
fig = figure('Color','w');
confusionchart(results(i).metrics.confMat, string(classLabels), ...
'Title', sprintf('Confusion %s (r=%.2f, rules=%d)', ...
results(i).mode, results(i).radius, results(i).nRules));
exportgraphics(fig, fullfile(outDir, ['cm_' tag '.png']), 'Resolution', 200);
close(fig);
% (B) PA / UA bars
fig = figure('Color','w');
t = tiledlayout(2,1,'TileSpacing','compact','Padding','compact');
nexttile;
bar(results(i).metrics.PA); ylim([0 1]);
xticks(1:numel(classLabels)); xticklabels(string(classLabels));
ylabel('PA (Recall)');
title(sprintf('Producer''s Accuracy %s (r=%.2f)', results(i).mode, results(i).radius));
nexttile;
bar(results(i).metrics.UA); ylim([0 1]);
xticks(1:numel(classLabels)); xticklabels(string(classLabels));
ylabel('UA (Precision)');
title(sprintf('User''s Accuracy %s (r=%.2f)', results(i).mode, results(i).radius));
exportgraphics(fig, fullfile(outDir, ['pa_ua_' tag '.png']), 'Resolution', 200);
close(fig);
% (C) Membership functions BEFORE/AFTER
% Layout: 2 rows (Before/After) x D columns (inputs)
try
plot_mfs_before_after(results(i).initFis, results(i).fis, ...
sprintf('%s (r=%.2f, %s)', results(i).mode, results(i).radius, tag), ...
fullfile(outDir, ['mfs_' tag '.png']));
catch ME
warning('MF plot failed for %s: %s', tag, ME.message);
end
% (D) Learning curves (ANFIS)
trErr = results(i).trError; % may be vector
ckErr = results(i).ckError; % may be vector
if ~isempty(trErr)
fig = figure('Color','w');
plot(1:numel(trErr), trErr, 'LineWidth', 1.2); hold on;
if ~isempty(ckErr)
plot(1:numel(ckErr), ckErr, '--', 'LineWidth', 1.2);
legend('Training Error','Validation Error','Location','best');
else
legend('Training Error','Location','best');
end
xlabel('Epoch'); ylabel('Error'); grid on;
title(sprintf('Learning Curve %s (r=%.2f, rules=%d)', ...
results(i).mode, results(i).radius, results(i).nRules));
exportgraphics(fig, fullfile(outDir, ['learning_' tag '.png']), 'Resolution', 200);
close(fig);
end
% (E) Predictions vs Truth (test set) like report example
if isfield(results(i),'yhat') && isfield(results(i),'ytrue')
yhat = results(i).yhat(:);
ytrue = results(i).ytrue(:);
fig = figure('Color','w');
plot(ytrue, 'LineWidth', 1.0); hold on;
plot(yhat, '--', 'LineWidth', 1.0);
xlabel('Test sample index'); ylabel('Class label');
title(sprintf('Truth vs Prediction %s (r=%.2f)', results(i).mode, results(i).radius));
legend('Truth','Prediction','Location','best'); grid on;
exportgraphics(fig, fullfile(outDir, ['pred_vs_truth_' tag '.png']), 'Resolution', 200);
close(fig);
end
end
% Across-model summaries
[~, idxSort] = sortrows([double(modes=='class-independent'), radii], [1 2]);
OA_s = OA(idxSort);
Kap_s = Kap(idxSort);
modes_s = modes(idxSort);
radii_s = radii(idxSort);
labels = arrayfun(@(j) sprintf('%s\nr=%.2f', modes_s(j), radii_s(j)), 1:nRuns, 'uni', 0);
fig = figure('Color','w');
bar(OA_s*100); xticks(1:nRuns); xticklabels(labels); xtickangle(30);
ylabel('Overall Accuracy (%)'); title('Overall Accuracy across models'); grid on;
exportgraphics(fig, fullfile(outDir, 'overall_accuracy_across_models.png'), 'Resolution', 200);
close(fig);
fig = figure('Color','w');
bar(Kap_s); xticks(1:nRuns); xticklabels(labels); xtickangle(30);
ylabel('Cohen''s \kappa'); title('Kappa across models'); grid on;
exportgraphics(fig, fullfile(outDir, 'kappa_across_models.png'), 'Resolution', 200);
close(fig);
fig = figure('Color','w');
gscatter(nRules, OA*100, modes, [], [], 8);
xlabel('#Rules'); ylabel('OA (%)'); title('Rules vs Accuracy'); grid on; legend('Location','best');
exportgraphics(fig, fullfile(outDir, 'rules_vs_accuracy.png'), 'Resolution', 200);
close(fig);
% CSV summary
T = table((1:nRuns)', modes, radii, nRules, OA, Kap, ...
'VariableNames', {'Run','Mode','Radius','Rules','OA','Kappa'});
writetable(T, fullfile(outDir, 'summary_scn1.csv'));
end
% ------------------ helpers ------------------
function plot_mfs_before_after(fisBefore, fisAfter, suptitleStr, outPng)
% Plot input MFs before/after in a 2xD tiled layout.
D = numel(fisAfter.Inputs); % assume same D
fig = figure('Color','w','Position',[100 100 1200 420]);
t = tiledlayout(2, D, 'TileSpacing','compact','Padding','compact');
for d = 1:D
nexttile(d); hold on;
try
[xB, yB] = plotmf(fisBefore, 'input', d);
plot(xB, yB, 'LineWidth', 1.0);
catch
% fallback: skip before if not available
end
title(sprintf('Input %d BEFORE', d));
ylim([0 1]); grid on;
nexttile(D + d); hold on;
[xA, yA] = plotmf(fisAfter, 'input', d);
plot(xA, yA, 'LineWidth', 1.0);
title(sprintf('Input %d AFTER', d));
ylim([0 1]); grid on;
end
sgtitle(['MFs ' suptitleStr]);
exportgraphics(fig, outPng, 'Resolution', 200);
close(fig);
end
+142
View File
@@ -0,0 +1,142 @@
function plot_results2(results, cfg, classLabels)
% PLOT_RESULTS2 Scenario 2 plotting suite
% Produces and saves:
% (A) CV heatmap of Kappa over (#features × radius)
% (B) CV heatmap of mean #rules over the same grid
% (C) Confusion matrix on TEST for the best model
% (D) PA/UA bars on TEST
% (E) Learning curves (train/validation error)
% (F) MFs before/after for the best model
% (G) Truth vs Prediction (TEST)
% (H) ReliefF feature weights bar chart
%
% All PNGs saved under cfg.outDir.
outDir = cfg.outDir;
% (A) CV heatmap Kappa
fig = figure('Color','w');
imagesc(results.cvScores);
set(gca,'XTick',1:numel(results.rGrid),'XTickLabel',compose('%.2f',results.rGrid));
set(gca,'YTick',1:numel(results.fGrid),'YTickLabel',string(results.fGrid));
xlabel('SC radius r_a'); ylabel('#Features (ReliefF)'); colorbar;
title(sprintf('CV mean Kappa (K=%d folds)', cfg.kfold));
for i = 1:numel(results.fGrid)
for j = 1:numel(results.rGrid)
text(j,i,sprintf('%.2f',results.cvScores(i,j)),...
'HorizontalAlignment','center','Color','w','FontWeight','bold');
end
end
exportgraphics(fig, fullfile(outDir,'cv_kappa_heatmap.png'), 'Resolution', 200);
close(fig);
% (B) CV heatmap mean #rules
fig = figure('Color','w');
imagesc(results.cvRules);
set(gca,'XTick',1:numel(results.rGrid),'XTickLabel',compose('%.2f',results.rGrid));
set(gca,'YTick',1:numel(results.fGrid),'YTickLabel',string(results.fGrid));
xlabel('SC radius r_a'); ylabel('#Features (ReliefF)'); colorbar;
title(sprintf('CV mean #Rules (K=%d folds)', cfg.kfold));
for i = 1:numel(results.fGrid)
for j = 1:numel(results.rGrid)
text(j,i,sprintf('%d',results.cvRules(i,j)),...
'HorizontalAlignment','center','Color','w','FontWeight','bold');
end
end
exportgraphics(fig, fullfile(outDir,'cv_rules_heatmap.png'), 'Resolution', 200);
close(fig);
% (C) Confusion matrix TEST
fig = figure('Color','w');
confusionchart(results.metrics.confMat, string(classLabels), ...
'Title', sprintf('Confusion best model (features=%d, r=%.2f, rules=%d)', ...
results.bestF, results.bestR, numel(results.bestFis.rule)));
exportgraphics(fig, fullfile(outDir,'cm_best_model.png'), 'Resolution', 200);
close(fig);
% (D) PA/UA bars TEST
fig = figure('Color','w');
t = tiledlayout(2,1,'TileSpacing','compact','Padding','compact');
nexttile; bar(results.metrics.PA); ylim([0 1]);
xticks(1:numel(classLabels)); xticklabels(string(classLabels));
ylabel('PA (Recall)'); title('Producer''s Accuracy (TEST)'); grid on;
nexttile; bar(results.metrics.UA); ylim([0 1]);
xticks(1:numel(classLabels)); xticklabels(string(classLabels));
ylabel('UA (Precision)'); title('User''s Accuracy (TEST)'); grid on;
exportgraphics(fig, fullfile(outDir,'pa_ua_best_model.png'), 'Resolution', 200);
close(fig);
% (E) Learning curves
fig = figure('Color','w');
plot(1:numel(results.trError), results.trError, 'LineWidth', 1.2); hold on;
if ~isempty(results.vaError)
plot(1:numel(results.vaError), results.vaError, '--', 'LineWidth', 1.2);
legend('Training Error','Validation Error','Location','best');
else
legend('Training Error','Location','best');
end
xlabel('Epoch'); ylabel('Error'); grid on;
title(sprintf('Learning Curve best model (features=%d, r=%.2f)', ...
results.bestF, results.bestR));
exportgraphics(fig, fullfile(outDir,'learning_best_model.png'), 'Resolution', 200);
close(fig);
% (F) MFs before/after for the best model
try
plot_mfs_before_after(results.initFis, results.bestFis, ...
sprintf('MFs best model (features=%d, r=%.2f)', results.bestF, results.bestR), ...
fullfile(outDir,'mfs_best_model.png'));
catch ME
warning('MF plot failed: %s', ME.message);
end
% (G) Truth vs Prediction TEST
fig = figure('Color','w');
plot(results.ytrue, 'LineWidth', 1.0); hold on;
plot(results.yhat, '--', 'LineWidth', 1.0);
xlabel('Test sample index'); ylabel('Class label'); grid on;
title('Truth vs Prediction (TEST)');
legend('Truth','Prediction','Location','best');
exportgraphics(fig, fullfile(outDir,'pred_vs_truth_best_model.png'), 'Resolution', 200);
close(fig);
% (H) ReliefF feature weights (on full train+val)
fig = figure('Color','w');
w = results.reliefW(:);
idx = results.selIdx(:);
% map back: selected indices first for clarity
bar(1:numel(idx), w(idx)); grid on;
xlabel('Selected feature index'); ylabel('ReliefF weight');
title(sprintf('ReliefF weights (top %d features)', results.bestF));
exportgraphics(fig, fullfile(outDir,'relieff_weights_selected.png'), 'Resolution', 200);
close(fig);
% ===================== local helper =====================
function plot_mfs_before_after(fisBefore, fisAfter, suptitleStr, outPng)
D = numel(fisAfter.Inputs);
fig = figure('Color','w','Position',[100 100 1200 420]);
t = tiledlayout(2, D, 'TileSpacing','compact','Padding','compact');
for d = 1:D
nexttile(d); hold on;
try
[xB, yB] = plotmf(fisBefore, 'input', d);
plot(xB, yB, 'LineWidth', 1.0);
catch
end
title(sprintf('Input %d BEFORE', d));
ylim([0 1]); grid on;
nexttile(D + d); hold on;
[xA, yA] = plotmf(fisAfter, 'input', d);
plot(xA, yA, 'LineWidth', 1.0);
title(sprintf('Input %d AFTER', d));
ylim([0 1]); grid on;
end
sgtitle(suptitleStr);
exportgraphics(fig, outPng, 'Resolution', 200);
close(fig);
end
end
+17
View File
@@ -0,0 +1,17 @@
function [Xn, mu, sigma] = preprocess_data(X, mu, sigma)
% PREPROCESS_DATA Normalize feature matrix using z-score scaling
%
% [Xn, mu, sigma] = preprocess(X)
% [Xn, mu, sigma] = preprocess(X, mu, sigma)
%
% Applies feature-wise standardization (zero mean, unit variance)
% to the predictors only labels Y remain unchanged.
if nargin < 2 || isempty(mu)
mu = mean(X,1);
sigma = std(X,[],1);
end
sigma(sigma==0) = 1; % avoid division by zero
Xn = (X - mu) ./ sigma;
end
Binary file not shown.
Binary file not shown.
+230
View File
@@ -0,0 +1,230 @@
%% scenario1.m Assignment 4 (Classification), Scenario 1 (Haberman)
% TSK classification with Subtractive Clustering (SC)
% Modes: (A) class-independent SC,
% (B) class-dependent SC)
% Uses: split_data, preprocess_data, evaluate_classification, plot_results1
%
% Dataset: ./Datasets/haberman.data
% Columns: [age, op_year, axillary_nodes, class] with class in {1,2}
%
% Assignment 4 in Fuzzy systems
%
% author:
% Christos Choutouridis ΑΕΜ 8997
% cchoutou@ece.auth.gr
%
close all; clear; clc;
% CONFIGURATION
% ================================
cfg = struct();
rng(42, 'twister'); % reproducibility
% Data handling
cfg.split = [0.6 0.2 0.2]; % train / val / test (stratified in split_data)
cfg.standardize = true; % z-score features
% SC radii sweep
cfg.radii = [0.20 0.80];
% ANFIS options
cfg.maxEpochs = 100;
cfg.errorGoal = 0;
cfg.initialStep = 0.01;
cfg.stepDecrease = 0.9;
cfg.stepIncrease = 1.1;
cfg.displayANFIS = 0; % quiet
% Modes
cfg.modes = {'class-independent','class-dependent'};
% Output
cfg.outDir = 'figures_scn1';
if ~exist(cfg.outDir,'dir'), mkdir(cfg.outDir); end
% DATA
dataPath = './Datasets/haberman.data';
assert(isfile(dataPath), 'Dataset not found at: %s', dataPath);
%
raw = load(dataPath);
assert(size(raw,2) == 4, 'Expected 4 columns in haberman.data');
X = raw(:,1:3);
Y = raw(:,4);
Y = Y(:);
classLabels = unique(Y);
minLabel = min(classLabels); maxLabel = max(classLabels);
% SPLIT & PREPROCESS
[trainX, valX, testX, trainY, valY, testY] = split_data(X, Y, cfg.split);
if cfg.standardize
[trainX, mu, sigma] = preprocess_data(trainX);
valX = preprocess_data(valX, mu, sigma);
testX = preprocess_data(testX, mu, sigma);
else
mu = []; sigma = [];
end
% For manual sugfis construction
inRanges = [min(trainX,[],1); max(trainX,[],1)];
% TRAINING
results = []; runId = 0;
for m = 1:numel(cfg.modes)
modeName = cfg.modes{m};
for r = 1:numel(cfg.radii)
radius = cfg.radii(r);
runId = runId + 1;
fprintf('\n=== Run %d: mode=%s, radius=%.2f ===\n', runId, modeName, radius);
% Initial FIS
switch modeName
case 'class-independent'
opt = genfisOptions('SubtractiveClustering', ...
'ClusterInfluenceRange', radius);
initFis = genfis(trainX, double(trainY), opt);
% genfis(Subtractive) already builds Sugeno with constant consequents.
case 'class-dependent'
% Our custom builder
initFis = build_classdep_fis(trainX, trainY, classLabels, radius, inRanges);
otherwise
error('Unknown mode: %s', modeName);
end
% ANFIS training
trData = [trainX double(trainY)];
ckData = [valX double(valY)];
anfisOpts = [cfg.maxEpochs cfg.errorGoal cfg.initialStep cfg.stepDecrease cfg.stepIncrease];
if cfg.displayANFIS
[fisTrained, trError, ~, ~, ckError] = anfis(trData, initFis, anfisOpts, [], ckData);
else
[fisTrained, trError, ~, ~, ckError] = anfis(trData, initFis, anfisOpts, [0 0 0 0], ckData);
end
% Evaluate on test set
yhat_cont = evalfis(testX, fisTrained);
yhat = round(yhat_cont);
% clip into valid label range (important for small rulebases)
yhat(yhat < minLabel) = minLabel;
yhat(yhat > maxLabel) = maxLabel;
% Metrics (note: our evaluate expects (yTrue, yPred))
R = evaluate_classification(testY, yhat, classLabels);
% Collect
res = struct();
res.runId = runId;
res.mode = modeName;
res.radius = radius;
res.fis = fisTrained;
res.nRules = numel(fisTrained.rule);
res.metrics = R;
res.trError = trError;
res.ckError = ckError;
res.mu = mu;
res.sigma = sigma;
res.initFis = initFis;
res.yhat = yhat;
res.ytrue = testY;
results = [results; res];
fprintf('Rules: %d | OA: %.2f%% | Kappa: %.3f\n', res.nRules, 100*R.OA, R.Kappa);
end
end
% PLOTTING
plot_results1(results, classLabels, cfg);
% SAVE ALL
save('results_scn1.mat','results','cfg','classLabels','mu','sigma', ...
'trainX','valX','testX','trainY','valY','testY');
fprintf('\nDone. Figures saved in: %s\n', cfg.outDir);
% LOCAL FUNCTIONS
% ===================================================
function fis = build_classdep_fis(X, Y, classLabels, radius, inRanges)
% BUILD_CLASSDEP_FIS class-dependent SC for Sugeno FIS (ANFIS-ready)
% Creates ONE constant output MF PER RULE (required by ANFIS).
% Runs SUBCLUST on FEATURES ONLY for each class.
D = size(X, 2);
fis = sugfis('Name','TSK_ClassDependent');
% Inputs with ranges from training data
for d = 1:D
fis = addInput(fis, [inRanges(1,d) inRanges(2,d)], 'Name', sprintf('x%d', d));
end
% Single scalar output y (range just spans label space)
outRange = [min(classLabels) max(classLabels)];
fis = addOutput(fis, outRange, 'Name', 'y');
ruleList = [];
% Build rules class-by-class
for k = 1:numel(classLabels)
c = classLabels(k);
Xi = X(Y==c, :);
if isempty(Xi), continue; end
% Subtractive clustering on class features
[centers, sigmas] = subclust(Xi, radius);
nCl = size(centers,1);
% robust sigma broadcasting to M×D
if isscalar(sigmas)
S = repmat(sigmas, nCl, D);
elseif size(sigmas,1) == 1 && size(sigmas,2) == D
S = repmat(sigmas, nCl, 1);
elseif size(sigmas,1) == nCl && size(sigmas,2) == D
S = sigmas;
else
S = repmat(0.5*(inRanges(2,:)-inRanges(1,:)), nCl, 1);
end
% -----------------------------------------
% For each cluster: add one Gaussian MF per input, one constant MF for output,
% and one rule that ties those together (AND=prod).
for i = 1:nCl
antecedentIdx = zeros(1,D);
% Add input MFs for this cluster (and remember their indices)
for d = 1:D
mfName = sprintf('c%d_r%d_x%d', c, i, d);
params = [S(i, d) centers(i, d)]; % [sigma center]
fis = addMF(fis, sprintf('x%d', d), 'gaussmf', params, 'Name', mfName);
antecedentIdx(d) = numel(fis.Inputs(d).MembershipFunctions);
end
% Add ONE output MF (constant) for THIS rule (ANFIS requirement)
outMfName = sprintf('const_c%d_r%d', c, i);
fis = addMF(fis, 'y', 'constant', double(c), 'Name', outMfName);
outIdx = numel(fis.Outputs(1).MembershipFunctions);
% Rule row: [inMFs outMF weight AND=1]
rule = [antecedentIdx, outIdx, 1, 1];
ruleList = [ruleList; rule]; %#ok<AGROW>
end
end
if ~isempty(ruleList)
fis = addRule(fis, ruleList);
end
% Standard TSK operators
fis.AndMethod = 'prod';
fis.OrMethod = 'probor';
fis.ImplicationMethod = 'prod';
fis.AggregationMethod = 'sum';
fis.DefuzzificationMethod = 'wtaver';
end
+297
View File
@@ -0,0 +1,297 @@
%% scenario2.m Assignment 4 (Classification), Scenario 2 (Epileptic Seizure)
% TSK classification on a high-dimensional dataset with feature selection.
% Verbose version with progress printing.
%
% Uses: split_data, preprocess_data, evaluate_classification, plot_results2
% Dataset path: ./Datasets/epileptic_seizure_data.csv
%
% Assignment 4 in Fuzzy systems
%
% author:
% Christos Choutouridis ΑΕΜ 8997
% cchoutou@ece.auth.gr
close all; clear; clc;
%parpool('threads',6);
fprintf('\nScenario 2 - Epileptic Seizure Classification');
fprintf('\n================================================\n\n');
% CONFIGURATION
cfg = struct();
rng(42,'twister'); % reproducibility
% Data handling
cfg.split = [0.6 0.2 0.2];
cfg.standardize = true;
% Feature selection + SC hyper-params
% Debug configuration
cfg.feature_grid = [5 8]; %[5 8 11 15];
cfg.radii_grid = [0.5 0.75]; %[0.25 0.50 0.75 1.00];
cfg.kfold = 3;
cfg.maxEpochs = 20; % ANFIS options
cfg.displayANFIS = 0;
% Default configuraion
%cfg.feature_grid = [5 8 11 15];
%cfg.radii_grid = [0.25 0.50 0.75 1.00];
%cfg.kfold = 5;
%cfg.maxEpochs = 100; % ANFIS options
%cfg.displayANFIS = 0;
% Output directory
cfg.outDir = 'figures_scn2';
if ~exist(cfg.outDir,'dir'), mkdir(cfg.outDir); end
fprintf('Configuration loaded: %d folds, %d feature options, %d radius options.\n', ...
cfg.kfold, numel(cfg.feature_grid), numel(cfg.radii_grid));
% DATA
dataPath = './Datasets/epileptic_seizure_data.csv';
fprintf('Loading dataset from %s ...\n', dataPath);
assert(isfile(dataPath), 'Dataset not found!');
raw = importdata(dataPath);
if isstruct(raw) && isfield(raw,'data')
A = raw.data;
else
A = readmatrix(dataPath);
end
X = A(:,1:end-1);
Y = A(:,end);
Y = double(Y(:));
classLabels = unique(Y);
num_classes = numel(classLabels);
fprintf('Dataset loaded: %d samples, %d features, %d classes.\n', ...
size(X,1), size(X,2), num_classes);
% SPLIT & PREPROCESS
fprintf('\nSplitting data into train/val/test (%.0f/%.0f/%.0f%%)...\n', cfg.split*100);
[trainX, valX, testX, trainY, valY, testY] = split_data(X, Y, cfg.split);
fprintf('-> train: %d val: %d test: %d\n', size(trainX,1), size(valX,1), size(testX,1));
if cfg.standardize
fprintf('Applying z-score normalization...\n');
[trainX, mu, sigma] = preprocess_data(trainX);
valX = preprocess_data(valX, mu, sigma);
testX = preprocess_data(testX, mu, sigma);
else
mu = []; sigma = [];
end
fullTrainX = [trainX; valX];
fullTrainY = [trainY; valY];
% GRID SEARCH
fprintf('\nGRID SEARCH (features × radius) using %d-fold CV\n', cfg.kfold);
cvp = cvpartition(trainY, 'KFold', cfg.kfold, 'Stratify', true);
nF = numel(cfg.feature_grid);
nR = numel(cfg.radii_grid);
cvScores = zeros(nF, nR);
cvRules = zeros(nF, nR);
for fi = 1:nF
featKeep = cfg.feature_grid(fi);
for ri = 1:nR
radius = cfg.radii_grid(ri);
fprintf('\n[GRID] features=%2d, radius=%.2f ... ', featKeep, radius);
kappas = zeros(cvp.NumTestSets,1);
rulesK = zeros(cvp.NumTestSets,1);
for k = 1:cvp.NumTestSets
fprintf('\n-> Fold %d/%d ... ', k, cfg.kfold);
trIdx = training(cvp, k);
teIdx = test(cvp, k);
Xtr = trainX(trIdx,:); Ytr = trainY(trIdx);
Xva = trainX(teIdx,:); Yva = trainY(teIdx);
% Relief feature selection
[idxFeat, ~] = relief_select(Xtr, Ytr);
sel = idxFeat(1:min(featKeep, numel(idxFeat)));
Xtr = Xtr(:, sel);
Xva = Xva(:, sel);
% Build FIS
inRanges = [min(Xtr,[],1); max(Xtr,[],1)];
initFis = build_classdep_fis(Xtr, Ytr, classLabels, radius, inRanges);
% Train
trData = [Xtr double(Ytr)];
vaData = [Xva double(Yva)];
anfisOpts = anfisOptions('InitialFis', initFis, ...
'EpochNumber', cfg.maxEpochs, ...
'ValidationData', vaData, ...
'OptimizationMethod', 1, ...
'DisplayErrorValues', 0, ...
'DisplayStepSize', 0);
[~, ~, ~, bestFis, ~] = anfis(trData, anfisOpts);
% Evaluate fold
yhat = evalfis(bestFis, Xva);
yhat = round(yhat);
yhat(yhat < min(classLabels)) = min(classLabels);
yhat(yhat > max(classLabels)) = max(classLabels);
R = evaluate_classification(Yva, yhat, classLabels);
kappas(k) = R.Kappa;
rulesK(k) = numel(bestFis.rule);
fprintf('kappa=%.3f rules=%d\n', R.Kappa, rulesK(k));
end
cvScores(fi,ri) = mean(kappas);
cvRules(fi,ri) = round(mean(rulesK));
fprintf('\n-> mean Kappa=%.3f mean rules=%d\n', cvScores(fi,ri), cvRules(fi,ri));
end
end
[maxPerRow, idxR] = max(cvScores, [], 2);
[bestKappa, idxF] = max(maxPerRow);
idxR = idxR(idxF);
bestFeatures = cfg.feature_grid(idxF);
bestRadius = cfg.radii_grid(idxR);
bestRulesEst = cvRules(idxF, idxR);
fprintf('\nBEST HYPERPARAMS\nfeatures=%d radius=%.2f CV Kappa=%.3f mean rules=%d\n', ...
bestFeatures, bestRadius, bestKappa, bestRulesEst);
% FINAL TRAIN
fprintf('\nTraining final model on train+val with best params ...\n');
[idxAll, weightsAll] = relief_select(fullTrainX, fullTrainY);
sel = idxAll(1:min(bestFeatures, numel(idxAll)));
Xtr = fullTrainX(:, sel);
Xte = testX(:, sel);
inRanges = [min(Xtr,[],1); max(Xtr,[],1)];
initFis = build_classdep_fis(Xtr, fullTrainY, classLabels, bestRadius, inRanges);
trData = [Xtr double(fullTrainY)];
teData = [Xte double(testY)];
anfisOpts = anfisOptions('InitialFis', initFis, ...
'EpochNumber', cfg.maxEpochs, ...
'ValidationData', teData, ...
'OptimizationMethod', 1, ...
'DisplayErrorValues', 0, ...
'DisplayStepSize', 0);
[fisTrained, trError, ~, bestFis, vaError] = anfis(trData, anfisOpts);
fprintf('Final training complete: %d rules.\n', numel(bestFis.rule));
% TEST EVAL
fprintf('\nEvaluating on TEST set ...\n');
yhat_test = evalfis(bestFis, Xte);
yhat_test = round(yhat_test);
yhat_test(yhat_test < min(classLabels)) = min(classLabels);
yhat_test(yhat_test > max(classLabels)) = max(classLabels);
Rtest = evaluate_classification(testY, yhat_test, classLabels);
fprintf('\n[TEST RESULTS]\n');
fprintf(' OA = %.2f %%\n', 100*Rtest.OA);
fprintf(' Kappa= %.3f\n', Rtest.Kappa);
fprintf(' Rules= %d\n', numel(bestFis.rule));
% PLOTTING
fprintf('\nGenerating figures ...\n');
results = struct();
results.cvScores = cvScores;
results.cvRules = cvRules;
results.fGrid = cfg.feature_grid;
results.rGrid = cfg.radii_grid;
results.bestF = numel(sel);
results.bestR = bestRadius;
results.bestFis = bestFis;
results.initFis = initFis;
results.trError = trError;
results.vaError = vaError;
results.ytrue = testY;
results.yhat = yhat_test;
results.metrics = Rtest;
results.selIdx = sel;
results.reliefW = weightsAll;
plot_results2(results, cfg, classLabels);
save('results_scn2.mat','results','cfg','classLabels','mu','sigma');
fprintf('\nDone. Figures saved in: %s\n', cfg.outDir);
% LOCAL FUNCTIONS
% ==================================================
function fis = build_classdep_fis(X, Y, classLabels, radius, inRanges)
% BUILD_CLASSDEP_FIS class-dependent SC Sugeno FIS (ANFIS-ready)
% Creates ONE constant output MF PER RULE (ANFIS requirement).
% Runs subclust on FEATURES ONLY per class.
D = size(X,2);
fis = sugfis('Name','TSK_CD');
% Inputs
for d = 1:D
fis = addInput(fis, [inRanges(1,d) inRanges(2,d)], 'Name', sprintf('x%d', d));
end
% Output (range spans label space)
outRange = [min(classLabels) max(classLabels)];
fis = addOutput(fis, outRange, 'Name', 'y');
ruleList = [];
for k = 1:numel(classLabels)
c = classLabels(k);
Xi = X(Y==c, :);
if isempty(Xi), continue; end
[centers, sigmas] = subclust(Xi, radius);
nCl = size(centers,1);
% Robust sigma broadcasting to M×D
if isscalar(sigmas)
S = repmat(sigmas, nCl, D);
elseif size(sigmas,1)==1 && size(sigmas,2)==D
S = repmat(sigmas, nCl, 1);
elseif all(size(sigmas)==[nCl D])
S = sigmas;
else
S = repmat(0.5*(inRanges(2,:)-inRanges(1,:)), nCl, 1);
end
for i = 1:nCl
antIdx = zeros(1,D);
for d = 1:D
mfName = sprintf('c%d_r%d_x%d', c, i, d);
params = [S(i,d) centers(i,d)]; % [sigma center]
fis = addMF(fis, sprintf('x%d', d), 'gaussmf', params, 'Name', mfName);
antIdx(d) = numel(fis.Inputs(d).MembershipFunctions);
end
% ONE constant output MF per rule
outName = sprintf('const_c%d_r%d', c, i);
fis = addMF(fis, 'y', 'constant', double(c), 'Name', outName);
outIdx = numel(fis.Outputs(1).MembershipFunctions);
ruleList = [ruleList; [antIdx, outIdx, 1, 1]]; %#ok<AGROW>
end
end
if ~isempty(ruleList)
fis = addRule(fis, ruleList);
end
% Standard TSK ops
fis.AndMethod = 'prod';
fis.OrMethod = 'probor';
fis.ImplicationMethod = 'prod';
fis.AggregationMethod = 'sum';
fis.DefuzzificationMethod = 'wtaver';
end
function [idx, w] = relief_select(X, y)
% RELIEF_SELECT wraps relieff and returns ranked indices + weights.
try
[idx, w] = relieff(X, y, 10); % k=10 neighbors
catch
% Fallback: simple variance ranking if Statistics Toolbox missing
w = var(X, 0, 1);
[~, idx] = sort(w, 'descend');
end
end
+39
View File
@@ -0,0 +1,39 @@
function [trainX, valX, testX, trainY, valY, testY] = split_data(X, Y, ratios)
% SPLIT_DATA Split dataset into train/validation/test sets (stratified)
%
% [trainX, valX, testX, trainY, valY, testY] = split(X, Y, ratios)
%
% ratios : [trainRatio, valRatio, testRatio] (e.g. [0.6 0.2 0.2])
%
% Stratified split ensures class proportions remain consistent.
if nargin < 3
ratios = [0.6 0.2 0.2];
end
assert(abs(sum(ratios) - 1) < 1e-6, 'Ratios must sum to 1.');
n = size(X,1);
classes = unique(Y);
idxTrain = []; idxVal = []; idxTest = [];
for c = classes'
idx = find(Y == c);
idx = idx(randperm(length(idx))); % randomize within class
nTrain = round(ratios(1)*length(idx));
nVal = round(ratios(2)*length(idx));
idxTrain = [idxTrain; idx(1:nTrain)];
idxVal = [idxVal; idx(nTrain+1:nTrain+nVal)];
idxTest = [idxTest; idx(nTrain+nVal+1:end)];
end
% Shuffle within each subset to mix classes
idxTrain = idxTrain(randperm(length(idxTrain)));
idxVal = idxVal(randperm(length(idxVal)));
idxTest = idxTest(randperm(length(idxTest)));
trainX = X(idxTrain,:); trainY = Y(idxTrain);
valX = X(idxVal,:); valY = Y(idxVal);
testX = X(idxTest,:); testY = Y(idxTest);
end