emanoelopes commited on
Commit
a33b3fa
·
1 Parent(s): b29f868

Pytest e estrutura do projeto

Browse files
.vscode/extensions.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "recommendations": [
3
+ "10nates.ollama-autocoder"
4
+ ]
5
+ }
.vscode/settings.json CHANGED
@@ -1,3 +1,4 @@
1
  {
2
- "continue.remoteConfigServerUrl": ""
 
3
  }
 
1
  {
2
+ "continue.remoteConfigServerUrl": "",
3
+ "CodeGPT.apiKey": "Huggingface"
4
  }
oulad.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:4601482a182ed9a7adaf0e93e3b2d4732e4efbb4d081000003cc0d090990ab0b
3
- size 143341
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d330dea5d2d2d47f67b787298e45bc817a047c6488c2654388ccd7d2f15dec9a
3
+ size 143349
requirements.txt CHANGED
@@ -1,5 +1,3 @@
1
- ansible==7.7.0
2
- ansible-core==2.14.18
3
  anyio==3.6.2
4
  apsw==3.40.0.0
5
  apt-xapian-index==0.49
 
 
 
1
  anyio==3.6.2
2
  apsw==3.40.0.0
3
  apt-xapian-index==0.49
sida.sh CHANGED
@@ -1,4 +1,6 @@
1
  #!/bin/bash
2
 
3
  source ./venv/bin/activate
4
- streamlit run webapp/home.py
 
 
 
1
  #!/bin/bash
2
 
3
  source ./venv/bin/activate
4
+ streamlit run webapp/home.py
5
+
6
+
uci.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:26d42b46a275f435d279686c4ceb62a6c41f36e4012c6c70e15c3d45f422504c
3
- size 3176806
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ff57645cb7ed1d00c72be46f40dd51cd4f7beeef976675b7aa2254cf1d6e3b61
3
+ size 3176814
webapp/home.py CHANGED
@@ -2,6 +2,10 @@ import streamlit as st
2
  import pandas as pd
3
  import seaborn as sns
4
  import matplotlib.pyplot as plt
 
 
 
 
5
 
6
  st.set_page_config(page_title="Dashboard Educacional", layout="wide")
7
 
 
2
  import pandas as pd
3
  import seaborn as sns
4
  import matplotlib.pyplot as plt
5
+ from pathlib import Path
6
+ import os
7
+ import pickle
8
+ import webapp.src.utilidades as utilidades
9
 
10
  st.set_page_config(page_title="Dashboard Educacional", layout="wide")
11
 
