emanoelopes commited on
Commit
e61791a
·
1 Parent(s): 7f1cd53

Geração da planilha, correções

Browse files
oulad.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:db8836a5c6229a0dd544e988ce90f42fed169d1b2febe9a30baff3770ee4f0d8
3
- size 142813
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6c040f4a216fca8105d4553f2a598f5bb8d9a5d685bf8bbece704e881fd56fe7
3
+ size 143089
template_unificado_features.xlsx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ff058a3d3b447fb6723357141f549d15f445f5c915c6f0f861a6d95ba291e288
3
+ size 5213
uci.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:51bca3898081f4268a3cb39e9df482bdfcb4afaa092cfbc4c06f4e228a68808a
3
- size 3176038
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d3db46da97fc1e891182b22caeba81d64b48cc5ea7922f2f624c9973c5f352de
3
+ size 3176212
webapp/home.py CHANGED
@@ -29,21 +29,21 @@ criar_sidebar_landpage()
29
  st.title("📊 Sistema de Análise de Dados Educacionais")
30
  st.markdown("### Análise Inteligente com IA")
31
 
32
- # Seção 1: Geração do Template
33
  st.markdown("## 📥 Passo 1: Baixe o Template")
34
  st.markdown("""
35
  O template inclui as **2 features mais importantes** identificadas em:
36
- - **UCI**: Escolas públicas portuguesas
37
- - **OULAD**: Plataforma de aprendizado online
38
  """)
39
 
40
  col1, col2 = st.columns([2, 1])
41
  with col1:
42
  st.markdown("""
43
  **Como usar o Template Unificado:**
44
- 1. Baixe o template Excel com as features mais importantes dos datasets UCI e OULAD
45
  2. Preencha o template com seus dados (incluindo o nome do aluno)
46
- 3. Mantenha a coluna 'resultado_final' com os resultados esperados
47
  4. Faça upload do template preenchido para análise automática
48
 
49
  **Vantagens do Template Unificado:**
@@ -60,30 +60,34 @@ with col2:
60
  - Coluna de resultado final
61
  """)
62
 
63
- if st.button("📥 Gerar Template Unificado", type="primary"):
64
- with st.spinner("Gerando template..."):
65
- df_template = gerar_template_unificado()
 
 
 
 
 
66
 
67
- if not df_template.empty:
68
- st.session_state.template_downloaded = True
69
- feature_cols = [col for col in df_template.columns if col not in ['nome_aluno', 'resultado_final']]
70
- st.success(f"✅ Template unificado gerado com sucesso! Inclui {len(feature_cols)} features: {', '.join(feature_cols)}")
71
-
72
- st.markdown("**Preview do Template Unificado:**")
73
- st.dataframe(df_template.head(), use_container_width=True)
74
-
75
- # Download
76
- excel_data = converter_template_para_excel(df_template)
77
- if excel_data:
78
- st.download_button(
79
- "⬇️ Baixar Template Excel",
80
- data=excel_data,
81
- file_name="template_analise_educacional.xlsx",
82
- mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
83
- key='download_unified_template'
84
- )
85
- else:
86
- st.error("Erro ao gerar template unificado. Verifique se os dados estão carregados.")
87
 
88
  # Seção 2: Upload e Análise
89
  st.markdown("## 📤 Passo 2: Envie o Template Preenchido")
 
29
  st.title("📊 Sistema de Análise de Dados Educacionais")
30
  st.markdown("### Análise Inteligente com IA")
31
 
32
+ # Seção 1: Download do Template
33
  st.markdown("## 📥 Passo 1: Baixe o Template")
34
  st.markdown("""
35
  O template inclui as **2 features mais importantes** identificadas em:
36
+ - **UCI**: Escolas públicas portuguesas (nota_2bim, faltas)
37
+ - **OULAD**: Plataforma de aprendizado online (pontuacao, regiao)
38
  """)
39
 
40
  col1, col2 = st.columns([2, 1])
41
  with col1:
