emanoelopes commited on
Commit
7b4d513
·
1 Parent(s): 5301d26

correcoes

Browse files
oulad.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:7ce19c86fbe8c0ed1b1569792d11eb40143e034280ad2f78ac2e448d58981206
3
- size 143287
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7a411a4319fd99eb32d21e79e9116eb889c3a26a4180281fee94d0d62a311f72
3
+ size 130510
webapp/pages/2_OULAD.py CHANGED
@@ -125,19 +125,6 @@ def show_basic_info(df):
125
  # st.pyplot(fig)
126
 
127
 
128
- # Imputando valores ausentes em 'date_registration' e 'date_unregistration'
129
- # Criar uma cópia explícita do dataframe para evitar SettingWithCopyWarning
130
- df_studentregistration_copy = df_studentregistration.copy()
131
-
132
- mean_date_registration = df_studentregistration_copy['date_registration'].mean()
133
- df_studentregistration_copy['date_unregistration'] = df_studentregistration_copy['date_unregistration'].fillna(df_studentregistration_copy['date_unregistration'].max())
134
- df_studentregistration_copy['date_registration'] = df_studentregistration_copy['date_registration'].fillna(mean_date_registration)
135
-
136
- # Display null values after imputation
137
- print("Null values after imputing date_registration and date_unregistration:")
138
- # st.write(df_studentregistration_copy.isnull().sum())
139
-
140
-
141
  new_vle = df_vle.drop(['week_from','week_to'],axis=1)
142
  show_basic_info(new_vle)
143
 
@@ -151,8 +138,21 @@ show_basic_info(new_studentInfo)
151
  # Criar uma cópia explícita do dataframe para evitar SettingWithCopyWarning
152
  df_student_registration_copy = df_studentregistration.copy()
153
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  mean_date_registration = df_student_registration_copy['date_registration'].mean()
155
- df_student_registration_copy['date_unregistration'] = df_student_registration_copy['date_unregistration'].fillna(df_student_registration_copy['date_unregistration'].max())
156
  df_student_registration_copy['date_registration'] = df_student_registration_copy['date_registration'].fillna(mean_date_registration)
157
 
158
  # Junção dos dados
@@ -170,8 +170,8 @@ st.session_state['merged_df'] = merged_df
170
  # Merge with courses dataframe
171
  merged_df = pd.merge(merged_df, df_courses, on=['code_presentation'], how='inner')
172
 
173
- # Merge with studentRegistration dataframe
174
- merged_df = pd.merge(merged_df, df_studentregistration, on=['code_presentation','id_student'], how='inner')
175
 
176
  # Imputing missing values for numerical columns with the mean
177
  for col in merged_df.select_dtypes(include=np.number).columns:
@@ -233,9 +233,34 @@ Com base no histograma, a maioria dos estudantes obteve notas finais elevadas, c
233
 
234
  st.write('## Distribuição de Atividades por Tipo')
235
  plt.figure(figsize=(10, 6))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  # Contar atividades únicas por tipo (não estudantes únicos, pois é sobre atividades)
237
  atividade_counts = merged_df['activity_type'].value_counts()
238
- sns.barplot(x=atividade_counts.index, y=atividade_counts.values)
 
 
 
239
  plt.title('Distribuição de Atividades por Tipo')
240
  plt.xlabel('Tipo de Atividade')
241
  plt.ylabel('Número de Atividades')
@@ -244,7 +269,7 @@ st.pyplot(plt)
244
  plt.clf()
245
 
246
  '''
247
- A atividade mais realizada é a 'outcontent' com quase o dobro de execuções em relação à segunda posição que é 'forumng'. A distribuição é acentuadamente desigual, com poucas atividades (como "forumng" e "subpage") tendo uso moderado.
248
  '''
249
 
250
 
@@ -290,9 +315,32 @@ A diferença na quantidade entre os gêneros masculino e feminino é algo em tor
290
 
291
  st.write('## Distribuição de Estudantes por Região')
292
  plt.figure(figsize=(10, 6))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  # Contar estudantes únicos por região
294
  regiao_counts = merged_df.groupby('region')['id_student'].nunique().sort_values(ascending=False)
295
- sns.barplot(x=regiao_counts.index, y=regiao_counts.values)
 
 
 
296
  plt.title('Distribuição de Estudantes por Região')
297
  plt.xlabel('Região')