webapp/home_1.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import seaborn as sns
4
+ import matplotlib.pyplot as plt
5
+ from pathlib import Path
6
+ import pickle
7
+
8
+ # Configuração da página Streamlit
9
+ st.set_page_config(page_title="Dashboard Educacional", layout="wide")
10
+
11
+ # Funções para carregar dados
12
+ @st.cache_data(show_spinner=False)
13
+ def load_uci_data(pickle_path: str = "uci.pkl") -> pd.DataFrame:
14
+ """Carrega o arquivo pickle com os dados do banco UCI."""
15
+ p = Path(pickle_path)
16
+ if not p.is_file():
17
+ st.warning(f"Arquivo {p} não encontrado.")
18
+ return pd.DataFrame()
19
+
20
+ try:
21
+ with p.open("rb") as f:
22
+ df = pickle.load(f)
23
+ except Exception as e:
24
+ st.error(f"Falha ao ler {p}: {e}")
25
+ return pd.DataFrame()
26
+
27
+ if not isinstance(df, pd.DataFrame):
28
+ st.error(f"O conteúdo de {p} não é um DataFrame.")
29
+ return pd.DataFrame()
30
+
31
+ return df
32
+
33
+ @st.cache_data(show_spinner=False)
34
+ def load_oulad_data(pickle_path: str = "oulad.pkl") -> pd.DataFrame:
35
+ """Carrega o arquivo pickle com os dados do banco OULAD."""
36
+ p = Path(pickle_path)
37
+ if not p.is_file():
38
+ st.warning(f"Arquivo {p} não encontrado.")
39
+ return pd.DataFrame()
40
+
41
+ try:
42
+ with p.open("rb") as f:
43
+ df = pickle.load(f)
44
+ except Exception as e:
45
+ st.error(f"Falha ao ler {p}: {e}")
46
+ return pd.DataFrame()
47
+
48
+ if not isinstance(df, pd.DataFrame):
49
+ st.error(f"O conteúdo de {p} não é um DataFrame.")
50
+ return pd.DataFrame()
51
+
52
+ return df
53
+
54
+ # Carregar dados no estado da sessão ou do usuário
55
+ if "df_uci" not in st.session_state:
56
+ st.session_state.df_uci = load_uci_data("uci.pkl")
57
+
58
+ if "df_oulad" not in st.session_state:
59
+ st.session_state.df_oulad = load_oulad_data("oulad.pkl")
60
+
61
+ # Exibir dados carregados
62
+ st.write("Dados da UCI:")
63
+ st.dataframe(st.session_state.df_uci)
64
+
65
+ st.write("Dados do OULAD:")
66
+ st.dataframe(st.session_state.df_oulad)
67
+
68
+ # Título do dashboard
69
+ st.title("Dashboard de Desempenho Educacional")
70
+
71
+ # Visão geral das métricas
72
+ col1, col2, col3, col4 = st.columns(4)
73
+ col1.metric("Alunos ativos", "1,200")
74
+ col2.metric("Média de notas", "78,5")
75
+ col3.metric("Taxa de abandono", "3,2 %")
76
+ col4.metric("Engajamento médio", "2,3 cliques/dia")
77
+
78
+ # Contexto do dashboard
79
+ st.markdown("""
80
+ Esta página mostra uma visão consolidada dos dados de duas bases públicas:
81
+ - **UCI**: informações de escolas públicas.
82
+ - **OULAD**: plataforma de aprendizado online.
83
+ Essas análises ajudam gestores e professores a identificar áreas de melhoria e a planejar intervenções.
84
+ """)
85
+
86
+ # Distribuição de notas (UCI)
87
+ fig, ax = plt.subplots(figsize=(6,4))
88
+ sns.histplot(st.session_state.df_uci['G3'], bins=20, kde=True, ax=ax)
89
+ ax.set_title("Distribuição de Notas (UCI)")
90
+ st.pyplot(fig)
91
+
92
+ # Distribuição de Cliques (OULAD)
93
+ fig, ax = plt.subplots(figsize=(6,4))
94
+ sns.histplot(st.session_state.df_oulad['clicks'], bins=20, kde=True, ax=ax)
95
+ ax.set_title("Distribuição de Cliques (OULAD)")
96
+ st.pyplot(fig)
97
+
98
+ # Filtros
99
+ periodo = st.selectbox("Período", ["2021", "2022", "2023"])
100
+ genero = st.multiselect("Gênero", ["Masculino", "Feminino", "Outro"])
101
+
102
+ # Tabela de correlação
103
+ corr = st.session_state.df_uci.corr()
104
+ st.dataframe(corr.style.background_gradient(cmap="coolwarm"))
webapp/pages/1_uci.py CHANGED
@@ -62,7 +62,12 @@ with st.sidebar:
62
  "Tipo de Visualização",
63
  ["Box Plot", "Histograma", "Violin Plot"]
64
  )
65
-
 
 
 
 
 
66
  st.markdown("---")
67
  st.markdown("## Informações")
68
  st.write(f"**Número de Instâncias:** {df.shape[0]}")
@@ -305,7 +310,9 @@ plt.clf()
305
  O gráfico indica uma ligeira tendência de queda na nota final conforme o número de faltas aumenta, especialmente a partir da faixa de 11-15 faltas. Estudantes que apresentam menos de 10 faltas alcançam notas máximas e concentram-se entre 10 e 14 pontos. As notas medianas e máximas observadas demonstram uma redução significativa quando superior a 16 faltas.