42
  st.markdown("""
43
  **Como usar o Template Unificado:**
44
+ 1. Baixe o template Excel pré-gerado com as features mais importantes
45
  2. Preencha o template com seus dados (incluindo o nome do aluno)
46
+ 3. Use escala 0-10 para 'resultado_final' (padrão brasileiro)
47
  4. Faça upload do template preenchido para análise automática
48
 
49
  **Vantagens do Template Unificado:**
 
60
  - Coluna de resultado final
61
  """)
62
 
63
+ # Botão para download do template pré-gerado
64
+ if st.button("📥 Baixar Template Unificado", type="primary"):
65
+ import os
66
+
67
+ # Verificar se o arquivo existe
68
+ template_path = "template_unificado_features.xlsx"
69
+ if os.path.exists(template_path):
70
+ st.session_state.template_downloaded = True
71
 
72
+ # Carregar e mostrar preview
73
+ df_template = pd.read_excel(template_path)
74
+ feature_cols = [col for col in df_template.columns if col not in ['nome_aluno', 'resultado_final']]
75
+ st.success(f"✅ Template unificado disponível! Inclui {len(feature_cols)} features: {', '.join(feature_cols)}")
76
+
77
+ st.markdown("**Preview do Template Unificado:**")
78
+ st.dataframe(df_template.head(), use_container_width=True)
79
+
80
+ # Download do arquivo
81
+ with open(template_path, "rb") as file:
82
+ st.download_button(
83
+ "⬇️ Baixar Template Excel",
84
+ data=file.read(),
85
+ file_name="template_analise_educacional.xlsx",
86
+ mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
87
+ key='download_unified_template'
88
+ )
89
+ else:
90
+ st.error("❌ Template não encontrado. Execute o sistema para gerar o template.")
 
91
 
92
  # Seção 2: Upload e Análise
93
  st.markdown("## 📤 Passo 2: Envie o Template Preenchido")
webapp/src/utilidades.py CHANGED
@@ -1254,9 +1254,15 @@ def gerar_template_unificado() -> pd.DataFrame:
1254
  df_importance_uci = calcular_feature_importance_uci()
1255
  top_features_uci = df_importance_uci.nlargest(2, 'importance')['feature'].tolist() if not df_importance_uci.empty else []
1256
 
1257
- # Get TOP 2 features from OULAD (não 3!)
1258
  df_importance_oulad = calcular_feature_importance_oulad()
1259
- top_features_oulad = df_importance_oulad.nlargest(2, 'importance')['feature'].tolist() if not df_importance_oulad.empty else []
 
 
 
 
 
 
1260
 
1261
  # Build template with name field first
1262
  template_data = {'nome_aluno': [''] * 10}
@@ -1295,7 +1301,7 @@ def gerar_template_unificado() -> pd.DataFrame:
1295
  if col == 'nome_aluno':
1296
  continue
1297
  elif col == 'resultado_final':
1298
- df_template.loc[0, col] = 'Pass'
1299
  elif 'reprovacoes' in col or 'faltas' in col or 'tentativas' in col:
1300
  df_template.loc[0, col] = 0
1301
  elif 'nota' in col or 'pontuacao' in col:
@@ -1386,6 +1392,14 @@ def validar_template_usuario(df_usuario: pd.DataFrame, df_template: pd.DataFrame
1386
  if 'resultado_final' not in df_usuario.columns:
1387
  return False, "Coluna 'resultado_final' não encontrada no arquivo"
1388
 
 
 
 
 
 
 
 
 
1389
  # Verificar se tem a coluna nome_aluno (para template unificado)
1390
  if 'nome_aluno' not in df_usuario.columns:
1391
  return False, "Coluna 'nome_aluno' não encontrada no arquivo"
@@ -1435,7 +1449,8 @@ def realizar_eda_automatica(df_usuario: pd.DataFrame) -> dict:
1435
  X = df_usuario.drop([target_col, 'nome_aluno'], axis=1, errors='ignore')
1436
 
1437
  # Detectar tipo de problema (regressão vs classificação)
1438
- is_regression = pd.api.types.is_numeric_dtype(y) and y.nunique() > 10
 
1439
 
1440
  # Dividir dados
1441
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
@@ -1567,8 +1582,8 @@ def realizar_analise_completa(df_usuario: pd.DataFrame) -> dict:
1567
  # Distribuições
1568
  resultados['graficos']['distribuicoes'] = criar_graficos_distribuicao(df_usuario)
1569
 
1570
- # Comparações
1571
- resultados['graficos']['comparacoes'] = criar_graficos_comparacao(df_usuario)
1572
 
1573
  return resultados
1574
 
@@ -1588,17 +1603,18 @@ def criar_graficos_distribuicao(df_usuario: pd.DataFrame) -> dict:
1588
  if 'resultado_final' in df_usuario.columns:
1589
  fig, ax = plt.subplots(figsize=(10, 6))
1590
 
1591
- # Traduzir valores
1592
  df_traduzido = df_usuario.copy()
1593
- df_traduzido['resultado_final'] = df_traduzido['resultado_final'].map({
1594
- 'Pass': 'Aprovados',
1595
- 'Fail': 'Reprovados',
1596
- 'Distinction': 'Com Distinção'
1597
- })
 
1598
 
1599
- df_traduzido['resultado_final'].value_counts().plot(kind='bar', ax=ax, color=['#28a745', '#dc3545', '#ffc107'])
1600
  ax.set_title('Distribuição de Resultados da Turma', fontsize=16, fontweight='bold')
1601
- ax.set_xlabel('Resultado Final')
1602
  ax.set_ylabel('Quantidade de Alunos')
1603
  ax.tick_params(axis='x', rotation=45)
1604
 
@@ -1615,69 +1631,100 @@ def criar_graficos_distribuicao(df_usuario: pd.DataFrame) -> dict:
1615
  st.error(f"Erro ao criar gráficos de distribuição: {e}")
1616
  return {}
1617
 
1618
- def criar_graficos_comparacao(df_usuario: pd.DataFrame) -> dict:
1619
- """Cria gráficos de comparação entre aprovados e reprovados"""
1620
  try:
1621
  import matplotlib.pyplot as plt
1622
- import seaborn as sns
 
1623
 
1624
  graficos = {}
1625
 
1626
- if 'resultado_final' in df_usuario.columns:
1627
- # Traduzir resultado_final
1628
- df_traduzido = df_usuario.copy()
1629
- df_traduzido['resultado_final'] = df_traduzido['resultado_final'].map({
1630
- 'Pass': 'Aprovados',
1631
- 'Fail': 'Reprovados'
1632
- })
1633
-
1634
- # Calcular médias por grupo
1635
- medias = df_traduzido.groupby('resultado_final').agg({
1636
- 'faltas': 'mean',
1637
- 'nota_2bim': 'mean',
1638
- 'cliques_plataforma': 'mean',
1639
- 'pontuacao_atividades': 'mean'
1640
- }).round(2)
1641
 
1642
- # Criar gráfico de comparação
1643
- fig, axes = plt.subplots(2, 2, figsize=(15, 10))
1644
- fig.suptitle('Comparação: Aprovados vs Reprovados', fontsize=16, fontweight='bold')
 
 
 
1645
 
1646
- # Gráfico 1: Faltas
1647
- if 'faltas' in medias.columns:
1648
- medias['faltas'].plot(kind='bar', ax=axes[0,0], color=['#28a745', '#dc3545'])
1649
- axes[0,0].set_title('Média de Faltas')
1650
- axes[0,0].set_ylabel('Número de Faltas')
1651
- axes[0,0].tick_params(axis='x', rotation=0)
1652
 
1653
- # Gráfico 2: Notas
1654
- if 'nota_2bim' in medias.columns:
1655
- medias['nota_2bim'].plot(kind='bar', ax=axes[0,1], color=['#28a745', '#dc3545'])
1656
- axes[0,1].set_title('Média das Notas')
1657
- axes[0,1].set_ylabel('Nota (0-10)')
1658
- axes[0,1].tick_params(axis='x', rotation=0)
1659
 
1660
- # Gráfico 3: Cliques
1661
- if 'cliques_plataforma' in medias.columns:
1662
- medias['cliques_plataforma'].plot(kind='bar', ax=axes[1,0], color=['#28a745', '#dc3545'])
1663
- axes[1,0].set_title('Média de Cliques na Plataforma')
1664
- axes[1,0].set_ylabel('Número de Cliques')
1665
- axes[1,0].tick_params(axis='x', rotation=0)
1666
 
1667
- # Gráfico 4: Pontuação
1668
- if 'pontuacao_atividades' in medias.columns:
1669
- medias['pontuacao_atividades'].plot(kind='bar', ax=axes[1,1], color=['#28a745', '#dc3545'])
1670
- axes[1,1].set_title('Média de Pontuação nas Atividades')
1671
- axes[1,1].set_ylabel('Pontuação (0-100)')
1672
- axes[1,1].tick_params(axis='x', rotation=0)
1673
-
1674
- plt.tight_layout()
1675
- graficos['comparacao_aprovados_reprovados'] = fig
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1676
 
1677
  return graficos
1678
 
1679
  except Exception as e:
1680
- st.error(f"Erro ao criar gráficos de comparação: {e}")
1681
  return {}
1682
 
1683
  def exibir_resultados_com_ia(resultados: dict, df_usuario: pd.DataFrame):
@@ -1691,7 +1738,7 @@ def exibir_resultados_com_ia(resultados: dict, df_usuario: pd.DataFrame):
1691
  with col1:
1692
  st.metric("Total de Alunos", len(df_usuario))
1693
  with col2:
1694
- taxa_aprovacao = (df_usuario['resultado_final'] == 'Pass').mean() * 100
1695
  st.metric("Taxa de Aprovação", f"{taxa_aprovacao:.1f}%")
1696
  with col3:
1697
  st.metric("Features Analisadas", len(df_usuario.columns) - 2)
@@ -1705,8 +1752,9 @@ def exibir_resultados_com_ia(resultados: dict, df_usuario: pd.DataFrame):
1705
  # Interpretação via OpenAI
1706
  contexto = {
1707
  'total_alunos': len(df_usuario),
1708
- 'aprovados': (df_usuario['resultado_final'] == 'Pass').sum(),
1709
- 'reprovados': (df_usuario['resultado_final'] == 'Fail').sum()
 
1710
  }
1711
 
1712
  # Tentar usar OpenAI se disponível
@@ -1744,9 +1792,50 @@ def exibir_resultados_com_ia(resultados: dict, df_usuario: pd.DataFrame):
1744
  """
1745
  st.info(f"💡 **Interpretação**: {interpretacao}")
1746
 
1747
- # 4. Comparação por Aluno
1748
- st.markdown("### 👥 Análise Individual")
1749
- st.dataframe(df_usuario)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1750
 
1751
  def criar_grafico_correlacao_traduzido(corr_matrix: pd.DataFrame):
1752
  """Cria heatmap de correlação com rótulos traduzidos"""
 
1254
  df_importance_uci = calcular_feature_importance_uci()
1255
  top_features_uci = df_importance_uci.nlargest(2, 'importance')['feature'].tolist() if not df_importance_uci.empty else []
1256
 
1257
+ # Get TOP features from OULAD, excluding temporal features
1258
  df_importance_oulad = calcular_feature_importance_oulad()
1259
+ if not df_importance_oulad.empty:
1260
+ # Exclude temporal features that don't make sense for regular school periods
1261
+ temporal_features = ['date_registration', 'date_unregistration']
1262
+ df_filtered = df_importance_oulad[~df_importance_oulad['feature'].isin(temporal_features)]
1263
+ top_features_oulad = df_filtered.nlargest(2, 'importance')['feature'].tolist()
1264
+ else:
1265
+ top_features_oulad = []
1266
 
1267
  # Build template with name field first
1268
  template_data = {'nome_aluno': [''] * 10}
 
1301
  if col == 'nome_aluno':
1302
  continue
1303
  elif col == 'resultado_final':
1304
+ df_template.loc[0, col] = 7.5 # Exemplo de nota 0-10 (padrão brasileiro)
1305
  elif 'reprovacoes' in col or 'faltas' in col or 'tentativas' in col:
1306
  df_template.loc[0, col] = 0
1307
  elif 'nota' in col or 'pontuacao' in col:
 
1392
  if 'resultado_final' not in df_usuario.columns:
1393
  return False, "Coluna 'resultado_final' não encontrada no arquivo"
1394
 
1395
+ # Verificar se resultado_final está na escala 0-10 (padrão brasileiro)
1396
+ resultado_values = df_usuario['resultado_final'].dropna()
1397
+ if len(resultado_values) > 0:
1398
+ if not pd.api.types.is_numeric_dtype(resultado_values):
1399
+ return False, "Coluna 'resultado_final' deve conter valores numéricos (0-10)"
1400
+ if (resultado_values < 0).any() or (resultado_values > 10).any():
1401
+ return False, "Valores em 'resultado_final' devem estar entre 0 e 10"
1402
+
1403
  # Verificar se tem a coluna nome_aluno (para template unificado)
1404
  if 'nome_aluno' not in df_usuario.columns:
1405
  return False, "Coluna 'nome_aluno' não encontrada no arquivo"
 
1449
  X = df_usuario.drop([target_col, 'nome_aluno'], axis=1, errors='ignore')
1450
 
1451
  # Detectar tipo de problema (regressão vs classificação)
1452
+ # Sempre tratar como regressão se for numérico (escala 0-10)
1453
+ is_regression = pd.api.types.is_numeric_dtype(y)
1454
 
1455
  # Dividir dados
1456
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
 
1582
  # Distribuições
1583
  resultados['graficos']['distribuicoes'] = criar_graficos_distribuicao(df_usuario)
1584
 
1585
+ # Gráfico radar (será criado com seleção de aluno)
1586
+ resultados['graficos']['radar'] = criar_grafico_radar_aluno(df_usuario)
1587
 
1588
  return resultados
1589
 
 
1603
  if 'resultado_final' in df_usuario.columns:
1604
  fig, ax = plt.subplots(figsize=(10, 6))
1605
 
1606
+ # Criar bins para notas numéricas (escala 0-10)
1607
  df_traduzido = df_usuario.copy()
1608
+ df_traduzido['faixa_nota'] = pd.cut(
1609
+ df_traduzido['resultado_final'],
1610
+ bins=[0, 5, 7, 10],
1611
+ labels=['Insuficiente (0-5)', 'Regular (5-7)', 'Bom (7-10)'],
1612
+ include_lowest=True
1613
+ )
1614
 
1615
+ df_traduzido['faixa_nota'].value_counts().plot(kind='bar', ax=ax, color=['#dc3545', '#ffc107', '#28a745'])
1616
  ax.set_title('Distribuição de Resultados da Turma', fontsize=16, fontweight='bold')
1617
+ ax.set_xlabel('Faixa de Nota')
1618
  ax.set_ylabel('Quantidade de Alunos')
1619
  ax.tick_params(axis='x', rotation=45)
1620
 
 
1631
  st.error(f"Erro ao criar gráficos de distribuição: {e}")
1632
  return {}
1633
 
1634
+ def criar_grafico_radar_aluno(df_usuario: pd.DataFrame, nome_aluno: str = None) -> dict:
1635
+ """Cria gráfico radar comparando aluno individual com média da turma"""
1636
  try:
1637
  import matplotlib.pyplot as plt
1638
+ import numpy as np
1639
+ from math import pi
1640
 
1641
  graficos = {}
1642
 
1643
+ if 'resultado_final' in df_usuario.columns and 'nome_aluno' in df_usuario.columns:
1644
+ # Se não especificado, usar o primeiro aluno como exemplo
1645
+ if nome_aluno is None:
1646
+ nome_aluno = df_usuario['nome_aluno'].iloc[0]
 
 
 
 
 
 
 
 
 
 
 
1647
 
1648
+ # Verificar se o aluno existe
1649
+ aluno_data = df_usuario[df_usuario['nome_aluno'] == nome_aluno]
1650
+ if aluno_data.empty:
1651
+ st.warning(f"Aluno '{nome_aluno}' não encontrado. Usando primeiro aluno como exemplo.")
1652
+ nome_aluno = df_usuario['nome_aluno'].iloc[0]
1653
+ aluno_data = df_usuario.iloc[[0]]
1654
 
1655
+ # Obter dados do aluno selecionado
1656
+ aluno_row = aluno_data.iloc[0]
 
 
 
 
1657
 
1658
+ # Calcular médias da turma (excluindo o aluno selecionado)
1659
+ turma_media = df_usuario[df_usuario['nome_aluno'] != nome_aluno].mean(numeric_only=True)
 
 
 
 
1660
 
1661
+ # Selecionar colunas numéricas para o radar (incluindo resultado_final)
1662
+ colunas_numericas = [col for col in df_usuario.select_dtypes(include=[np.number]).columns
1663
+ if col in aluno_row.index]
 
 
 
1664
 
1665
+ if len(colunas_numericas) >= 3: # Mínimo 3 dimensões para radar
1666
+ # Preparar dados para o radar
1667
+ valores_aluno = [aluno_row[col] for col in colunas_numericas]
1668
+ valores_turma = [turma_media[col] for col in colunas_numericas]
1669
+
1670
+ # Normalizar valores para escala 0-10 (assumindo que as features já estão nessa escala)
1671
+ # Se não estiverem, fazer normalização simples
1672
+ max_val = max(max(valores_aluno), max(valores_turma))
1673
+ if max_val > 10:
1674
+ valores_aluno = [v/max_val*10 for v in valores_aluno]
1675
+ valores_turma = [v/max_val*10 for v in valores_turma]
1676
+
1677
+ # Criar gráfico radar
1678
+ fig, ax = plt.subplots(figsize=(10, 10), subplot_kw=dict(projection='polar'))
1679
+
1680
+ # Ângulos para cada dimensão
1681
+ angles = [n / float(len(colunas_numericas)) * 2 * pi for n in range(len(colunas_numericas))]
1682
+ angles += angles[:1] # Fechar o círculo
1683
+
1684
+ # Adicionar valores para fechar o círculo
1685
+ valores_aluno += valores_aluno[:1]
1686
+ valores_turma += valores_turma[:1]
1687
+
1688
+ # Plotar dados
1689
+ ax.plot(angles, valores_aluno, 'o-', linewidth=2, label=f'{nome_aluno}', color='#2E86AB', markersize=8)
1690
+ ax.fill(angles, valores_aluno, alpha=0.25, color='#2E86AB')
1691
+
1692
+ ax.plot(angles, valores_turma, 'o-', linewidth=2, label='Média da Turma', color='#A23B72', markersize=8)
1693
+ ax.fill(angles, valores_turma, alpha=0.25, color='#A23B72')
1694
+
1695
+ # Configurar eixos com traduções
1696
+ traducao_rotulos = {
1697
+ 'nota_2bim': 'Nota 2º Bimestre',
1698
+ 'faltas': 'Faltas',
1699
+ 'pontuacao': 'Pontuação',
1700
+ 'resultado_final': 'Nota Final'
1701
+ }
1702
+
1703
+ ax.set_xticks(angles[:-1])
1704
+ ax.set_xticklabels([traducao_rotulos.get(col, col.replace('_', ' ').title()) for col in colunas_numericas])
1705
+ ax.set_ylim(0, 10)
1706
+ ax.set_yticks([2, 4, 6, 8, 10])
1707
+ ax.set_yticklabels(['2', '4', '6', '8', '10'])
1708
+ ax.grid(True)
1709
+
1710
+ # Título e legenda
1711
+ ax.set_title(f'Comparação: {nome_aluno} vs Média da Turma', size=16, fontweight='bold', pad=20)
1712
+ ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.0))
1713
+
1714
+ # Adicionar valores nas pontas
1715
+ for i, (angle, valor_aluno, valor_turma) in enumerate(zip(angles[:-1], valores_aluno[:-1], valores_turma[:-1])):
1716
+ ax.text(angle, valor_aluno + 0.5, f'{valor_aluno:.1f}', ha='center', va='center', fontweight='bold', color='#2E86AB')
1717
+ ax.text(angle, valor_turma - 0.5, f'{valor_turma:.1f}', ha='center', va='center', fontweight='bold', color='#A23B72')
1718
+
1719
+ plt.tight_layout()
1720
+ graficos['radar_comparacao_aluno'] = fig
1721
+ else:
1722
+ st.warning("Não há colunas numéricas suficientes para criar o gráfico radar.")
1723
 
1724
  return graficos
1725
 
1726
  except Exception as e:
1727
+ st.error(f"Erro ao criar gráfico radar: {e}")
1728
  return {}
1729
 
1730
  def exibir_resultados_com_ia(resultados: dict, df_usuario: pd.DataFrame):
 
1738
  with col1:
1739
  st.metric("Total de Alunos", len(df_usuario))
1740
  with col2:
1741
+ taxa_aprovacao = (df_usuario['resultado_final'] >= 5.0).mean() * 100 # Aprovação >= 5.0
1742
  st.metric("Taxa de Aprovação", f"{taxa_aprovacao:.1f}%")
1743
  with col3:
1744
  st.metric("Features Analisadas", len(df_usuario.columns) - 2)
 
1752
  # Interpretação via OpenAI
1753
  contexto = {
1754
  'total_alunos': len(df_usuario),
1755
+ 'aprovados': (df_usuario['resultado_final'] >= 5.0).sum(),
1756
+ 'reprovados': (df_usuario['resultado_final'] < 5.0).sum(),
1757
+ 'media_geral': df_usuario['resultado_final'].mean()
1758
  }
1759
 
1760
  # Tentar usar OpenAI se disponível
 
1792
  """
1793
  st.info(f"💡 **Interpretação**: {interpretacao}")
1794
 
1795
+ # 4. Gráfico Radar - Comparação Individual
1796
+ st.markdown("### 🎯 Análise Individual - Gráfico Radar")
1797
+
1798
+ # Campo de busca para seleção do aluno
1799
+ if 'nome_aluno' in df_usuario.columns:
1800
+ nomes_alunos = sorted(df_usuario['nome_aluno'].unique().tolist()) # Ordem alfabética
1801
+ nome_selecionado = st.selectbox(
1802
+ "Selecione o aluno para análise:",
1803
+ options=nomes_alunos,
1804
+ index=0,
1805
+ help="Escolha um aluno para comparar com a média da turma"
1806
+ )
1807
+
1808
+ # Criar gráfico radar para o aluno selecionado
1809
+ grafico_radar = criar_grafico_radar_aluno(df_usuario, nome_selecionado)
1810
+
1811
+ if 'radar_comparacao_aluno' in grafico_radar:
1812
+ st.pyplot(grafico_radar['radar_comparacao_aluno'])
1813
+
1814
+ # Interpretação do gráfico radar
1815
+ try:
1816
+ from .openai_interpreter import interpretar_grafico
1817
+ contexto_radar = {
1818
+ 'nome_aluno': nome_selecionado,
1819
+ 'total_alunos': len(df_usuario),
1820
+ 'media_turma': df_usuario['resultado_final'].mean()
1821
+ }
1822
+ interpretacao = interpretar_grafico('radar_comparacao', contexto_radar)
1823
+ st.info(f"💡 **Interpretação**: {interpretacao}")
1824
+ except:
1825
+ interpretacao = f"""
1826
+ Este gráfico radar compara o desempenho de {nome_selecionado} com a média da turma.
1827
+ Áreas onde o aluno está acima da média (linha azul acima da rosa) indicam pontos fortes.
1828
+ Áreas abaixo da média podem indicar necessidades de apoio pedagógico.
1829
+ """
1830
+ st.info(f"💡 **Interpretação**: {interpretacao}")
1831
+ else:
1832
+ st.warning("Não foi possível criar o gráfico radar para este aluno.")
1833
+ else:
1834
+ st.warning("Coluna 'nome_aluno' não encontrada nos dados.")
1835
+
1836
+ # 5. Tabela de Dados
1837
+ st.markdown("### 📋 Dados Completos da Turma")
1838
+ st.dataframe(df_usuario, use_container_width=True)
1839
 
1840
  def criar_grafico_correlacao_traduzido(corr_matrix: pd.DataFrame):
1841
  """Cria heatmap de correlação com rótulos traduzidos"""