298
  plt.ylabel('Número de Estudantes Únicos')
@@ -301,14 +349,26 @@ st.pyplot(plt)
301
  plt.clf()
302
 
303
  """
304
- As regiões "South West Region" e "South Region" detêm a maior concentração de estudantes, resultando em uma leve predominância do sul da Inglaterra. A distribuição é relativamente decrescente e sem discrepâncias abruptas.
 
305
  """
306
 
307
  st.write('## Distribuição dos Estudantes por Resultado Final')
308
  plt.figure(figsize=(6, 6))
 
 
 
 
 
 
 
 
309
  # Contar estudantes únicos por resultado final
310
  resultado_counts = merged_df.groupby('final_result')['id_student'].nunique().sort_values(ascending=False)
311
- sns.barplot(x=resultado_counts.index, y=resultado_counts.values)
 
 
 
312
  plt.title('Distribuição dos Estudantes por Resultado Final')
313
  plt.xlabel('Resultado Final')
314
  plt.ylabel('Número de Estudantes Únicos')
@@ -316,7 +376,7 @@ st.pyplot(plt)
316
  plt.clf()
317
 
318
  '''
319
- 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.
320
  '''
321
 
322
  st.markdown('## Analisando a importância das classes (feature importance)')
@@ -376,29 +436,52 @@ st.markdown("Modelo treinado com sucesso!")
376
  st.markdown("Avaliando do modelo...")
377
 
378
  predictions = ml_model.predict(X_test)
379
- from sklearn.metrics import confusion_matrix, classification_report
380
-
381
- # st.write(classification_report(y_test, predictions, zero_division=0))
382
- # st.write(confusion_matrix(y_test, predictions))
383
-
384
- from sklearn.inspection import permutation_importance
385
- import pandas as pd
386
 
387
  # Drop rows with NaN in y_test
388
  nan_rows_test = y_test.isnull()
389
  X_test_cleaned = X_test[~nan_rows_test].copy()
390
  y_test_cleaned = y_test[~nan_rows_test].copy()
 
391
 
392
- result = permutation_importance(ml_model, X_test_cleaned, y_test_cleaned, n_repeats=10, random_state=42, n_jobs=2)
393
- sorted_idx = result.importances_mean.argsort()
394
 
 
 
 
 
 
395
 
396
- fig, ax = plt.subplots(figsize=(12, 8))
 
 
 
 
 
 
397
 
