import pandas as pd import gradio as gr from gradio import components from gradio import Interface import numpy as np import statsmodels import statsmodels.api as sm from statsmodels.stats.stattools import jarque_bera import plotly.express as px import plotly.graph_objects as go import matplotlib.pyplot as plt import seaborn as sns # função para conversão da escala das variáveis: def aplicar_operacao(df, scv, col_index): if scv == 'x': pass elif scv == 'lnx': df.iloc[:, col_index] = round(np.log(df.iloc[:, col_index]), 8) elif scv == '1/x': df.iloc[:, col_index] = round(1 / df.iloc[:, col_index], 8) elif scv == 'x²': df.iloc[:, col_index] = round(df.iloc[:, col_index] ** 2, 8) elif scv == 'y': pass elif scv == 'lny': df.iloc[:, col_index] = round(np.log(df.iloc[:, col_index]), 8) elif scv == '1/y': df.iloc[:, col_index] = round(1 / df.iloc[:, col_index], 8) elif scv == 'y²': df.iloc[:, col_index] = round(df.iloc[:, col_index] ** 2, 8) # função para plotagem dos gráficos de dispersão: def criar_grafico_dispersao(df, x_column, y_column, hover_name, trendline_color): # Calculando a correlação entre as variáveis x e y correlacao = df[x_column].corr(df[y_column]) # Criando o gráfico de dispersão com a linha de tendência fig = px.scatter(df, x=x_column, y=y_column, hover_name=hover_name, trendline="ols") # Definindo a cor de fundo e do papel fig.update_layout( plot_bgcolor='rgb(240, 240, 240)', paper_bgcolor='rgb(240, 240, 240)' ) # Definindo a cor dos pontos fig.update_traces(marker=dict(color=trendline_color, size=8)) # Definindo a cor da linha de tendência fig.update_traces(line=dict(color="black")) # Adicionando o texto com a correlação na linha de tendência fig.add_annotation( x=df[x_column].max(), y=df[y_column].max(), text=f"Correlação: {correlacao:.2f}", showarrow=False, font=dict(color="black") ) return fig # função para a regressão linear def avaliacao_imovel(planilha, v_1, v_2, v_3, v_4, v_5, v_6, v_7, scv_d, scv_1, scv_2, scv_3, scv_4, scv_5, scv_6, scv_7, linhas): # ---------------------------------Planilha------------------------------# df_dados = pd.read_excel(planilha.name) df_original = df_dados.copy() #-----------------------------------Escalas------------------------------# aplicar_operacao(df_dados, scv_d, 1) aplicar_operacao(df_dados, scv_1, 2) aplicar_operacao(df_dados, scv_2, 3) aplicar_operacao(df_dados, scv_3, 4) aplicar_operacao(df_dados, scv_4, 5) aplicar_operacao(df_dados, scv_5, 6) aplicar_operacao(df_dados, scv_6, 7) aplicar_operacao(df_dados, scv_7, 8) #----------------Manipulação das linhas (dados / outiliers----------------# num_linhas = df_dados.shape[0] linhas_selecionadas = [int(linha) - 1 for linha in linhas if int(linha) - 1 < num_linhas] df_filtrado = df_dados.iloc[linhas_selecionadas] df_outliers = df_dados.drop(linhas_selecionadas) df_filtrado.sort_values(by=df_filtrado.columns[0], inplace=True) #----------------Manipulação das Colunas (variáveis)-----------------------# # Variáveis independentes X = pd.DataFrame() # Iterar sobre as colunas do DataFrame df_filtrado for i, col in enumerate(df_filtrado.columns): # Verificar se a coluna atual deve ser adicionada com base na condição e se ela existe no DataFrame if (i == 2 and v_1) or (i == 3 and v_2) or (i == 4 and v_3) or (i == 5 and v_4) or (i == 6 and v_5) or (i == 7 and v_6) or (i == 8 and v_7): if i < len(df_filtrado.columns): X[col] = df_filtrado.iloc[:, i] #---------------------------Gráficos de dispersão--------------------------# fig_v1 = None fig_v2 = None fig_v3 = None fig_v4 = None fig_v5 = None fig_v6 = None fig_v7 = None if v_1: fig_v1 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[2], df_filtrado.columns[1], df_filtrado.columns[0], "orange") if v_2: fig_v2 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[3], df_filtrado.columns[1], df_filtrado.columns[0], "orange") if v_3: fig_v3 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[4], df_filtrado.columns[1], df_filtrado.columns[0], "orange") if v_4: fig_v4 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[5], df_filtrado.columns[1], df_filtrado.columns[0], "orange") if v_5: fig_v5 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[6], df_filtrado.columns[1], df_filtrado.columns[0], "orange") if v_6: fig_v6 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[7], df_filtrado.columns[1], df_filtrado.columns[0], "orange") if v_7: fig_v7 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[8], df_filtrado.columns[1], df_filtrado.columns[0], "orange") #--------------------------Regressão Linerar------------------------------# # Variável dependente y = df_filtrado.iloc[:, 1:2] # Adicionando uma constante à variável independente (intercepto) X = sm.add_constant(X) # Inicializando o modelo de regressão linear modelo = sm.OLS(y, X) # Ajustando o modelo aos dados resultado = modelo.fit() # Calculando os resíduos do modelo residuos = resultado.resid # Calculando Desvio Padrão dos Resíduos #desvio_padrao_residuos = round(np.std(resultado.resid), 8) desvio_padrao_residuos = round(np.std(residuos), 8) # Calculando Estatística F estatistica_F = round(resultado.fvalue, 8) # Obtendo Nível de Significância do Modelo nivel_significancia = round(resultado.f_pvalue, 8) # Calculando R² r_squared = round(resultado.rsquared, 8) # Calculando R² ajustado r_squared_adjusted = round(resultado.rsquared_adj, 8) # Obtendo Número de Observações num_observacoes = round(resultado.nobs, 0) # Calculando Coeficiente de Correlação coef_correlacao = round(np.sqrt(r_squared), 8) # Calculando o teste de Jarque-Bera para os resíduos jarque_bera_test, p_value, skewness, kurtosis = jarque_bera(residuos) # Formatando os resultados com 4 casas decimais jarque_bera_test = round(jarque_bera_test, 8) p_value = round(p_value, 8) skewness = round(skewness, 8) kurtosis = round(kurtosis, 8) # Extrair os coeficientes da regressão coeficientes = resultado.params # Calcular a distância de Cook distancia_cook = resultado.get_influence().cooks_distance[0] # String com os resultados resultados_gerais = f""" Desvio Padrão: {desvio_padrao_residuos} Estatística F: {estatistica_F} Nível de Significância do Modelo: {nivel_significancia} R²: {r_squared} R² ajustado: {r_squared_adjusted} Número de observações: {num_observacoes} Coeficianete de Correlação: {coef_correlacao} Teste de Jarque-Bera: - Estatística do teste: {jarque_bera_test} - Valor-p: {p_value} - Assimetria (Skewness): {skewness} - Curtose (Kurtosis): {kurtosis} """ # Equação do modelo # Inicialize a equação do modelo if scv_d == 'y': equacao_modelo = "y =" elif scv_d == 'lny': equacao_modelo = "ln(y) =" elif scv_d == '1/y': equacao_modelo = "1/y =" elif scv_d == 'y²': equacao_modelo = "y² =" # Iterar sobre os coeficientes estimados for nome_coluna, coeficiente in zip(X.columns, coeficientes): # Se o nome da coluna for 'const', adicione apenas o coeficiente if nome_coluna == 'const': equacao_modelo += f" {coeficiente:.8f} +" else: # Adicionar o termo à equação do modelo equacao_modelo += f" {coeficiente:.8f} * {nome_coluna} +" # Remover o último sinal de adição equacao_modelo = equacao_modelo[:-1] # Exibindo estatísticas do modelo resultado_summary = resultado.summary() resultado_html = resultado.summary().tables[1].as_html() # Obtenha as estatísticas do modelo em formato de DataFrame #resultado_summary_df = pd.DataFrame(resultado_summary.tables[1]) #---------------------df_final (utilizado na regressão)----------------------# # Adicionando a primeira coluna de df_filtrado ao início de df_final ordem = df_filtrado[[df_filtrado.columns[0]]].copy() df_final = pd.concat([ordem, y, X], axis=1) df_final = df_final.drop(columns=['const']) #--------------------df_final (adiciona o erro_padronizado)------------------# # Calculando o erro padronizado erro_padronizado = round(residuos / desvio_padrao_residuos, 5) # Adicionando a coluna de erro padronizado ao df_final df_final['Erro Padronizado'] = erro_padronizado #-------------------df_maiores_que_2 (possíveis outliers)--------------------# # Criar DataFrame apenas com os dados cujo erro padronizado é maior que 2 df_maiores_que_2 = df_final[abs(df_final['Erro Padronizado']) > 2] #------------df_correl (Valores Ajustados x Preços Observados)---------------# # Obtendo os valores previstos valores_previstos = resultado.predict(X) # Adicionando os valores previstos como uma nova coluna ao df_final df_final['Valores Ajustados'] = round(valores_previstos, 8) # Criando uma dataframe para os Valores Ajustados x Preços Observados df_correl = df_final[[df_filtrado.columns[0], df_filtrado.columns[1], 'Valores Ajustados']] df_correl = df_correl.rename(columns={df_filtrado.columns[1]: 'Preços Observados'}) # Desfazendo a conversão da escala if scv_d == 'lnx': df_correl['Valores Ajustados'] = round(np.exp(df_correl['Valores Ajustados']), 8) df_correl['Preços Observados'] = round(np.exp(df_correl['Preços Observados']), 8) elif scv_d == '1/x': df_correl['Valores Ajustados'] = round(1 / df_correl['Valores Ajustados'], 8) df_correl['Preços Observados'] = round(1 / df_correl['Preços Observados'], 8) elif scv_d == 'x²': df_correl['Valores Ajustados'] = round(np.sqrt(df_correl['Valores Ajustados']), 8) df_correl['Preços Observados'] = round(np.sqrt(df_correl['Preços Observados']), 8) else: pass # Nenhuma transformação é necessária df_correl['Diferença %'] = round(((df_correl['Valores Ajustados']/df_correl['Preços Observados'])-1)*100, 8) #------------Gráficos dos Valores Ajustados x Resíduos Padronizados e Histograma---------------# # Criando subplots fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(8, 12)) # Plotagem dos resíduos padronizados ax1.scatter(df_final['Valores Ajustados'], erro_padronizado, color='orange', alpha=0.6) ax1.axhline(y=0, color='black', linestyle='--', linewidth=1) # Linha zero ax1.axhline(y=2, color='red', linestyle='-', linewidth=1) # Linhas vermelhas em ±2 ax1.axhline(y=-2, color='red', linestyle='-', linewidth=1) ax1.set_title('Gráfico de Resíduos Padronizados') ax1.set_xlabel('Valores Ajustados') ax1.set_ylabel('Resíduos Padronizados') ax1.grid(True) # Adicionando rótulos aos pontos com resíduos padronizados > 2 #for i, txt in enumerate(df_final.iloc[:, 0]): #if abs(erro_padronizado[i]) > 2: #ax1.annotate(txt, (df_final['Valores Ajustados'][i], erro_padronizado[i]), color='black') # Histograma dos resíduos padronizados sns.histplot(erro_padronizado, kde=True, color='orange', alpha=0.6, ax=ax2) ax2.set_title('Histograma dos Resíduos Padronizados') ax2.set_xlabel('Resíduos Padronizados') ax2.set_ylabel('Frequência') ax2.grid(True) # Gráfico da distância de Cook ax3.plot(distancia_cook, marker='o', linestyle='None', color='orange') ax3.axhline(y=1, color='red', linestyle='--', linewidth=1) ax3.set_title('Gráfico da Distância de Cook') ax3.set_xlabel('Número da Observação') ax3.set_ylabel('Distância de Cook') ax3.grid(True) # Adicionando rótulos aos pontos for i, txt in enumerate(df_final.iloc[:, 0]): ax3.annotate(txt, (i, distancia_cook[i])) # Ajustando a posição dos subplots plt.tight_layout() # Exibindo os subplots plt.show() # Listagem de pontos discrepantes limite_cook = 4 / (len(df_final) - len(resultado.params)) pontos_discrepantes = [] for i, cook_dist in enumerate(distancia_cook): if cook_dist > limite_cook: pontos_discrepantes.append(df_final.iloc[i, 0]) # Usando a primeira coluna como rótulo # Listagem de pontos influentes limite_cook = 1 pontos_influentes = [] for i, cook_dist in enumerate(distancia_cook): if cook_dist > limite_cook: pontos_influentes.append(df_final.iloc[i, 0]) # Usando a primeira coluna como rótulo #---------------------------------------Outputs----------------------------------# return df_original, resultados_gerais, resultado_html, equacao_modelo, df_final, df_maiores_que_2, df_outliers, df_correl, fig_v1, fig_v2, fig_v3, fig_v4, fig_v5, fig_v6, fig_v7, plt, pontos_discrepantes, pontos_influentes #df_filtrado,resultado_summary_df, #--------------------------------------Interface---------------------------------# numeros = [str(i) for i in range(0, 501)] with gr.Blocks(theme=gr.themes.Monochrome(), title="avalia.se") as demo: gr.Markdown(f"""

