diff --git a/src/script/__init__.py b/src/adega/management/__init__.py similarity index 100% rename from src/script/__init__.py rename to src/adega/management/__init__.py diff --git a/src/adega/management/commands/__init__.py b/src/adega/management/commands/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/adega/management/commands/analyze.py b/src/adega/management/commands/analyze.py new file mode 100644 index 0000000000000000000000000000000000000000..de038c449320fc57db29d6b5577b0a96891db3fb --- /dev/null +++ b/src/adega/management/commands/analyze.py @@ -0,0 +1,18 @@ +from django.core.management.base import BaseCommand +from uploads.models import Submission + +from script.main import analyze + + +class Command(BaseCommand): + help = 'Makes one specific analysis' + + def add_arguments(self, parser): + parser.add_argument('submission_id', type=int) + + def handle(self, *args, **options): + id = options['submission_id'] + + submission = Submission.objects.get(pk=id) + + analyze(submission) diff --git a/src/script/.gitignore b/src/script/.gitignore deleted file mode 100644 index 2a40d2a5a1d39024d84e71b8cf5764efc6082a33..0000000000000000000000000000000000000000 --- a/src/script/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -cache/* -*.json -*.xls -*.csv -script/base/*.xls -script/base/*.csv diff --git a/src/script/analysis/course_analysis.py b/src/script/analysis/course_analysis.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d8b88331539a23bf4e7598923ba06fed57ff31ac 100644 --- a/src/script/analysis/course_analysis.py +++ b/src/script/analysis/course_analysis.py @@ -0,0 +1,310 @@ +# -*- coding: utf-8 -*- +from datetime import datetime +import pprint +import pandas as pd +import json +import numpy as np +from script.utils.situations import Situation as sit +def grafico(df,lista_disciplinas): + for disciplina in lista_disciplinas.keys() : + qtd_aluno = lista_disciplinas[disciplina]["qtd_alunos"] + dic = {"00-4.9":0.0 , "05-9.9":0.0 , "10-14.9":0.0 , "15-19.9":0.0 , "20-24.9":0.0 , "25-29.9":0.0 , "30-34.9":0.0 , + "35-39.9":0.0 , "40-44.9":0.0 , "45-49.9":0.0 , "50-54.9":0.0 , "55-59.9":0.0 , "60-64.9":0.0 , "65-69.9":0.0 , + "70-74.9":0.0 , "75-79.9":0.0 , "80-84.9":0.0 , "85-89.9":0.0 , "90-94.9":0.0 ,"95-100": 0.0} + disciplina_df = df.loc[df.COD_ATIV_CURRIC == disciplina] + disci_lista = [] + for i in disciplina_df.iterrows(): + nota = 0.0 if i[1].MEDIA_FINAL > 100 else i[1].MEDIA_FINAL + for key in dic.keys(): + a = key.split('-') + value_min = float(a[0]) + value_max = float(a[1]) + if((nota >= value_min) and (nota <= value_max)): + dic[key] += float(nota) + break; + for j in dic.keys(): + disci_lista.append([j, 0.0 if qtd_aluno == 0 else dic[j] / qtd_aluno]) + + lista_disciplinas[disciplina]["compara_nota"] = disci_lista + + + + +def informacoes_gerais(df,lista_disciplinas): + #quantidade de matriculas + disciplinas = df.groupby(["COD_ATIV_CURRIC"]).size() + for disciplina in disciplinas.index: + disciplina_dict = {} + disciplina_df = df.loc[df.COD_ATIV_CURRIC == disciplina] + disciplina_dict["qtd_alunos"] = int(disciplinas[disciplina]) + disciplina_dict["disciplina_codigo"] = disciplina + disciplina_dict["disciplina_nome"] = \ + disciplina_df.NOME_ATIV_CURRIC.values[0] + lista_disciplinas[disciplina] = disciplina_dict +def conhecimento(qtd,disciplina_dict): + conheci_df = qtd.loc[(qtd.SITUACAO == sit.SIT_CONHECIMENTO_APROVADO) | + (qtd.SITUACAO == sit.SIT_CONHECIMENTO_REPROVADO)] + total_conheci = conheci_df.qtd.sum() + if np.isnan(total_conheci): + total_conheci = 0 + conheci_aprov = conheci_df.loc[conheci_df.SITUACAO == \ + sit.SIT_CONHECIMENTO_APROVADO].set_index("COD_ATIV_CURRIC" ) + disciplina_dict["qtd_conhecimento"] = int(total_conheci) + + if (total_conheci !=0) and (not conheci_aprov.empty): + disciplina_dict["taxa_conhecimento"] = float(conheci_aprov.qtd.values[0] / + total_conheci) + else: + disciplina_dict["taxa_conhecimento"] = 0.0 + +def trancamento(qtd,disciplina_dict,qtd_matr): + trancamento_df = qtd.loc[(qtd.SITUACAO == sit.SIT_TRANCAMENTO_ADMINISTRATIVO) | + (qtd.SITUACAO == sit.SIT_TRANCAMENTO_TOTAL) | + (qtd.SITUACAO == sit.SIT_CANCELADO)] + qtd_tranc = trancamento_df.qtd.sum() + if np.isnan(qtd_tranc): + qtd_tranc = 0 + disciplina_dict["qtd_trancamento"] = int(qtd_tranc) + disciplina_dict["taxa_trancamento"] = float(qtd_tranc / qtd_matr) if qtd_matr else 0.0 + + +def reprovacao(qtd,disciplina,qtd_matr,taxa_reprov_absoluta,taxa_reprov_freq): + """existem as analises reprovacao absoluta, reprovacao por frequencia, + reprovacao absoluta, reprovacao por frequencia da ultima vez que a + disciplina foi ofertada, a logica das analise sao a mesma so muda os valores + do dataframe qtd e o nomes das chaves do dicionario,logo é possÃvel reaproveitar + o mesmo codigo para fazer analise geral e da ultima vez que foi ofertado.""" + sit_reprov = sit.SITUATION_FAIL + (sit.SIT_REPROVADO_SEM_NOTA,) + reprov_df = qtd.loc[(qtd.SITUACAO == sit_reprov[0]) | + (qtd.SITUACAO == sit_reprov[1]) | + (qtd.SITUACAO == sit_reprov[2]) | + (qtd.SITUACAO == sit_reprov[3]) ] + qtd_reprov_abso = reprov_df.qtd.sum() #quantidade de reprovacao absoluta + qtd_reprov_freq = reprov_df.loc[reprov_df.SITUACAO == sit_reprov[1]] + if qtd_matr != 0: + if np.isnan(qtd_reprov_abso): + disciplina[taxa_reprov_absoluta] = 0.0 + else: + disciplina[taxa_reprov_absoluta] = float(qtd_reprov_abso / qtd_matr) + + if qtd_reprov_freq.empty: + disciplina[taxa_reprov_freq] = 0.0 + else: + disciplina[taxa_reprov_freq] = float(qtd_reprov_freq.qtd.values[0] / qtd_matr) + + else: + disciplina[taxa_reprov_absoluta] = 0.0 + disciplina[taxa_reprov_freq] = 0.0 + +def nota(notas_df,disciplina,index): + notas = [] + for i in notas_df.iterrows(): + if i[1].SITUACAO in sit.SITUATION_AFFECT_IRA: + nota = 0 if np.isnan(i[1].MEDIA_FINAL) else i[1].MEDIA_FINAL + #alguns valores de media_final não são confiaveis na tabela .33 + nota = 0 if nota > 100 else nota + notas.append(nota) + + if len(notas) != 0: + notas_np = np.array(notas) + media_np = np.mean(notas_np) + desvio_np = np.std(notas_np) + media = 0.0 if np.isnan(media_np) else media_np + desvio = 0.0 if np.isnan(desvio_np) else desvio_np + disciplina[index] = [media,desvio] + else: + disciplina[index] = [0.0,0.0] + + +def analises_gerais(df,lista_disciplinas): + qtd_geral= df.groupby(["COD_ATIV_CURRIC","SITUACAO"]).size().reset_index(name="qtd" ) + qtd_ultimo_geral = \ + df.groupby(["COD_ATIV_CURRIC","SITUACAO","ANO"]).size().reset_index(name="qtd") + matr_por_semestre = \ + df.groupby(["COD_ATIV_CURRIC","ANO"]).size().reset_index(name="matr") + """ dataframe com a quantidade de matriculas por periodo e ano, por exemplo + disciplina ci055 2010/1 teve x matriculas""" + """Dataframes relacionado a notas.O campo qtd é inutil, o groupby pede se + que se use um apply sobre o groupby, pois se não o grouby é tratado como + objeto e não como um dataframe """ + nota_geral_df = df.groupby(["COD_ATIV_CURRIC","MEDIA_FINAL", "SITUACAO", + ]).size().reset_index(name = "qtd" ) + nota_semestral_df = df.groupby(["COD_ATIV_CURRIC","ANO", "MEDIA_FINAL", "SITUACAO", + ]).size().reset_index(name = "qtd" ) + for disciplina in lista_disciplinas.keys(): + disciplina_dict = {} #facilitar os calculos + + qtd = qtd_geral.loc[qtd_geral.COD_ATIV_CURRIC == disciplina] + + disciplina_semestral = qtd_ultimo_geral.loc[qtd_ultimo_geral.COD_ATIV_CURRIC == \ + disciplina] + + ano = datetime.now().year - 1 + + qtd_ultimo = disciplina_semestral.loc[disciplina_semestral.ANO == ano] + + + #quantidade de alunos + qtd_matriculas = lista_disciplinas[disciplina]["qtd_alunos"] + + + #qtd é um dataframe que contem a ocorrencia de cada situacao + qtd = qtd_geral.loc[qtd_geral.COD_ATIV_CURRIC == disciplina] + + #faz analises relacionada ao conhecimento + conhecimento(qtd,disciplina_dict) + + # faz analises relacionada ao trancamento + trancamento(qtd,disciplina_dict,qtd_matriculas) + + # faz analises relacionada a reprovacoes + reprovacao(qtd,disciplina_dict,qtd_matriculas,"taxa_reprovacao_absoluta","taxa_reprovacao_frequencia") + qtd_matr_ultimo = matr_por_semestre.loc[(matr_por_semestre.COD_ATIV_CURRIC \ + == disciplina) & matr_por_semestre.ANO == ano] + + if qtd_matr_ultimo.empty: #caso a disciplina nao foi ofertada no ultimo ano + disciplina_dict["taxa_reprovacao_ultimo_absoluta"] = -1 + disciplina_dict["taxa_reprovacao_ultimo_frequencia"] = -1 + else: + reprovacao(qtd_ultimo,disciplina_dict,qtd_matriculas,"taxa_reprovacao_ultimo_absoluta", + "taxa_reprovacao_ultimo_frequencia") + + #faz as analises relacionada a nota + nota_df = nota_geral_df.loc[nota_geral_df.COD_ATIV_CURRIC == disciplina] + nota_por_semestre_df = nota_semestral_df.loc[nota_semestral_df.COD_ATIV_CURRIC == disciplina] + nota_ultimo = nota_por_semestre_df.loc[nota_por_semestre_df.ANO == + ano] + + nota(nota_df,disciplina_dict,"nota") + if nota_ultimo.empty: + disciplina_dict["nota_ultimo_ano"] = -1 + nota(nota_ultimo,disciplina_dict,"nota_ultimo_ano") + + + lista_disciplinas[disciplina].update(disciplina_dict) +# *cursada ate a aprovacao +def analises_semestrais(df,lista_disciplinas): + # [ ] -> nota media de aprovaçao + geral_df = \ + df.groupby(["COD_ATIV_CURRIC","ANO","PERIODO"]).size().reset_index(name + = "matr" ) + df_semestral = df.groupby(["COD_ATIV_CURRIC", "ANO", "PERIODO" , + "SITUACAO"]).size().reset_index(name = "qtds" ) + disciplinas = {} + for i in df_semestral.iterrows(): # percorre o dataframe + disciplina = i[1].COD_ATIV_CURRIC #nome da disciplina + if not(disciplina in disciplinas): + disciplinas[disciplina] = {} + + # para chave do dicionario ser do formato ano/periodo + ano = str(int(i[1].ANO)) + periodo = str(i[1].PERIODO) + periodo_curso = ano+"/"+periodo # chave do dicionario + + situacao = i[1].SITUACAO + #verifica se a chave ano/periodo exitste no dicionario + if not(periodo_curso in disciplinas[disciplina] ): + disciplinas[disciplina][periodo_curso] = [0,0] #qtd aprovado,total + + # se a situacao for igual a aprovado entao qtd de aprovados em + # ano/periodo +1 + if situacao in sit.SITUATION_PASS: + disciplinas[disciplina][periodo_curso][0] += 1 # qtd de aprovados + + #quantidade total de matriculas no periodo ano/periodo + disciplinas[disciplina][periodo_curso][1] += 1 + + for disciplina in disciplinas.keys(): + for ano_periodo in disciplinas[disciplina].keys(): + qtd_total = disciplinas[disciplina][ano_periodo][1] + qtd_aprovados = disciplinas[disciplina][ano_periodo][0] + #calcula a taxa de aprovacao por semestre, qtd_aprov/qtd_total + if qtd_total != 0: + disciplinas[disciplina][ano_periodo][0] = qtd_aprovados / qtd_total + else: + disciplinas[disciplina][ano_periodo][0] = 0.0 + + aprovacao_semestral = disciplinas[disciplina] + lista_disciplinas[disciplina]["aprovacao_semestral"] = aprovacao_semestral +def transforma_json(lista_disciplinas): + for disciplina in lista_disciplinas.keys(): + disciplina_dict =lista_disciplinas[disciplina] + with open('cache/'+disciplina+'.json','w') as f: + f.write(json.dumps(lista_disciplinas[disciplina],indent=4)) +def listagem_disciplina(df,lista_disciplinas): + listagem = {} + compara_aprov = {} + compara_nota = {} + cache = {} + disciplinas = {} + # nota media de todas as disciplinas + trancamento = [] + reprovacao = [] + conhecimento = [] + nota= [] # lista que contem todas as notas medias de todas as disciplinas + nota_desvio = [] # lista que contem todos os desvio padrao de todas as disciplinas + grafico(df,lista_disciplinas) + + for disciplina in lista_disciplinas.keys(): + disciplina_dict = lista_disciplinas[disciplina] + cache[disciplina] = {"nota":disciplina_dict["nota"], + "taxa_reprovacao_absoluta":disciplina_dict["taxa_reprovacao_absoluta"], + "taxa_reprovacao_frequencia":disciplina_dict["taxa_reprovacao_frequencia"], + "taxa_trancamento":disciplina_dict["taxa_trancamento"] } + compara_disciplina = [] + compara_nota[disciplina]= lista_disciplinas[disciplina]["compara_nota"] + #calcula aprovacao semestral + for ano in disciplina_dict["aprovacao_semestral"].keys(): + aprov_por_ano = [ano,disciplina_dict["aprovacao_semestral"][ano][0]] + compara_disciplina.append(aprov_por_ano) + + compara_aprov[disciplina] = compara_disciplina + disciplinas[disciplina] = disciplina_dict["disciplina_nome"] + + # pega todas as taxas adiciona em uma lista, que depois será tranformada + # em numpy array para poder uutilizar os metodos np.mean e np.std + conhecimento.append(disciplina_dict["taxa_conhecimento"]) + trancamento.append(disciplina_dict["taxa_trancamento" ]) + reprovacao.append(disciplina_dict["taxa_reprovacao_absoluta" ]) + nota.append(disciplina_dict["nota"][0]) + + #nota + nota_np = np.array(nota) + nota_media= np.mean(nota_np) + nota_desvio= np.std(nota_np) + #trancamento + trancamento_np = np.array(trancamento) + trancamento_media = np.mean(trancamento_np) + trancamento_desvio = np.std(trancamento_np) + #conhecimento + conhecimento_np = np.array(trancamento) + conhecimento_media = np.mean(trancamento_np) + conhecimento_desvio = np.std(trancamento_np) + #reprovacao + reprovacao_np = np.array(trancamento) + reprovacao_media = np.mean(trancamento_np) + reprovacao_desvio = np.std(trancamento_np) + + #verifica se o resultado final não é nan + + listagem = { "cache" : cache, + "compara_aprov": compara_aprov, + "compara_nota": compara_nota, + "disciplinas": disciplinas, + "taxa_conhecimento":[float(conhecimento_media),float(conhecimento_desvio)] , + "taxa_trancamento":[float(trancamento_media),float(trancamento_desvio)] , + "taxa_reprovacao":[float(reprovacao_media),float(reprovacao_desvio)] , + "nota": [float(nota_media),float(nota_desvio)] + } + with open("cache/disciplinas.json",'w') as f: + f.write(json.dumps(listagem,indent=4)) + # [ ] ->media_disc + # [ ] compara_aprov + +def analises_disciplinas(df): + lista_disciplinas = {} + informacoes_gerais(df,lista_disciplinas) + analises_gerais(df,lista_disciplinas) + analises_semestrais(df,lista_disciplinas) + transforma_json(lista_disciplinas) + listagem_disciplina(df,lista_disciplinas) diff --git a/src/script/analysis/degree_analysis.py b/src/script/analysis/degree_analysis.py index ca72bb2944cbcb84f13708c45b0e70a72505fe2b..cdedfdc62ae7f67bb933547eb2bb584397259787 100644 --- a/src/script/analysis/degree_analysis.py +++ b/src/script/analysis/degree_analysis.py @@ -1,5 +1,6 @@ import pandas as pd import math +import json from script.utils.situations import Situation, EvasionForm @@ -29,18 +30,59 @@ def general_failure(df): return (average, standard_deviation) +def current_students_failure(df): + fixed = df.loc[(df.FORMA_EVASAO == EvasionForm.EF_ATIVO)] + affect_ira = fixed[fixed.SITUACAO.isin(Situation.SITUATION_AFFECT_IRA)] + failures = affect_ira[affect_ira.SITUACAO.isin(Situation.SITUATION_FAIL)] + + average = failures.shape[0] / affect_ira.shape[0] + + student_courses = affect_ira.groupby(['MATR_ALUNO'], as_index=False)\ + .aggregate({'SITUACAO': 'count'}) + student_failures = failures.groupby(['MATR_ALUNO'], as_index=False)\ + .aggregate({'SITUACAO': 'count'}) + + merged = pd.merge(student_courses, student_failures, on=['MATR_ALUNO']) + merged.columns = ['MART_ALUNO', 'FEITAS', 'REPROVADO'] + variance = merged['REPROVADO'].div(merged['FEITAS']).sub(average)\ + .pow(2).sum() / merged.shape[0] + standard_deviation = math.sqrt(variance) + return (average, standard_deviation) + def general_ira(df): fixed = df[df.SITUACAO.isin(Situation.SITUATION_AFFECT_IRA)] fixed = fixed[fixed.MEDIA_FINAL <= 100] return (fixed.MEDIA_FINAL.mean(), fixed.MEDIA_FINAL.std()) -def total_evasion_rate(df): +def current_ira(df): + ano_grade = int(df.loc[df['NUM_VERSAO'].idxmax()]['NUM_VERSAO']) + fixed = df.loc[(df['NUM_VERSAO'] == ano_grade)] + fixed = fixed[fixed.SITUACAO.isin(Situation.SITUATION_AFFECT_IRA)] + fixed = fixed[fixed.MEDIA_FINAL <= 100] + return (fixed.MEDIA_FINAL.mean(), fixed.MEDIA_FINAL.std()) + +def current_students_ira(df): + fixed = df.loc[(df.FORMA_EVASAO == EvasionForm.EF_ATIVO)] + fixed = fixed[fixed.SITUACAO.isin(Situation.SITUATION_AFFECT_IRA)] + fixed = fixed[fixed.MEDIA_FINAL <= 100] + return (fixed.MEDIA_FINAL.mean(), fixed.MEDIA_FINAL.std()) + +def general_evasion_rate(df): students = df['MATR_ALUNO'].drop_duplicates() total_student = students.shape[0] total_evasion = students.loc[(df.FORMA_EVASAO != EvasionForm.EF_ATIVO) & (df.FORMA_EVASAO != EvasionForm.EF_FORMATURA) & (df.FORMA_EVASAO != EvasionForm.EF_REINTEGRACAO)].shape[0] return total_evasion / total_student +def current_evasion_rate(df): + ano_grade = int(df.loc[df['NUM_VERSAO'].idxmax()]['NUM_VERSAO']) + students = df.loc[(df['NUM_VERSAO'] == ano_grade)] + students = students['MATR_ALUNO'].drop_duplicates() + total_student = students.shape[0] + total_evasion = students.loc[(df.FORMA_EVASAO != EvasionForm.EF_ATIVO) & (df.FORMA_EVASAO != EvasionForm.EF_FORMATURA) & (df.FORMA_EVASAO != EvasionForm.EF_REINTEGRACAO)].shape[0] + + return total_evasion / total_student + def average_graduation_time(df): graduates = df.loc[(df.FORMA_EVASAO == EvasionForm.EF_FORMATURA)] total_graduate = graduates.shape[0] @@ -62,3 +104,104 @@ def average_graduation_time(df): average_time /= 2 return average_time + +def total_students(df): + return df.drop_duplicates('MATR_ALUNO').shape[0] + +def current_total_students(df): + return df.loc[(df.FORMA_EVASAO == EvasionForm.EF_ATIVO)].drop_duplicates('MATR_ALUNO').shape[0] + +def taxa_abandono(df): + students = df['MATR_ALUNO'].drop_duplicates() + total_student = students.shape[0] + total_abandono = students.loc[(df.FORMA_EVASAO == EvasionForm.EF_ABANDONO)].shape[0] + + return total_abandono / total_student + +def average_ira_graph(df): + alunos = df.drop_duplicates('MATR_ALUNO') + + dic = build_dict_ira_medio(alunos) + + return dic + +def current_students_average_ira_graph(df): + alunos_se = df.loc[(df.FORMA_EVASAO == EvasionForm.EF_ATIVO)] + alunos_se = alunos_se.drop_duplicates('MATR_ALUNO') + + dic_se = build_dict_ira_medio(alunos_se) + + return dic_se + +def graduates_average_ira_graph(df): + alunos_for = df.loc[(df.FORMA_EVASAO == EvasionForm.EF_FORMATURA)] + alunos_for = alunos_for.drop_duplicates('MATR_ALUNO') + + dic_for = build_dict_ira_medio(alunos_for) + + return dic_for + +def period_evasion_graph(df): + di_qtd = {} + dic = {} + evasions_total = 0 + year_start = int(df['ANO'].min()) + year_end = int(df['ANO'].max()) + 1 + students = df.drop_duplicates() + for year in range(year_start, year_end): + for semester in range(1, 3): + evasions = students.loc[(df['ANO_EVASAO'] == str(year)) & (df['SEMESTRE_EVASAO'] == str(semester))].shape[0] + date = str(year) + ' {}º PerÃodo'.format(semester) + di_qtd[date] = evasions + evasions_total += evasions + if evasions_total: + for di in di_qtd: + qtd = di_qtd[di] + dic[di] = {'qtd': qtd, 'taxa': (qtd/evasions_total)*100} + + return dic + +def build_dict_ira_medio(alunos): + dic = {"00-4.9":0, "05-9.9":0, "10-14.9":0, "15-19.9":0, "20-24.9":0, "25-29.9":0, "30-34.9":0, + "35-39.9":0, "40-44.9":0, "45-49.9":0, "50-54.9":0, "55-59.9":0, "60-64.9":0, "65-69.9":0, + "70-74.9":0, "75-79.9":0, "80-84.9":0, "85-89.9":0, "90-94.9": 0,"95-100":0} + + iras = [] + for index, row in alunos.iterrows(): + if(row['MEDIA_FINAL'] is not None): + iras.append(row['MEDIA_FINAL']) + + for d in dic: + aux = d.split('-') + v1 = float(aux[0]) + if (v1 == 0.0): + v1 += 0.01 + v2 = float(aux[1]) + dic[d] = sum((float(num) >= v1) and (float(num) < v2) for num in iras) + + return dic + +def build_degree_json(df): + def merge_dicts(dict1, dict2, dict3): + dict_out = {} + for key, value in dict1.items(): + v2 = dict2[key] if key in dict2 else None + v3 = dict3[key] if key in dict3 else None + dict_out[key] = {'ira_medio': value, 'sem_evasao': v2, 'formatura': v3} + return dict_out + dic = merge_dicts(average_ira_graph(df),current_students_average_ira_graph(df),graduates_average_ira_graph(df)) + degree_json = { + "ira_medio_grafico": json.dumps(sorted(dic.items())), + "evasao_grafico": json.dumps(sorted(period_evasion_graph(df).items())), + "ira_atual": current_students_ira(df), + "ira_medio": general_ira(df), + "qtd_alunos": total_students(df), + "qtd_alunos_atuais": current_total_students(df), + "taxa_evasao": general_evasion_rate(df), + "taxa_formatura": average_graduation(df), + "taxa_reprovacao": general_failure(df), + "taxa_reprovacao_atual": current_students_failure(df), + "tempo_formatura": average_graduation_time(df), + } + with open("cache/curso/curso.json",'w') as f: + f.write(json.dumps(degree_json,indent=4)) diff --git a/src/script/analysis/student_analysis.py b/src/script/analysis/student_analysis.py index f6df56a9151250a85a9dda4762d64ee0788312d9..b3958ff6cadde7e743f4a4874bf40883376683b8 100644 --- a/src/script/analysis/student_analysis.py +++ b/src/script/analysis/student_analysis.py @@ -1,16 +1,62 @@ import numpy as np +#~ TODO: +#~ FAZER CACHE DE TUDO +#~ AO CHAMAR A FUNCAO VERIFICAR SE TEM ALGO NA CACHE + from script.utils.situations import * +import pandas as pd ANO_ATUAL = 2017 SEMESTRE_ATUAL = 2 -def listagem_alunos_ativos(df): - return list(df["MATR_ALUNO"][df["FORMA_EVASAO"] == EvasionForm.EF_ATIVO].drop_duplicates()) +def listagem_alunos(df): + #~ ativos = df[["MATR_ALUNO", "NOME_PESSOA",]][df["FORMA_EVASAO"] == EvasionForm.EF_ATIVO].drop_duplicates() + situacoes = df.groupby(["MATR_ALUNO", "NOME_PESSOA", "FORMA_EVASAO"]) + situacoes = list(pd.DataFrame({'count' : situacoes.size()}).reset_index().groupby(["FORMA_EVASAO"])) + #~ Cria lista de nome de listagens + retorno = {} + for s in situacoes: + #Busca a lista de alunos relacionados a um codigo + retorno[s[0]] = list(s[1]["MATR_ALUNO"]) + + return retorno + +def ira_alunos(df): + iras = ira_por_quantidade_disciplinas(df) + for i in iras: + ira_total = 0 + carga_total = 0 + for semestre in iras[i]: + ira_total += iras[i][semestre][0]*iras[i][semestre][2] + carga_total+=iras[i][semestre][2] + + if(carga_total != 0): + iras[i] = ira_total/carga_total + else: + iras[i] = 0 + return iras + +def taxa_aprovacao(df): + aprovacoes_semestres = indice_aprovacao_semestral(df) + + for aluno in aprovacoes_semestres: + total = sum([aprovacoes_semestres[aluno][s][1] for s in aprovacoes_semestres[aluno]]) + aprovacoes = sum([aprovacoes_semestres[aluno][s][0] for s in aprovacoes_semestres[aluno]]) + total = float(total) + aprovacoes = float(aprovacoes) + if(total != 0): + aprovacoes_semestres[aluno] = aprovacoes/total + else: + aprovacoes_semestres[aluno] = None + #~ for semestre in aprovacoes_semestres[aluno]: + #~ aprovacoes+=aprovacoes_semestres[aluno][semestre][0] + #~ total+=aprovacoes_semestres[semestre][1] + + return aprovacoes_semestres + - - def posicao_turmaIngresso_semestral(df): iras = ira_semestral(df) @@ -68,10 +114,11 @@ def ira_por_quantidade_disciplinas(df): situacao = int(df["SITUACAO"][i]) nota = float(df["MEDIA_FINAL"][i]) carga = float(df["CH_TOTAL"][i]) - media_credito = int(df["MEDIA_CREDITO"][i]) + #media_credito = int(df["MEDIA_CREDITO"][i]) - if (situacao in Situation.SITUATION_AFFECT_IRA and media_credito != 0): + #if (situacao in Situation.SITUATION_AFFECT_IRA and media_credito != 0): + if (situacao in Situation.SITUATION_AFFECT_IRA): if not (ano + "/" + semestre in students[matr]): students[matr][ano + "/" + semestre] = [0, 0, 0] @@ -83,6 +130,7 @@ def ira_por_quantidade_disciplinas(df): for periodo in students[matr]: if (students[matr][periodo][2] != 0): students[matr][periodo][0] /= students[matr][periodo][2] * 100 + return (students) @@ -107,6 +155,7 @@ def indice_aprovacao_semestral(df): students[matr][ano + "/" + semestre][1] += 1 if situacao in Situation.SITUATION_FAIL: students[matr][ano + "/" + semestre][1] += 1 + return (students) diff --git a/src/script/base/dataframe_base.py b/src/script/base/dataframe_base.py index 51a2eb1b21498b933c2dcc1941e494123572d9ff..7097a4f38c77c77d83832aebae06d1e7d5d5dfcc 100644 --- a/src/script/base/dataframe_base.py +++ b/src/script/base/dataframe_base.py @@ -1,3 +1,4 @@ + import os import pandas as pd import numpy as np @@ -5,102 +6,109 @@ from script.utils.situations import * class DataframeHolder: - def __init__(self, dataframe): - self.students = dataframe.groupby('MATR_ALUNO') - self.courses = dataframe.groupby('COD_ATIV_CURRIC') - self.admission = dataframe.groupby(['ANO_INGRESSO', 'SEMESTRE_INGRESSO']) + def __init__(self, dataframe): + self.students = dataframe.groupby('MATR_ALUNO') + self.courses = dataframe.groupby('COD_ATIV_CURRIC') + self.admission = dataframe.groupby(['ANO_INGRESSO', 'SEMESTRE_INGRESSO']) def load_dataframes(cwd='.'): - dataframes = [] - for path, dirs, files in os.walk(cwd): - for f in files: - file_path = path + '/' + f - dh = {'name': f, 'dataframe': None} - if 'csv' in f: - dh['dataframe'] = read_csv(file_path) - if 'xls' in f: - dh['dataframe'] = read_excel(file_path) - - if dh['dataframe'] is not None: - dataframes.append(dh) - - dataframe = fix_dataframes(dataframes) - - return dataframe + dataframes = [] + for path, dirs, files in os.walk(cwd): + for f in files: + file_path = path + '/' + f + dh = {'name': f, 'dataframe': None} + if 'csv' in f: + dh['dataframe'] = read_csv(file_path) + if 'xls' in f: + dh['dataframe'] = read_excel(file_path) + + if dh['dataframe'] is not None: + dataframes.append(dh) + + dataframe = fix_dataframes(dataframes) + dh = DataframeHolder(dataframe) + #~ dh.students.aggregate(teste) +# print(dh.students['MEDIA_FINAL'].aggregate(teste)) + return dataframe def read_excel(path, planilha='Planilha1'): - return pd.read_excel(path) + return pd.read_excel(path) def read_csv(path): - return pd.read_csv(path) + return pd.read_csv(path) def fix_dataframes(dataframes): - for df in dataframes: - if df['name'] == 'historico.xls' or df['name'] == 'historico.csv': - history = df['dataframe'] - if df['name'] == 'matricula.xls' or df['name'] == 'matricula.csv': - register = df['dataframe'] + for df in dataframes: + if df['name'] == 'historico.xls' or df['name'] == 'historico.csv': + history = df['dataframe'] + history.rename(columns={'DESCR_SITUACAO': 'SITUACAO'}, inplace=True) + if df['name'] == 'matricula.xls' or df['name'] == 'matricula.csv': + register = df['dataframe'] - clean_history(history) - clean_register(register) - # ~ df.dropna(axis=0, how='all') - history["MEDIA_FINAL"] = pd.to_numeric(history["MEDIA_FINAL"], errors='coerce') - history = history[np.isfinite(history['MEDIA_FINAL'])] + #~ clean_history(history) + clean_register(register) + #~ df.dropna(axis=0, how='all') + history["MEDIA_FINAL"] = pd.to_numeric(history["MEDIA_FINAL"], errors='coerce') + history = history[np.isfinite(history['MEDIA_FINAL'])] - merged = pd.merge(history, register, how='right', on=['MATR_ALUNO']) - # ~ print(merged) - fix_situation(merged) - # fix_admission(merged) - fix_evasion(merged) - return merged + merged = pd.merge(history, register, how='outer', on=['MATR_ALUNO']) + merged = merged.rename(index=str, columns={"ANO_INGRESSO_x": "ANO_INGRESSO", "SEMESTRE_INGRESSO_x": "SEMESTRE_INGRESSO", "FORMA_INGRESSO_x": "FORMA_INGRESSO"}) + + fix_situation(merged) + fix_admission(merged) + fix_evasion(merged) + fix_carga(merged) + + return merged def clean_history(df): df.drop(['ID_NOTA', 'CONCEITO', 'ID_LOCAL_DISPENSA', 'SITUACAO_CURRICULO', 'ID_CURSO_ALUNO', 'ID_VERSAO_CURSO', 'ID_CURRIC_ALUNO', - 'ID_ATIV_CURRIC', 'SITUACAO_ITEM', 'ID_ESTRUTURA_CUR' - ], axis=1, inplace=True) + 'ID_ATIV_CURRIC', 'SITUACAO_ITEM', 'ID_ESTRUTURA_CUR', 'NUM_VERSAO' + ], axis=1, inplace=True) df['PERIODO'] = df['PERIODO'].str.split('o').str[0] def clean_register(df): - df_split = df['PERIODO_INGRESSO'].str.split('/') - df['ANO_INGRESSO'] = df_split.str[0] - df['SEMESTRE_INGRESSO'] = df_split.str[1].str.split('o').str[0] - df_split = df['PERIODO_EVASAO'].str.split('/') - df['ANO_EVASAO'] = df_split.str[0] - df['SEMESTRE_EVASAO'] = df_split.str[1].str.split('o').str[0] + df_split = df['PERIODO_INGRESSO'].str.split('/') + df['ANO_INGRESSO'] = df_split.str[0] + df['SEMESTRE_INGRESSO'] = df_split.str[1].str.split('o').str[0] + df_split = df['PERIODO_EVASAO'].str.split('/') + df['ANO_EVASAO'] = df_split.str[0] + df['SEMESTRE_EVASAO'] = df_split.str[1].str.split('o').str[0] - df.drop(['ID_PESSOA', 'NOME_PESSOA', 'DT_NASCIMENTO', 'NOME_UNIDADE', - 'COD_CURSO', 'NUM_VERSAO', 'PERIODO_INGRESSO', 'PERIODO_EVASAO', - ], axis=1, inplace=True) + df.drop(['ID_PESSOA', 'NOME_PESSOA', 'DT_NASCIMENTO', 'NOME_UNIDADE','COD_CURSO', 'PERIODO_INGRESSO', 'PERIODO_EVASAO'],axis=1, inplace=True) def fix_situation(df): - for situation in Situation.SITUATIONS: - df.loc[df.SITUACAO == situation[1], 'SITUACAO'] = situation[0] + for situation in Situation.SITUATIONS: + df.loc[df.SITUACAO == situation[1], 'SITUACAO'] = situation[0] def fix_admission(df): - for adm in AdmissionType.ADMISSION_FORM: - df.loc[df.FORMA_INGRESSO == adm[1], 'FORMA_INGRESSO'] = adm[0] + for adm in AdmissionType.ADMISSION_FORM: + df.loc[df.FORMA_INGRESSO == adm[1], 'FORMA_INGRESSO'] = adm[0] + +def fix_carga(df): + df["CH_TOTAL"] = df["CH_TEORICA"]+df["CH_PRATICA"] def fix_evasion(df): - evasionForms = [x[1] for x in EvasionForm.EVASION_FORM] - df.loc[~df.FORMA_EVASAO.isin(evasionForms), 'FORMA_EVASAO'] = 100 - for evasion in EvasionForm.EVASION_FORM: - # ~ df.loc[df.FORMA_EVASAO.str.contains(evasion[1]).fillna(1.0), 'FORMA_EVASAO'] = evasion[0] - df.loc[df.FORMA_EVASAO == evasion[1], 'FORMA_EVASAO'] = evasion[0] - - # ~ if(evasion[0] == 100): - # ~ for x in df.FORMA_EVASAO.str.contains(evasion[1]).fillna(False): - # ~ if(x != 0.0): - # ~ print(x) -# ~ print(df.FORMA_EVASAO.str.contains(evasion[1]).fillna(5)) -# ~ print(df[['MATR_ALUNO','FORMA_EVASAO']]) + evasionForms = [x[1] for x in EvasionForm.EVASION_FORM] + df.loc[~df.FORMA_EVASAO.isin(evasionForms), 'FORMA_EVASAO'] = 100 + for evasion in EvasionForm.EVASION_FORM: + #~ df.loc[df.FORMA_EVASAO.str.contains(evasion[1]).fillna(1.0), 'FORMA_EVASAO'] = evasion[0] + df.loc[df.FORMA_EVASAO == evasion[1], 'FORMA_EVASAO'] = evasion[0] + + #~ if(evasion[0] == 100): + #~ for x in df.FORMA_EVASAO.str.contains(evasion[1]).fillna(False): + #~ if(x != 0.0): + #~ print(x) + #~ print(df.FORMA_EVASAO.str.contains(evasion[1]).fillna(5)) + #~ print(df[['MATR_ALUNO','FORMA_EVASAO']]) diff --git a/src/script/build_cache.py b/src/script/build_cache.py index aae7dbc9a65c87bd220049c6a9575082b29f1176..82e411147bad8697993c09395f19c4ac7e8ca025 100644 --- a/src/script/build_cache.py +++ b/src/script/build_cache.py @@ -12,7 +12,6 @@ except NameError: def build_cache(dataframe): - # os.chdir("../src") path = 'cache/curso' @@ -108,6 +107,9 @@ def generate_student_data(path, dataframe): (aluno_turmas(dataframe), "aluno_turmas"), + + (taxa_aprovacao(dataframe), + "taxa_aprovacao"), ] for x in student_data: @@ -116,6 +118,21 @@ def generate_student_data(path, dataframe): save_json(path+x+".json", student_data[x]) + listagens_arquivos = [ + EvasionForm.EF_ABANDONO, + EvasionForm.EF_DESISTENCIA, + EvasionForm.EF_FORMATURA, + EvasionForm.EF_ATIVO + ] + + listagens = listagem_alunos(dataframe) + for l in listagens: + if(l in listagens_arquivos): + save_json(path+"listagem/"+str(l)+".json", listagens[l]) + + + + #Falta verificar se alguem nao recebeu algumas analises def generate_student_list(path): diff --git a/src/script/main.py b/src/script/main.py index a87bb15069645f737c2f853dd22ea4b01ce555eb..fb45fa4376ba1c55fd62aa39c2787af16ba594c1 100644 --- a/src/script/main.py +++ b/src/script/main.py @@ -1,8 +1,10 @@ import os import time -from datetime import timedelta from script.base.dataframe_base import load_dataframes from script.build_cache import build_cache +from script.analysis.course_analysis import * + +from datetime import timedelta def analyze(submission): @@ -13,6 +15,11 @@ def analyze(submission): build_cache(dataframe) + submission.processed = True + + submission.process_time = round(time.clock() - start_time) + submission.save() + cpu_time = timedelta(seconds=round(time.clock() - start_time)) run_time = timedelta(seconds=round(time.time() - start_time_exec)) print("--- Tempo de CPU: {} ---".format(cpu_time)) @@ -24,13 +31,9 @@ def main(): start_time_exec = time.time() dataframe = load_dataframes(os.getcwd() + '/script/' + 'base') - # ~ for i, line in enumerate(dataframe): - # ~ print(type(dataframe["MEDIA_FINAL"][i])) - # ~ print(dataframe["MEDIA_FINAL"][i]) - # ~ print(dataframe) build_cache(dataframe) - cpu_time = timedelta(seconds=round(time.clock() - start_time)) + analises_disciplinas(dataframe) run_time = timedelta(seconds=round(time.time() - start_time_exec)) print("--- Tempo de CPU: {} ---".format(cpu_time)) print("--- Tempo total: {} ---".format(run_time)) diff --git a/src/script/utils/situations.py b/src/script/utils/situations.py index e62c509f8884a379b25826ec9f7a5423bfb6b838..d44993528dbff0fc440702eacae7b1cfc44efaf1 100644 --- a/src/script/utils/situations.py +++ b/src/script/utils/situations.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # == Admission Form == # class AdmissionType: AT_DESCONHECIDO = 0 @@ -65,6 +66,14 @@ class EvasionForm: ) # == Situation Courses == # +#note: os valores da coluna media_final não são confiavel, situation como +# reprovacao,reprovacao_freq,dispensa_com_nota aparecem em algumas linha como +# 9999, o valor 9999 é o valor definido pelo sie para ser o 'null' na tabela +# .33, na tabela .18 o 'null' é o zero e não ocorre problema de calculo de +# nota/ira +# orientaçao: verificar se media_final é maior que 100 se sim atribua 0 se nao +# atribua media_final + class Situation: SIT_DESCONHECIDA = 0 @@ -89,6 +98,8 @@ class Situation: SIT_APROV_ADIANTAMENTO = 15 SIT_INCOMPLETO = 16 + + SIT_REPROVADO_ADIAN = 17 SIT_OUTROS = 100 @@ -98,6 +109,7 @@ class Situation: (SIT_REPROVADO, 'Reprovado por nota'), (SIT_MATRICULA, 'MatrÃcula'), (SIT_REPROVADO_FREQ, 'Reprovado por Frequência'), + (SIT_REPROVADO_ADIAN, 'Reprov Adiantamento'), (SIT_EQUIVALENCIA, 'Equivalência de Disciplina'), (SIT_CANCELADO, 'Cancelado'), @@ -123,6 +135,7 @@ class Situation: SIT_REPROVADO_FREQ, SIT_DISPENSA_COM_NOTA, SIT_CONHECIMENTO_APROVADO, + SIT_REPROVADO_ADIAN, SIT_CONHECIMENTO_REPROVADO ) @@ -135,6 +148,7 @@ class Situation: SITUATION_FAIL = ( SIT_REPROVADO, SIT_REPROVADO_FREQ, + SIT_REPROVADO_ADIAN, SIT_CONHECIMENTO_REPROVADO ) diff --git a/src/uploads/admin.py b/src/uploads/admin.py index f6770b002b386aa4a54922d3d8c86872aada55f9..99875aefe6a3f8cef6aa2978c97da412fabf3851 100644 --- a/src/uploads/admin.py +++ b/src/uploads/admin.py @@ -13,11 +13,6 @@ def make_analysis(modeladmin, request, queryset): print('analisando: '+str(submission)) analyze(submission) - submission.processed = True - - print('salvando') - submission.save() - print('OK') except: print('Análise falhou') @@ -33,4 +28,4 @@ class SubmissionAdmin(admin.ModelAdmin): actions = [make_analysis] -admin.site.register(Submission, SubmissionAdmin) \ No newline at end of file +admin.site.register(Submission, SubmissionAdmin) diff --git a/src/uploads/models.py b/src/uploads/models.py index b2786fcaf539dc9e12c9a0a62bbc45df8a778bf8..ac914d6b405786ff520463a8c5ccf0981200b52e 100644 --- a/src/uploads/models.py +++ b/src/uploads/models.py @@ -24,6 +24,8 @@ class Submission(models.Model): processed = models.BooleanField(default=False) + process_time = models.IntegerField(null=True) + def path(self): return path.join(settings.MEDIA_ROOT, self.course, str(self.id))