398
- ax.boxplot(result.importances[sorted_idx].T, vert=False, labels=X_test_cleaned.columns[sorted_idx])
399
- ax.set_title("Permutation Importances (test set)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  fig.tight_layout()
401
  st.pyplot(fig)
 
402
 
403
  st.markdown("## Conclusão")
404
  st.markdown("Nesta análise exploratória dos dados do OULAD, conseguimos entender melhor o perfil dos estudantes, suas atividades na plataforma e os fatores que influenciam seu desempenho acadêmico. Através da visualização dos dados, identificamos padrões interessantes, como a predominância de estudantes do gênero masculino e a distribuição etária dos participantes. Além disso, o treinamento do modelo de aprendizado de máquina nos permitiu avaliar a importância das diferentes características dos dados, destacando quais fatores têm maior impacto no resultado final dos estudantes. Essas informações são valiosas para instituições educacionais que buscam melhorar a experiência de aprendizagem e o suporte oferecido aos alunos. Futuras análises podem aprofundar ainda mais esses insights, explorando outras variáveis e utilizando técnicas avançadas de modelagem preditiva.")
 
125
  # st.pyplot(fig)
126
 
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  new_vle = df_vle.drop(['week_from','week_to'],axis=1)
129
  show_basic_info(new_vle)
130
 
 
138
  # Criar uma cópia explícita do dataframe para evitar SettingWithCopyWarning
139
  df_student_registration_copy = df_studentregistration.copy()
140
 
141
+ # Criar variável binária indicando se o estudante cancelou o registro
142
+ df_student_registration_copy['cancelou'] = df_student_registration_copy['date_unregistration'].notna().astype(int)
143
+
144
+ # Preencher date_unregistration com valor alto quando ausente (para diferenciar de valores reais)
145
+ # Usar max + 1000 para garantir que seja claramente distinto de qualquer data real
146
+ max_date_unregistration = df_student_registration_copy['date_unregistration'].max()
147
+ if pd.notna(max_date_unregistration):
148
+ valor_nao_cancelou = max_date_unregistration + 1000
149
+ else:
150
+ # Se todos os valores forem NaN, usar um valor padrão alto
151
+ valor_nao_cancelou = 999999
152
+ df_student_registration_copy['date_unregistration'] = df_student_registration_copy['date_unregistration'].fillna(valor_nao_cancelou)
153
+
154
+ # Preencher date_registration com a média quando ausente
155
  mean_date_registration = df_student_registration_copy['date_registration'].mean()
 
156
  df_student_registration_copy['date_registration'] = df_student_registration_copy['date_registration'].fillna(mean_date_registration)
157
 
158
  # Junção dos dados
 
170
  # Merge with courses dataframe
171
  merged_df = pd.merge(merged_df, df_courses, on=['code_presentation'], how='inner')
172
 
173
+ # Merge with studentRegistration dataframe (usando a versão processada com variável cancelou)
174
+ merged_df = pd.merge(merged_df, df_student_registration_copy, on=['code_presentation','id_student'], how='inner')
175
 
176
  # Imputing missing values for numerical columns with the mean
177
  for col in merged_df.select_dtypes(include=np.number).columns:
 
233
 
234
  st.write('## Distribuição de Atividades por Tipo')
235
  plt.figure(figsize=(10, 6))
236
+ # Dicionário de tradução dos tipos de atividades
237
+ traducao_atividades = {
238
+ 'outcontent': 'Conteúdo Externo',
239
+ 'forumng': 'Fórum NG',
240
+ 'subpage': 'Subpágina',
241
+ 'resource': 'Recurso',
242
+ 'url': 'URL',
243
+ 'homepage': 'Página Inicial',
244
+ 'quiz': 'Quiz',
245
+ 'ouwiki': 'Wiki da Open University',
246
+ 'dataplus': 'DataPlus',
247
+ 'glossary': 'Glossário',
248
+ 'htmlactivity': 'Atividade HTML',
249
+ 'questionnaire': 'Questionário',
250
+ 'page': 'Página',
251
+ 'folder': 'Pasta',
252
+ ' llaborate': 'Atividades Colaborativas',
253
+ 'dualpane': 'Painel Duplo',
254
+ 'repeatactivity': 'Atividade Repetida',
255
+ 'sharedsubpage': 'Subpágina Compartilhada'
256
+ }
257
+
258
  # Contar atividades únicas por tipo (não estudantes únicos, pois é sobre atividades)
259
  atividade_counts = merged_df['activity_type'].value_counts()
260
+ # Traduzir os índices (tipos de atividades) - criar novo Series com índices traduzidos
261
+ atividades_traduzidas = [traducao_atividades.get(x, x) for x in atividade_counts.index]
262
+ atividade_counts_traduzido = pd.Series(atividade_counts.values, index=atividades_traduzidas)
263
+ sns.barplot(x=atividade_counts_traduzido.index, y=atividade_counts_traduzido.values)
264
  plt.title('Distribuição de Atividades por Tipo')
265
  plt.xlabel('Tipo de Atividade')
266
  plt.ylabel('Número de Atividades')
 
269
  plt.clf()
270
 
271
  '''
272
+ A atividade mais realizada é a 'Conteúdo Externo' com quase o dobro de execuções em relação à segunda posição que é 'Fórum NG'. A distribuição é acentuadamente desigual, com poucas atividades (como "Fórum NG" e "Subpágina") tendo uso moderado.
273
  '''
274
 
275
 
 
315
 
316
  st.write('## Distribuição de Estudantes por Região')
317
  plt.figure(figsize=(10, 6))
318
+ # Dicionário de tradução das regiões
319
+ traducao_regioes = {
320
+ 'East Anglian Region': 'Região de East Anglia',
321
+ 'East Midlands Region': 'Região dos Midlands Orientais',
322
+ 'Ireland': 'Irlanda',
323
+ 'London Region': 'Região de Londres',
324
+ 'North Region': 'Região Norte',
325
+ 'North East Region': 'Região Nordeste',
326
+ 'North Western Region': 'Região Noroeste',
327
+ 'North West Region': 'Região Noroeste',
328
+ 'Scotland': 'Escócia',
329
+ 'South East Region': 'Região Sudeste',
330
+ 'South Region': 'Região Sul',
331
+ 'South West Region': 'Região Sudoeste',
332
+ 'Wales': 'País de Gales',
333
+ 'West Midlands Region': 'Região dos Midlands Ocidentais',
334
+ 'Yorkshire and The Humber Region': 'Região de Yorkshire e Humber',
335
+ 'Yorkshire and the Humber Region': 'Região de Yorkshire e Humber'
336
+ }
337
+
338
  # Contar estudantes únicos por região
339
  regiao_counts = merged_df.groupby('region')['id_student'].nunique().sort_values(ascending=False)
340
+ # Traduzir os índices (regiões) - criar novo Series com índices traduzidos
341
+ regioes_traduzidas = [traducao_regioes.get(x, x) for x in regiao_counts.index]
342
+ regiao_counts_traduzido = pd.Series(regiao_counts.values, index=regioes_traduzidas)
343
+ sns.barplot(x=regiao_counts_traduzido.index, y=regiao_counts_traduzido.values)
344
  plt.title('Distribuição de Estudantes por Região')
345
  plt.xlabel('Região')
346
  plt.ylabel('Número de Estudantes Únicos')
 
349
  plt.clf()
350
 
351
  """
352
+ As regiões do sudeste sul detêm a maior concentração de estudantes, pode ter relação com a presença de importantes universidades na região: Universidade de Cambridge, Universidade de Essex, Universidade de Artes de Norwich, entre outras.
353
+ A distribuição é relativamente decrescente e sem discrepâncias abruptas.
354
  """
355
 
356
  st.write('## Distribuição dos Estudantes por Resultado Final')
357
  plt.figure(figsize=(6, 6))
358
+ # Dicionário de tradução dos resultados finais
359
+ traducao_resultados = {
360
+ 'Pass': 'Aprovado',
361
+ 'Distinction': 'Aprovação com Mérito',
362
+ 'Withdrawn': 'Desistente',
363
+ 'Fail': 'Reprovado'
364
+ }
365
+
366
  # Contar estudantes únicos por resultado final
367
  resultado_counts = merged_df.groupby('final_result')['id_student'].nunique().sort_values(ascending=False)
368
+ # Traduzir os índices (resultados) - criar novo Series com índices traduzidos
369
+ resultados_traduzidos = [traducao_resultados.get(x, x) for x in resultado_counts.index]
370
+ resultado_counts_traduzido = pd.Series(resultado_counts.values, index=resultados_traduzidos)
371
+ sns.barplot(x=resultado_counts_traduzido.index, y=resultado_counts_traduzido.values)
372
  plt.title('Distribuição dos Estudantes por Resultado Final')
373
  plt.xlabel('Resultado Final')
374
  plt.ylabel('Número de Estudantes Únicos')
 
376
  plt.clf()
377
 
378
  '''
379
+ A grande maioria dos estudantes obteve o resultado "Aprovado", superando vastamente as outras categorias. Os resultados de "Aprovação com Mérito", "Desistente" e "Reprovado" representam uma proporção muito menor do total de alunos, indicando uma alta taxa de sucesso geral.
380
  '''
381
 
382
  st.markdown('## Analisando a importância das classes (feature importance)')
 
436
  st.markdown("Avaliando do modelo...")
437
 
438
  predictions = ml_model.predict(X_test)
439
+ from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
 
 
 
 
 
 
440
 
441
  # Drop rows with NaN in y_test
442
  nan_rows_test = y_test.isnull()
443
  X_test_cleaned = X_test[~nan_rows_test].copy()
444
  y_test_cleaned = y_test[~nan_rows_test].copy()
445
+ predictions_cleaned = ml_model.predict(X_test_cleaned)
446
 
447
+ # Exibir métricas do modelo
448
+ st.markdown("### Métricas de Avaliação do Modelo")
449
 
450
+ # Calcular métricas individuais
451
+ accuracy = accuracy_score(y_test_cleaned, predictions_cleaned)
452
+ precision = precision_score(y_test_cleaned, predictions_cleaned, average='weighted', zero_division=0)
453
+ recall = recall_score(y_test_cleaned, predictions_cleaned, average='weighted', zero_division=0)
454
+ f1 = f1_score(y_test_cleaned, predictions_cleaned, average='weighted', zero_division=0)
455
 
456
+ # Criar tabela com as métricas
457
+ metricas_df = pd.DataFrame({
458
+ 'Métrica': ['Acurácia', 'Precisão (weighted)', 'Recall (weighted)', 'F1-Score (weighted)'],
459
+ 'Valor': [accuracy, precision, recall, f1]
460
+ })
461
+ metricas_df['Valor'] = metricas_df['Valor'].round(4)
462
+ st.dataframe(metricas_df, use_container_width=True, hide_index=True)
463
 
464
+ from sklearn.inspection import permutation_importance
465
+
466
+ result = permutation_importance(ml_model, X_test_cleaned, y_test_cleaned, n_repeats=10, random_state=42, n_jobs=2)
467
+ sorted_idx = result.importances_mean.argsort()
468
+
469
+ # Pegar apenas as top 5 features mais importantes (ordenadas da mais importante para a menos importante)
470
+ top_5_idx = sorted_idx[-5:][::-1] # Reverter para ter a mais importante primeiro
471
+ top_5_features = X_test_cleaned.columns[top_5_idx]
472
+ top_5_importances = result.importances_mean[top_5_idx]
473
+
474
+ # Criar gráfico de barras
475
+ fig, ax = plt.subplots(figsize=(10, 6))
476
+ ax.barh(range(len(top_5_features)), top_5_importances)
477
+ ax.set_yticks(range(len(top_5_features)))
478
+ ax.set_yticklabels(top_5_features)
479
+ ax.set_xlabel('Importância da Permutação')
480
+ ax.set_title('Top 5 Features Mais Importantes (Permutation Importances)')
481
+ ax.invert_yaxis() # Mostrar a feature mais importante no topo
482
  fig.tight_layout()
483
  st.pyplot(fig)
484
+ plt.clf()
485
 
486
  st.markdown("## Conclusão")
487
  st.markdown("Nesta análise exploratória dos dados do OULAD, conseguimos entender melhor o perfil dos estudantes, suas atividades na plataforma e os fatores que influenciam seu desempenho acadêmico. Através da visualização dos dados, identificamos padrões interessantes, como a predominância de estudantes do gênero masculino e a distribuição etária dos participantes. Além disso, o treinamento do modelo de aprendizado de máquina nos permitiu avaliar a importância das diferentes características dos dados, destacando quais fatores têm maior impacto no resultado final dos estudantes. Essas informações são valiosas para instituições educacionais que buscam melhorar a experiência de aprendizagem e o suporte oferecido aos alunos. Futuras análises podem aprofundar ainda mais esses insights, explorando outras variáveis e utilizando técnicas avançadas de modelagem preditiva.")
webapp/src/carregar_dados.py CHANGED
@@ -162,9 +162,22 @@ def processar_dados_oulad(dataframes_oulad):
162
 
163
  # Imputação otimizada de valores ausentes
164
  df_student_registration_copy = df_studentregistration.copy()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  mean_date_registration = df_student_registration_copy['date_registration'].mean()
166
- df_student_registration_copy['date_unregistration'] = df_student_registration_copy['date_unregistration'].fillna(
167
- df_student_registration_copy['date_unregistration'].max())
168
  df_student_registration_copy['date_registration'] = df_student_registration_copy['date_registration'].fillna(mean_date_registration)
169
 
170
  print("🔄 Fazendo joins dos dados...")
 
162
 
163
  # Imputação otimizada de valores ausentes
164
  df_student_registration_copy = df_studentregistration.copy()
165
+
166
+ # Criar variável binária indicando se o estudante cancelou o registro
167
+ df_student_registration_copy['cancelou'] = df_student_registration_copy['date_unregistration'].notna().astype(int)
168
+
169
+ # Preencher date_unregistration com valor alto quando ausente (para diferenciar de valores reais)
170
+ # Usar max + 1000 para garantir que seja claramente distinto de qualquer data real
171
+ max_date_unregistration = df_student_registration_copy['date_unregistration'].max()
172
+ if pd.notna(max_date_unregistration):
173
+ valor_nao_cancelou = max_date_unregistration + 1000
174
+ else:
175
+ # Se todos os valores forem NaN, usar um valor padrão alto
176
+ valor_nao_cancelou = 999999
177
+ df_student_registration_copy['date_unregistration'] = df_student_registration_copy['date_unregistration'].fillna(valor_nao_cancelou)
178
+
179
+ # Preencher date_registration com a média quando ausente
180
  mean_date_registration = df_student_registration_copy['date_registration'].mean()
 
 
181
  df_student_registration_copy['date_registration'] = df_student_registration_copy['date_registration'].fillna(mean_date_registration)
182
 
183
  print("🔄 Fazendo joins dos dados...")
webapp/src/vizualizacoes.py CHANGED
@@ -5,6 +5,30 @@ import matplotlib.pyplot as plt
5
  import seaborn as sns
6
  import numpy as np
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  def criar_grafico_distribuicao_notas(df_uci):
9
  """Cria gráfico de distribuição de notas para UCI"""
10
  if df_uci.empty or 'G3' not in df_uci.columns:
@@ -87,9 +111,13 @@ def criar_grafico_atividades_oulad(df_oulad):
87
  if df_oulad.empty or 'activity_type' not in df_oulad.columns:
88
  return None
89
 
 
 
 
 
90
  fig, ax = plt.subplots(figsize=(10, 6))
91
- sns.countplot(data=df_oulad, x='activity_type',
92
- order=df_oulad['activity_type'].value_counts().index, ax=ax)
93
  ax.set_title("Distribuição de Atividades por Tipo (OULAD)")
94
  ax.set_xlabel("Tipo de Atividade")
95
  ax.set_ylabel("Contagem")
@@ -362,7 +390,8 @@ def criar_grafico_sugerido_oulad():
362
  # 3. Distribuição de atividades
363
  if 'activity_type' in df_oulad.columns:
364
  atividades_counts = df_oulad['activity_type'].value_counts().head(6) # Top 6 atividades
365
- atividades = atividades_counts.index.tolist()
 
366
  cliques = atividades_counts.values.tolist()
367
 
368
  axes[1, 0].barh(atividades, cliques, color='lightsteelblue')
 
5
  import seaborn as sns
6
  import numpy as np
7
 
8
+ def traduzir_tipo_atividade(activity_type):
9
+ """Traduz tipos de atividades do OULAD de inglês para português"""
10
+ traducao_atividades = {
11
+ 'outcontent': 'Conteúdo Externo',
12
+ 'forumng': 'Fórum NG',
13
+ 'subpage': 'Subpágina',
14
+ 'resource': 'Recurso',
15
+ 'url': 'URL',
16
+ 'homepage': 'Página Inicial',
17
+ 'quiz': 'Quiz',
18
+ 'ouwiki': 'Wiki da Open University',
19
+ 'dataplus': 'DataPlus',
20
+ 'glossary': 'Glossário',
21
+ 'htmlactivity': 'Atividade HTML',
22
+ 'questionnaire': 'Questionário',
23
+ 'page': 'Página',
24
+ 'folder': 'Pasta',
25
+ 'oucollaborate': 'Atividades Colaborativas',
26
+ 'dualpane': 'Painel Duplo',
27
+ 'repeatactivity': 'Atividade Repetida',
28
+ 'sharedsubpage': 'Subpágina Compartilhada'
29
+ }
30
+ return traducao_atividades.get(activity_type, activity_type)
31
+
32
  def criar_grafico_distribuicao_notas(df_uci):
33
  """Cria gráfico de distribuição de notas para UCI"""
34
  if df_uci.empty or 'G3' not in df_uci.columns:
 
111
  if df_oulad.empty or 'activity_type' not in df_oulad.columns:
112
  return None
113
 
114
+ # Criar cópia do dataframe para traduzir os tipos de atividades
115
+ df_traduzido = df_oulad.copy()
116
+ df_traduzido['activity_type'] = df_traduzido['activity_type'].apply(traduzir_tipo_atividade)
117
+
118
  fig, ax = plt.subplots(figsize=(10, 6))
119
+ sns.countplot(data=df_traduzido, x='activity_type',
120
+ order=df_traduzido['activity_type'].value_counts().index, ax=ax)
121
  ax.set_title("Distribuição de Atividades por Tipo (OULAD)")
122
  ax.set_xlabel("Tipo de Atividade")
123
  ax.set_ylabel("Contagem")
 
390
  # 3. Distribuição de atividades
391
  if 'activity_type' in df_oulad.columns:
392
  atividades_counts = df_oulad['activity_type'].value_counts().head(6) # Top 6 atividades
393
+ # Traduzir os tipos de atividades
394
+ atividades = [traduzir_tipo_atividade(atividade) for atividade in atividades_counts.index.tolist()]
395
  cliques = atividades_counts.values.tolist()
396
 
397
  axes[1, 0].barh(atividades, cliques, color='lightsteelblue')