Módulo de Regressão Linear

Aplicativo MCDDM com tratamento científico / Para ver a documentação, você pode baixar aqui

""") with gr.Row(): with gr.Column(): file_input = gr.File(label="Upload planilha", type="filepath") var_checkboxes = [gr.Checkbox(value=False, label=f"Variável independente {i}") for i in range(1, 8)] escala_dependente = gr.Radio(['y', 'lny', '1/y', 'y²'], label="Escala VARIÁVEL DEPENDENTE", value='x') escala_independente = [gr.Radio(['x', 'lnx', '1/x', 'x²'], label=f"---> Escala variável independente {i}", value='x') for i in range(1, 8)] dados = gr.components.CheckboxGroup(numeros, value=numeros[1:501], label="Selecionar dados", type="index") with gr.Column(): output1 = gr.Dataframe(label="Planilha de dados original") output2 = gr.Textbox(label="Resultados Gerais do Modelo") output3 = gr.HTML(label="Resultados por variável") output4 = gr.Textbox(label="Equação do Modelo") # Add more outputs here following the same pattern submit_btn = gr.Button("Avaliar") submit_btn.click(avaliacao_imovel, inputs=[file_input] + var_checkboxes + [escala_dependente] + escala_independente + [dados], outputs=[output1, output2, output3, output4]) demo.launch(debug=True)