Skip to content

Commit 385f836

Browse files
Merge branch 'main' into deepsource-transform-8eabe43c
2 parents f1457c7 + 02c3dac commit 385f836

File tree

8 files changed

+196
-2
lines changed

8 files changed

+196
-2
lines changed

docs/anexos.pdf

262 KB
Binary file not shown.
185 KB
Loading
192 KB
Loading
79.5 KB
Loading

docs/tex/D_Manual_programador.tex

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,17 @@ \subsubsection{Travis-CI}
285285
\imagenRuta{../img/anexos/manual-programador/Travis-CI-UBUMLaaS}{Travis-CI.}{Travis-CI-UBUMLaaS}
286286

287287
\subsection{Pruebas del sistema}
288-
Intro \\ (En desarrollo)
289-
Tal y como se ha descrito, \texttt{UBUMLaaS} es un \textit{software} que ha sufrido un cambio de diseño de grandes dimensiones, por lo que las pruebas de integración continua previas que existían han dejado de ser funcionales, debido a que únicamente comprobaban la interacción del usuario con la plataforma a través de un navegador.
288+
Las pruebas del sistema se encuentran dentro de los trabajos futuros que debe seguir la aplicación.
289+
290+
Tal y como se ha descrito, \texttt{UBUMLaaS} es un \textit{software} que ha sufrido un cambio de diseño de grandes dimensiones, por lo que las pruebas de integración continua previas que existían han dejado de ser funcionales. La problemática que surge con las existentes es que no eran pruebas sobre el \textit{backend} de la aplicación, sino la interacción del usuario (mediante el uso de \textit{Selenium}) con el \textit{frontend}.
291+
292+
Es por ello que, al haberse hecho <<de cero>> toda la interfaz de la aplicación web, literalmente, no existe ninguna referencia de las antiguas que las pruebas existentes puedan reutilizar.
293+
294+
Debido a esta problemática, y con el fin de obtener un sistema estable, se ha seleccionado a un grupo de personas de edades comprendidas entre 18 y 55 años, profesionales de mecánica y electrónica, medicina, informática y estudiantes del grado de otras universidades españolas; con el fin de que dado un \href{https://github.com/dpr1005/Semisupervised-learning-and-instance-selection-methods/blob/917d49bcc9d7f1a4825225414b246023bfa2ea7b/docs/misc/survey_steps.pdf}{documento} relativamente sencillo, puedan hacer uso de todo el sistema, y sean estos los que reporten en un \href{https://forms.gle/eZUWmT5GNahqYVVa6}{formulario de \texttt{Google}} sus impresiones y resultados. Está preparado para que se vaya leyendo el documento, probando la aplicación y posteriormente rellenando el formulario, de forma que todo sea un proceso auto-guiado.
295+
296+
Gracias a estas respuestas, se han podido encontrar \textit{bugs} existentes en la aplicación que no permitían trabajar correctamente con ella. El más importante de todo y el cual posee su propia \href{https://github.com/dpr1005/UBUMLaaS/issues/101}{\textit{issue}}, es el desfase existente entre los algoritmos de \texttt{Scikit-Learn} de la versión 0.21 (la utilizada previamente) y la actual, la 0.24. Numerosos algoritmos han sido modificados en su parametrización y por ende en \texttt{UBUMLaaS} no se podían utilizar.
297+
298+
Durante algunos meses de desarrollo del proyecto \texttt{Travis-CI} funcionó correctamente pero la propia herramienta sufrió una actualización a finales de marzo y dejó de ser funcional, resultando en numerosos \textit{commits} marcados como erróneos, pero tal y como se aprecia en los propios \textit{logs} de Travis, nunca se llegó a testar el código, sino que en la configuración de la máquina remota <<rompía>>.
290299

291300
\clearpage
292301
\section{IS-SSL}
@@ -481,3 +490,47 @@ \subsubsection{Sonar Cloud}
481490
\imagenRuta{../img/anexos/manual-programador/SonarCloud-IS-SSL}{SonarCloud.}{SonarCloud-IS-SSL}
482491

483492
\subsection{Pruebas del sistema}
493+
494+
En esta sección se van a describir las pruebas que poseen las bibliotecas.
495+
496+
Las pruebas son realmente sencillas, ya que los propios algoritmos no poseen muchas disyunciones. Es por ello que el conjunto de pruebas codificado está compuesto de pruebas unitarias para cada algoritmo programado, permitiendo comprobar tanto que las entradas son correctas, como sus salidas. En el caso de los algoritmos de selección de instancias se asegura que las instancias recuperadas pertenecen al conjunto de datos de entrada, y que no son más que las que se introdujeron en primera instancia. De tal manera que en caso de que los algoritmos se modifiquen, el filtrado lo sigan realizando. La prueba base se puede visualizar en la Figura~\ref{fig:base-test-is}.
497+
498+
Para la biblioteca de algoritmos de aprendizaje semi-supervisado se poseen también pruebas unitarias para todos y cada uno de ellos, la prueba base se puede visualizar en~\ref{fig:base-test-ssl}. En ellas se comprueban:
499+
\begin{itemize}
500+
\tightlist
501+
\item Tipo de objeto de entrada.
502+
\item Instanciación con mediante diferentes parámetros, tanto por defecto como mediante uso de diccionarios.
503+
\item Entrenamiento del propio algoritmo (\texttt{fit}).
504+
\item Predicción usando el modelo, \texttt{predict}.
505+
\item Las etiquetas devueltas como resultado de la predicción existen en el conjunto de entrenamiento, no se ha inventado ninguna.
506+
\end{itemize}
507+
508+
509+
\imagenFlotante{../img/anexos/manual-programador/base-tests-is}{Prueba base para algoritmos de selección de instancias.}{base-test-is}
510+
\imagenFlotante{../img/anexos/manual-programador/base-tests-ssl}{Prueba base para algoritmos de aprendizaje semi-supervisado.}{base-test-ssl}
511+
\begin{figure}
512+
\centering
513+
\includegraphics[width=0.5\textwidth]{../img/anexos/manual-programador/tests-superados-is-ssl}
514+
\caption{Prueba base para algoritmos de aprendizaje semi-supervisado.}\label{fig:tests-superados-is-ssl}
515+
516+
\end{figure}
517+
518+
Además, se ha codificado una prueba para asegurar que se siguen leyendo los ficheros \texttt{ARFF} correctamente.
519+
520+
El resultado de las ejecuciones se puede ver la Figura~\ref{fig:tests-superados-is-ssl}.
521+
522+
523+
524+
525+
526+
527+
528+
529+
530+
531+
532+
533+
534+
535+
536+

tests/test_InstanceSelection.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,36 @@
1515

1616

1717
def to_dataframe(y):
18+
"""
19+
If the input is not a dataframe, convert it to a dataframe
20+
21+
:param y: The target variable
22+
:return: A dataframe
23+
"""
1824
if not isinstance(y, pd.DataFrame):
1925
return pd.DataFrame(y)
2026

2127

2228
@pytest.fixture
2329
def iris_dataset():
30+
"""
31+
It loads the iris dataset, converts the target variable to a dataframe, and
32+
returns the data and target
33+
:return: The dataframe of the features and the dataframe of the labels
34+
"""
2435
x, y = load_iris(return_X_y=True, as_frame=True)
2536
y = to_dataframe(y)
2637
return x, y
2738

2839

2940
@pytest.fixture
3041
def iris_dataset_ss():
42+
"""
43+
It loads the iris dataset, randomly selects 30% of the data points to be
44+
unlabeled, and returns the labeled and unlabeled data
45+
:return: The original dataframe, the original labels, the complete
46+
dataframe, and the complete labels.
47+
"""
3148
x, y = load_iris(return_X_y=True, as_frame=True)
3249
y = to_dataframe(y)
3350
li = list(set(range(x.shape[0])))
@@ -45,6 +62,16 @@ def iris_dataset_ss():
4562

4663

4764
def base(x, y, algorithm, params=None):
65+
"""
66+
It takes in a dataframe of features, a dataframe of labels, an algorithm,
67+
and a dictionary of parameters. It then creates a model using the
68+
algorithm and parameters, and filters the data using the model
69+
70+
:param x: The input dataframe
71+
:param y: The target variable
72+
:param algorithm: The algorithm to use
73+
:param params: a dictionary of parameters to pass to the algorithm
74+
"""
4875
assert isinstance(x, pd.DataFrame) and isinstance(y, pd.DataFrame)
4976
model = algorithm(**params) if params is not None else algorithm()
5077
x_filtered, y_filtered = model.filter(x, y)
@@ -57,46 +84,91 @@ def base(x, y, algorithm, params=None):
5784

5885

5986
def test_enn_original(iris_dataset):
87+
"""
88+
It tests the ENN algorithm on the iris dataset
89+
90+
:param iris_dataset: This is the dataset to use
91+
"""
6092
x, y = iris_dataset
6193
base(x, y, ENN, {"nearest_neighbors": 3, "power_parameter": 2})
6294

6395

6496
def test_cnn(iris_dataset):
97+
"""
98+
It tests the CNN algorithm on the iris dataset
99+
100+
:param iris_dataset: This is the dataset to use
101+
"""
65102
x, y = iris_dataset
66103
base(x, y, CNN)
67104

68105

69106
def test_rnn(iris_dataset):
107+
"""
108+
It tests the RNN algorithm on the iris dataset
109+
110+
:param iris_dataset: This is the dataset to use
111+
"""
70112
x, y = iris_dataset
71113
base(x, y, RNN)
72114

73115

74116
def test_icf(iris_dataset):
117+
"""
118+
It tests the ICF algorithm on the iris dataset
119+
120+
:param iris_dataset: This is the dataset to use
121+
"""
75122
x, y = iris_dataset
76123
base(x, y, ICF, {"nearest_neighbors": 3, "power_parameter": 2})
77124

78125

79126
def test_mss(iris_dataset):
127+
"""
128+
It tests the MSS algorithm on the iris dataset
129+
130+
:param iris_dataset: This is the dataset to use
131+
"""
80132
x, y = iris_dataset
81133
base(x, y, MSS)
82134

83135

84136
def test_drop3(iris_dataset):
137+
"""
138+
It tests the DROP3 algorithm on the iris dataset
139+
140+
:param iris_dataset: This is the dataset to use
141+
"""
85142
x, y = iris_dataset
86143
base(x, y, DROP3, {"nearest_neighbors": 3, "power_parameter": 2})
87144

88145

89146
def test_local_sets_lssm(iris_dataset):
147+
"""
148+
It tests the LSSm algorithm on the iris dataset
149+
150+
:param iris_dataset: This is the dataset to use
151+
"""
90152
x, y = iris_dataset
91153
base(x, y, LSSm)
92154

93155

94156
def test_local_sets_lsbo(iris_dataset):
157+
"""
158+
It tests the LSBo algorithm on the iris dataset
159+
160+
:param iris_dataset: This is the dataset to use
161+
"""
95162
x, y = iris_dataset
96163
base(x, y, LSBo)
97164

98165

99166
def test_enn_ss(iris_dataset_ss):
167+
"""
168+
It tests the safe ENN algorithm on the iris dataset
169+
170+
:param iris_dataset: This is the dataset to use
171+
"""
100172
(
101173
original,
102174
original_labels,
@@ -124,6 +196,13 @@ def test_enn_ss(iris_dataset_ss):
124196

125197

126198
def test_different_len(iris_dataset):
199+
"""
200+
It tests that the filter method raises a ValueError if the length of the
201+
input and output dataframes are different
202+
203+
:param iris_dataset: a fixture that returns a tuple of two pandas
204+
DataFrames, one for the features and one for the target
205+
"""
127206
x, y = iris_dataset
128207
y = y.loc[:-1]
129208
model1 = LSSm()

tests/test_SemiSupervised.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919

2020
@pytest.fixture
2121
def digits_dataset_ss():
22+
"""
23+
It loads the digits dataset, splits it into train and test sets, and then
24+
randomly assigns 55% of the training set as unlabeled
25+
:return: x_train, x_test, y_train, y_test, opt_labels
26+
"""
2227
x, y = load_digits(return_X_y=True, as_frame=True)
2328
x = x.to_numpy()
2429
y = y.to_numpy()
@@ -38,6 +43,18 @@ def digits_dataset_ss():
3843

3944

4045
def base(x_train, x_test, y_train, y_test, opt_labels, algorithm, params=None):
46+
"""
47+
It takes in a training and testing set, a list of possible labels, and a
48+
model, and checks the predictions of the model on the testing set
49+
50+
:param x_train: The training data
51+
:param x_test: The test data
52+
:param y_train: The training labels
53+
:param y_test: the actual labels of the test set
54+
:param opt_labels: the set of labels that the model can predict
55+
:param algorithm: the algorithm to use
56+
:param params: a dictionary of parameters to pass to the algorithm
57+
"""
4158
assert isinstance(x_train, pd.DataFrame) and isinstance(
4259
y_train, pd.DataFrame)
4360
assert isinstance(x_test, pd.DataFrame) and isinstance(
@@ -51,6 +68,11 @@ def base(x_train, x_test, y_train, y_test, opt_labels, algorithm, params=None):
5168

5269

5370
def test_co_training(digits_dataset_ss):
71+
"""
72+
It tests the Co-Training algorithm on the digits dataset
73+
74+
:param digits_dataset_ss: The dataset we're using
75+
"""
5476
x_train, x_test, y_train, y_test, opt_labels = digits_dataset_ss
5577
base(
5678
x_train,
@@ -106,6 +128,11 @@ def test_co_training(digits_dataset_ss):
106128

107129

108130
def test_tri_training(digits_dataset_ss):
131+
"""
132+
It tests the Tri-Training algorithm on the digits dataset
133+
134+
:param digits_dataset_ss: the dataset we're using
135+
"""
109136
x_train, x_test, y_train, y_test, opt_labels = digits_dataset_ss
110137
base(
111138
x_train,
@@ -123,6 +150,11 @@ def test_tri_training(digits_dataset_ss):
123150

124151

125152
def test_demo_co_learning(digits_dataset_ss):
153+
"""
154+
It tests the Democratic Co-Learning algorithm on the digits dataset
155+
156+
:param digits_dataset_ss: The dataset we're using
157+
"""
126158
x_train, x_test, y_train, y_test, opt_labels = digits_dataset_ss
127159
base(x_train, x_test, y_train, y_test, opt_labels, DemocraticCoLearning)
128160
base(
@@ -141,11 +173,25 @@ def test_demo_co_learning(digits_dataset_ss):
141173

142174

143175
def test_density_peaks(digits_dataset_ss):
176+
"""
177+
It takes the training and testing data, and the optimal labels, and runs the
178+
STDPNF algorithm on it
179+
180+
:param digits_dataset_ss: a tuple of (x_train, x_test, y_train, y_test,
181+
opt_labels)
182+
"""
144183
x_train, x_test, y_train, y_test, opt_labels = digits_dataset_ss
145184
base(x_train, x_test, y_train, y_test, opt_labels, STDPNF)
146185

147186

148187
def test_density_peaks_filtering(digits_dataset_ss):
188+
"""
189+
It tests that the `filtering` option works as expected in the STDPNF
190+
algorithm
191+
192+
:param digits_dataset_ss: a fixture that returns a tuple of (x_train,
193+
x_test, y_train, y_test, opt_labels)
194+
"""
149195
x_train, x_test, y_train, y_test, opt_labels = digits_dataset_ss
150196
with pytest.raises(AttributeError):
151197
base(x_train, x_test, y_train, y_test,
@@ -177,6 +223,12 @@ def test_density_peaks_filtering(digits_dataset_ss):
177223

178224

179225
def test_different_len(digits_dataset_ss):
226+
"""
227+
It tests that if the length of the input and output are different, then the
228+
model will raise a ValueError
229+
230+
:param digits_dataset_ss: a tuple of (x, x_test, y, y_test, y_pred)
231+
"""
180232
x, _, y, _, _ = digits_dataset_ss
181233
co = CoTraining()
182234
tri = TriTraining()

tests/test_utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,20 @@
1414

1515
@pytest.fixture
1616
def arff_path_file():
17+
"""
18+
It returns the path to the iris dataset in the datasets folder
19+
:return: The path to the iris.arff file
20+
"""
1721
return join("datasets", "iris.arff")
1822

1923

2024
def test_arff_data(arff_path_file):
25+
"""
26+
`arff_data` loads an arff file into a `Bunch` object, which is a
27+
dictionary-like object.
28+
29+
:param arff_path_file: The path to the arff file
30+
"""
2131
dataset = arff_data(arff_path_file)
2232
assert isinstance(dataset, Bunch)
2333
dataset1 = arff_data(arff_path_file, ["a", "b", "c", "d"])

0 commit comments

Comments
 (0)