306
  '''
307
 
308
- st.markdown("## Entendendo as relações das classes utilizando Aprendizado de Máquina")
 
 
309
 
310
  st.markdown("Preparação dos dados para modelos de ML...")
311
  Y = df['G3']
@@ -365,11 +372,6 @@ st.markdown(f"Mean Absolute Error (MAE): {mae:.2f}")
365
  st.markdown(f"Root Mean Squared Error (RMSE): {rmse:.2f}")
366
  st.markdown(f"R-squared (R2): {r2:.2f}")
367
 
368
-
369
- """
370
- ## Importância das classes em relação ao resultado final\
371
- """
372
-
373
  from sklearn.inspection import permutation_importance
374
 
375
  result = permutation_importance(model, X_test, y_test, n_repeats=10, random_state=42, n_jobs=2)
@@ -395,3 +397,16 @@ A análise dos dados mostra que a maioria dos estudantes tem entre 15 e 19 anos,
395
  with open('uci.pkl', 'wb') as f:
396
  pickle.dump(model, f)
397
  f.close()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  "Tipo de Visualização",
63
  ["Box Plot", "Histograma", "Violin Plot"]
64
  )
65
+ st.markdown("---")
66
+ st.markdown("### Experimente")
67
+ analyzer = st.selectbox(
68
+ "Analisador",
69
+ ["UCI EDA", "OULAD EDA"]
70
+ )
71
  st.markdown("---")
72
  st.markdown("## Informações")
73
  st.write(f"**Número de Instâncias:** {df.shape[0]}")
 
310
  O gráfico indica uma ligeira tendência de queda na nota final conforme o número de faltas aumenta, especialmente a partir da faixa de 11-15 faltas. Estudantes que apresentam menos de 10 faltas alcançam notas máximas e concentram-se entre 10 e 14 pontos. As notas medianas e máximas observadas demonstram uma redução significativa quando superior a 16 faltas.
311
  '''
312
 
313
+ """
314
+ ## Importância das classes em relação ao resultado final\
315
+ """
316
 
317
  st.markdown("Preparação dos dados para modelos de ML...")
318
  Y = df['G3']
 
372
  st.markdown(f"Root Mean Squared Error (RMSE): {rmse:.2f}")
373
  st.markdown(f"R-squared (R2): {r2:.2f}")
374
 
 
 
 
 
 
375
  from sklearn.inspection import permutation_importance
376
 
377
  result = permutation_importance(model, X_test, y_test, n_repeats=10, random_state=42, n_jobs=2)
 
397
  with open('uci.pkl', 'wb') as f:
398
  pickle.dump(model, f)
399
  f.close()
400
+
401
+ # PyGWalker
402
+
403
+ import pygwalker as pyg
404
+ from pygwalker.api.streamlit import StreamlitRenderer
405
+
406
+ if "df_uci" in st.session_state:
407
+ df = st.session_state['df_uci']
408
+ walker = pyg.walk(df)
409
+ else:
410
+ st.write("Nenhum dado disponível. Por favor, navegue para a página UCI primeiro.")
411
+
412
+
webapp/pages/2_oulad.py CHANGED
@@ -289,7 +289,7 @@ plt.clf()
289
  a grande maioria dos estudantes obteve o resultado "Pass" (Aprovado), superando vastamente as outras categorias. Os resultados de "Distinction" (Aprovação com mérito), "Withdrawn" (Desistente) e "Fail" (Reprovado) representam uma proporção muito menor do total de alunos, indicando uma alta taxa de sucesso geral.
290
  '''
291
 
292
- st.markdown("## Entendendo as relações das classes utilizando Aprendizado de Máquina")
293
 
294
  st.markdown("Preparação dos dados para modelos de ML...")
295
  Y = merged_df['final_result']
@@ -349,8 +349,6 @@ from sklearn.metrics import confusion_matrix, classification_report
349
  # st.write(classification_report(y_test, predictions, zero_division=0))
350
  # st.write(confusion_matrix(y_test, predictions))
351
 
352
- st.markdown('## Analisando a importância das classes (feature importance)')
353
-
354
  from sklearn.inspection import permutation_importance
355
  import pandas as pd
356
 
 
289
  a grande maioria dos estudantes obteve o resultado "Pass" (Aprovado), superando vastamente as outras categorias. Os resultados de "Distinction" (Aprovação com mérito), "Withdrawn" (Desistente) e "Fail" (Reprovado) representam uma proporção muito menor do total de alunos, indicando uma alta taxa de sucesso geral.
290
  '''
291
 
292
+ st.markdown('## Analisando a importância das classes (feature importance)')
293
 
294
  st.markdown("Preparação dos dados para modelos de ML...")
