Spaces:
Sleeping
Sleeping
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="<span style='color: gray; font-size: 48px;'>avalia.se</span>") as demo: | |
gr.Markdown(f""" | |
<p style="text-align: left;"><b><span style='color: orange; font-size: 30px;'>Módulo de Regressão Linear</span></b></p> | |
<p style="text-align: left;"></span>Aplicativo MCDDM com tratamento científico / Para ver a documentação, você pode baixar <a href='https://huggingface.co/spaces/DavidSB/avaliaFACTOR/resolve/main/dados_entrada_factor.xlsx' download='dados_entrada_factor.xlsx'>aqui</a><br><br></p> | |
""") | |
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) |