295
  Y = merged_df['final_result']
 
349
  # st.write(classification_report(y_test, predictions, zero_division=0))
350
  # st.write(confusion_matrix(y_test, predictions))
351
 
 
 
352
  from sklearn.inspection import permutation_importance
353
  import pandas as pd
354
 
webapp/pages/__init__.py ADDED
File without changes
webapp/src/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # src/__init__.py
2
+ from .carregar_dados import carregar_uci_dados, carregar_oulad_dados
webapp/src/carregar_dados.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # src/carregar_dados.py
2
+ import pandas as pd
3
+ from pathlib import Path
4
+ import pickle
5
+
6
+ def carregar_uci_dados(pickle_path: str = "datasets/uci.pkl") -> pd.DataFrame:
7
+ p = Path(pickle_path)
8
+ if not p.is_file():
9
+ raise FileNotFoundError(f"Arquivo {p} não encontrado.")
10
+
11
+ try:
12
+ with p.open("rb") as f:
13
+ df = pickle.load(f)
14
+ except Exception as e:
15
+ raise ValueError(f"Erro ao ler o arquivo {pickle_path}: {e}")
16
+
17
+ if not isinstance(df, pd.DataFrame):
18
+ raise TypeError("O conteúdo do arquivo não é um DataFrame.")
19
+
20
+ return df
21
+
22
+ def carregar_oulad_dados(pickle_path: str = "datasets/oulad.pkl") -> pd.DataFrame:
23
+ p = Path(pickle_path)
24
+ if not p.is_file():
25
+ raise FileNotFoundError(f"Arquivo {p} não encontrado.")
26
+
27
+ try:
28
+ with p.open("rb") as f:
29
+ df = pickle.load(f)
30
+ except Exception as e:
31
+ raise ValueError(f"Erro ao ler o arquivo {pickle_path}: {e}")
32
+
33
+ if not isinstance(df, pd.DataFrame):
34
+ raise TypeError("O conteúdo do arquivo não é um DataFrame.")
35
+
36
+ return df
webapp/src/salvar_resultados.py ADDED
File without changes
webapp/{utilidades.py → src/utilidades.py} RENAMED
@@ -1,9 +1,26 @@
1
  from pathlib import Path
2
  import streamlit as st
3
  import pandas as pd
4
- import os
5
- import pickle
6
 
7
  def leitura_oulad_data():
8
  datasets_path = Path(__file__).parent.parents / 'datasets' / 'oulad_data'
9
  st.write(f"Path dos datasets: {datasets_path}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from pathlib import Path
2
  import streamlit as st
3
  import pandas as pd
 
 
4
 
5
  def leitura_oulad_data():
6
  datasets_path = Path(__file__).parent.parents / 'datasets' / 'oulad_data'
7
  st.write(f"Path dos datasets: {datasets_path}")
8
+
9
+
10
+ # Create visualization selection in sidebar
11
+ with st.sidebar:
12
+ st.markdown("### Escolha o dataset ")
13
+ eda_dataset = st.selectbox(
14
+ "Analise",
15
+ ["UCI EDA", "OULAD EDA"]
16
+ )
17
+
18
+ ### footer
19
+ st.markdown("Mestrado em Tecnologia Educacional - UFC")
20
+
21
+
22
+
23
+ if eda_dataset is 'UCI EDA':
24
+ st.write("UCI EDA")
25
+ else
26
+ st.write("OULAD EDA")
webapp/src/vizualizacoes.py ADDED
File without changes
webapp/tests/test_carregar_dados.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # tests/test_carregar_dados.py
2
+ import pytest
3
+ from webapp/src.carregar_dados import carregar_uci_dados, carregar_oulad_dados
4
+
5
+ def test_carregar_uci_dados():
6
+ df = carregar_uci_dados()
7
+ assert isinstance(df, pd.DataFrame), "O retorno não é um DataFrame"
8
+ # Adicione mais asserções conforme necessário para validar o conteúdo do DataFrame
9
+
10
+ def test_carregar_oulad_dados():
11
+ df = carregar_oulad_dados()
12
+ assert isinstance(df, pd.DataFrame), "O retorno não é um DataFrame"
13
+ # Adicione mais asserções conforme necessário para validar o conteúdo do DataFrame