DavidSB commited on
Commit
809e4c9
·
verified ·
1 Parent(s): c2ca673

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +357 -0
app.py ADDED
@@ -0,0 +1,357 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import gradio as gr
3
+ import numpy as np
4
+ import statsmodels.api as sm
5
+ from statsmodels.stats.stattools import jarque_bera
6
+ import textwrap
7
+ import plotly.express as px
8
+ import plotly.graph_objects as go
9
+ import matplotlib.pyplot as plt
10
+ import seaborn as sns
11
+
12
+ # função para conversão da escala das variáveis:
13
+ def aplicar_operacao(df, scv, col_index):
14
+ if scv == 'x':
15
+ pass
16
+ elif scv == 'lnx':
17
+ df.iloc[:, col_index] = round(np.log(df.iloc[:, col_index]), 3)
18
+ elif scv == '1/x':
19
+ df.iloc[:, col_index] = round(1 / df.iloc[:, col_index], 3)
20
+ elif scv == 'x²':
21
+ df.iloc[:, col_index] = round(df.iloc[:, col_index] ** 2, 3)
22
+
23
+ # função para plotagem dos gráficos de dispersão:
24
+ def criar_grafico_dispersao(df, x_column, y_column, hover_name, trendline_color):
25
+ # Calculando a correlação entre as variáveis x e y
26
+ correlacao = df[x_column].corr(df[y_column])
27
+
28
+ # Criando o gráfico de dispersão com a linha de tendência
29
+ fig = px.scatter(df, x=x_column, y=y_column, hover_name=hover_name, trendline="ols")
30
+ # Definindo a cor de fundo e do papel
31
+ fig.update_layout(
32
+ plot_bgcolor='rgb(240, 240, 240)',
33
+ paper_bgcolor='rgb(240, 240, 240)'
34
+ )
35
+ # Definindo a cor dos pontos
36
+ fig.update_traces(marker=dict(color=trendline_color, size=8))
37
+ # Definindo a cor da linha de tendência
38
+ fig.update_traces(line=dict(color="black"))
39
+ # Adicionando o texto com a correlação na linha de tendência
40
+ fig.add_annotation(
41
+ x=df[x_column].max(),
42
+ y=df[y_column].max(),
43
+ text=f"Correlação: {correlacao:.2f}",
44
+ showarrow=False,
45
+ font=dict(color="black")
46
+ )
47
+ return fig
48
+
49
+ # função para a regressão linear
50
+ 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):
51
+
52
+ # ---------------------------------Planilha------------------------------#
53
+
54
+ df_dados = pd.read_excel(planilha.name)
55
+ df_original = df_dados.copy()
56
+
57
+ #-----------------------------------Escalas------------------------------#
58
+
59
+ aplicar_operacao(df_dados, scv_d, 1)
60
+ aplicar_operacao(df_dados, scv_1, 2)
61
+ aplicar_operacao(df_dados, scv_2, 3)
62
+ aplicar_operacao(df_dados, scv_3, 4)
63
+ aplicar_operacao(df_dados, scv_4, 5)
64
+ aplicar_operacao(df_dados, scv_5, 6)
65
+ aplicar_operacao(df_dados, scv_6, 7)
66
+ aplicar_operacao(df_dados, scv_7, 8)
67
+
68
+ #----------------Manipulação das linhas (dados / outiliers----------------#
69
+
70
+ num_linhas = df_dados.shape[0]
71
+ linhas_selecionadas = [int(linha) - 1 for linha in linhas if int(linha) - 1 < num_linhas]
72
+ df_filtrado = df_dados.iloc[linhas_selecionadas]
73
+ df_outliers = df_dados.drop(linhas_selecionadas)
74
+ df_filtrado.sort_values(by=df_filtrado.columns[0], inplace=True)
75
+
76
+ #----------------Manipulação das Colunas (variáveis)-----------------------#
77
+
78
+ # Variáveis independentes
79
+ X = pd.DataFrame()
80
+
81
+ # Iterar sobre as colunas do DataFrame df_filtrado
82
+ for i, col in enumerate(df_filtrado.columns):
83
+ # Verificar se a coluna atual deve ser adicionada com base na condição e se ela existe no DataFrame
84
+ 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):
85
+ if i < len(df_filtrado.columns):
86
+ X[col] = df_filtrado.iloc[:, i]
87
+
88
+ #---------------------------Gráficos de dispersão--------------------------#
89
+
90
+ fig_v1 = None
91
+ fig_v2 = None
92
+ fig_v3 = None
93
+ fig_v4 = None
94
+ fig_v5 = None
95
+ fig_v6 = None
96
+ fig_v7 = None
97
+
98
+ if v_1:
99
+ fig_v1 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[2], df_filtrado.columns[1], df_filtrado.columns[0], "orange")
100
+ if v_2:
101
+ fig_v2 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[3], df_filtrado.columns[1], df_filtrado.columns[0], "orange")
102
+ if v_3:
103
+ fig_v3 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[4], df_filtrado.columns[1], df_filtrado.columns[0], "orange")
104
+ if v_4:
105
+ fig_v4 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[5], df_filtrado.columns[1], df_filtrado.columns[0], "orange")
106
+ if v_5:
107
+ fig_v5 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[6], df_filtrado.columns[1], df_filtrado.columns[0], "orange")
108
+ if v_6:
109
+ fig_v6 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[7], df_filtrado.columns[1], df_filtrado.columns[0], "orange")
110
+ if v_7:
111
+ fig_v7 = criar_grafico_dispersao(df_filtrado, df_filtrado.columns[8], df_filtrado.columns[1], df_filtrado.columns[0], "orange")
112
+
113
+ #--------------------------Regressão Linerar------------------------------#
114
+
115
+ # Variável dependente
116
+ y = df_filtrado.iloc[:, 1:2]
117
+
118
+ # Adicionando uma constante à variável independente (intercepto)
119
+ X = sm.add_constant(X)
120
+
121
+ # Inicializando o modelo de regressão linear
122
+ modelo = sm.OLS(y, X)
123
+
124
+ # Ajustando o modelo aos dados
125
+ resultado = modelo.fit()
126
+
127
+ # Calculando os resíduos do modelo
128
+ residuos = resultado.resid
129
+
130
+ # Calculando Desvio Padrão dos Resíduos
131
+ #desvio_padrao_residuos = round(np.std(resultado.resid), 4)
132
+ desvio_padrao_residuos = round(np.std(residuos), 4)
133
+ # Calculando Estatística F
134
+ estatistica_F = round(resultado.fvalue, 4)
135
+ # Obtendo Nível de Significância do Modelo
136
+ nivel_significancia = round(resultado.f_pvalue, 4)
137
+ # Calculando R²
138
+ r_squared = round(resultado.rsquared, 4)
139
+ # Calculando R² ajustado
140
+ r_squared_adjusted = round(resultado.rsquared_adj, 4)
141
+ # Obtendo Número de Observações
142
+ num_observacoes = round(resultado.nobs, 0)
143
+ # Calculando Coeficiente de Correlação
144
+ coef_correlacao = round(np.sqrt(r_squared), 4)
145
+ # Calculando o teste de Jarque-Bera para os resíduos
146
+ jarque_bera_test, p_value, skewness, kurtosis = jarque_bera(residuos)
147
+ # Formatando os resultados com 4 casas decimais
148
+ jarque_bera_test = round(jarque_bera_test, 4)
149
+ p_value = round(p_value, 4)
150
+ skewness = round(skewness, 4)
151
+ kurtosis = round(kurtosis, 4)
152
+ # Extrair os coeficientes da regressão
153
+ coeficientes = resultado.params
154
+ # Calcular a distância de Cook
155
+ distancia_cook = resultado.get_influence().cooks_distance[0]
156
+
157
+ # String com os resultados
158
+ resultados_gerais = f"""
159
+ Desvio Padrão: {desvio_padrao_residuos}
160
+ Estatística F: {estatistica_F}
161
+ Nível de Significância do Modelo: {nivel_significancia}
162
+ R²: {r_squared}
163
+ R² ajustado: {r_squared_adjusted}
164
+ Número de observações: {num_observacoes}
165
+ Coeficianete de Correlação: {coef_correlacao}
166
+ Teste de Jarque-Bera:
167
+ - Estatística do teste: {jarque_bera_test}
168
+ - Valor-p: {p_value}
169
+ - Assimetria (Skewness): {skewness}
170
+ - Curtose (Kurtosis): {kurtosis}
171
+ """
172
+
173
+ # Equação do modelo
174
+ # Inicialize a equação do modelo
175
+ equacao_modelo = "y ="
176
+ # Iterar sobre os coeficientes estimados
177
+ for nome_coluna, coeficiente in zip(X.columns, coeficientes):
178
+ # Se o nome da coluna for 'const', adicione apenas o coeficiente
179
+ if nome_coluna == 'const':
180
+ equacao_modelo += f" {coeficiente:.4f} +"
181
+ else:
182
+ # Adicionar o termo à equação do modelo
183
+ equacao_modelo += f" {coeficiente:.4f} * {nome_coluna} +"
184
+ # Remover o último sinal de adição
185
+ equacao_modelo = equacao_modelo[:-1]
186
+ # Exibindo estatísticas do modelo
187
+ resultado_summary = resultado.summary()
188
+ resultado_html = resultado.summary().tables[1].as_html()
189
+ # Obtenha as estatísticas do modelo em formato de DataFrame
190
+ #resultado_summary_df = pd.DataFrame(resultado_summary.tables[1])
191
+
192
+ #---------------------df_final (utilizado na regressão)----------------------#
193
+
194
+ # Adicionando a primeira coluna de df_filtrado ao início de df_final
195
+ ordem = df_filtrado[[df_filtrado.columns[0]]].copy()
196
+ df_final = pd.concat([ordem, y, X], axis=1)
197
+ df_final = df_final.drop(columns=['const'])
198
+
199
+ #--------------------df_final (adiciona o erro_padronizado)------------------#
200
+
201
+ # Calculando o erro padronizado
202
+ erro_padronizado = round(residuos / desvio_padrao_residuos, 3)
203
+ # Adicionando a coluna de erro padronizado ao df_final
204
+ df_final['Erro Padronizado'] = erro_padronizado
205
+
206
+ #-------------------df_maiores_que_2 (possíveis outliers)--------------------#
207
+
208
+ # Criar DataFrame apenas com os dados cujo erro padronizado é maior que 2
209
+ df_maiores_que_2 = df_final[abs(df_final['Erro Padronizado']) > 2]
210
+
211
+ #------------df_correl (Valores Ajustados x Preços Observados)---------------#
212
+
213
+ # Obtendo os valores previstos
214
+ valores_previstos = resultado.predict(X)
215
+ # Adicionando os valores previstos como uma nova coluna ao df_final
216
+ df_final['Valores Ajustados'] = round(valores_previstos, 2)
217
+ # Criando uma dataframe para os Valores Ajustados x Preços Observados
218
+ df_correl = df_final[[df_filtrado.columns[0], df_filtrado.columns[1], 'Valores Ajustados']]
219
+ df_correl = df_correl.rename(columns={df_filtrado.columns[1]: 'Preços Observados'})
220
+ # Desfazendo a conversão da escala
221
+ if scv_d == 'lnx':
222
+ df_correl['Valores Ajustados'] = round(np.exp(df_correl['Valores Ajustados']), 2)
223
+ df_correl['Preços Observados'] = round(np.exp(df_correl['Preços Observados']), 2)
224
+ elif scv_d == '1/x':
225
+ df_correl['Valores Ajustados'] = round(1 / df_correl['Valores Ajustados'], 2)
226
+ df_correl['Preços Observados'] = round(1 / df_correl['Preços Observados'], 2)
227
+ elif scv_d == 'x²':
228
+ df_correl['Valores Ajustados'] = round(np.sqrt(df_correl['Valores Ajustados']), 2)
229
+ df_correl['Preços Observados'] = round(np.sqrt(df_correl['Preços Observados']), 2)
230
+ else:
231
+ pass # Nenhuma transformação é necessária
232
+
233
+ df_correl['Diferença %'] = round(((df_correl['Valores Ajustados']/df_correl['Preços Observados'])-1)*100, 2)
234
+
235
+ #------------Gráficos dos Valores Ajustados x Resíduos Padronizados e Histograma---------------#
236
+
237
+ # Criando subplots
238
+ fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(8, 12))
239
+
240
+ # Plotagem dos resíduos padronizados
241
+ ax1.scatter(df_final['Valores Ajustados'], erro_padronizado, color='orange', alpha=0.6)
242
+ ax1.axhline(y=0, color='black', linestyle='--', linewidth=1) # Linha zero
243
+ ax1.axhline(y=2, color='red', linestyle='-', linewidth=1) # Linhas vermelhas em ±2
244
+ ax1.axhline(y=-2, color='red', linestyle='-', linewidth=1)
245
+ ax1.set_title('Gráfico de Resíduos Padronizados')
246
+ ax1.set_xlabel('Valores Ajustados')
247
+ ax1.set_ylabel('Resíduos Padronizados')
248
+ ax1.grid(True)
249
+
250
+ # Adicionando rótulos aos pontos com resíduos padronizados > 2
251
+ #for i, txt in enumerate(df_final.iloc[:, 0]):
252
+ #if abs(erro_padronizado[i]) > 2:
253
+ #ax1.annotate(txt, (df_final['Valores Ajustados'][i], erro_padronizado[i]), color='black')
254
+
255
+ # Histograma dos resíduos padronizados
256
+ sns.histplot(erro_padronizado, kde=True, color='orange', alpha=0.6, ax=ax2)
257
+ ax2.set_title('Histograma dos Resíduos Padronizados')
258
+ ax2.set_xlabel('Resíduos Padronizados')
259
+ ax2.set_ylabel('Frequência')
260
+ ax2.grid(True)
261
+
262
+ # Gráfico da distância de Cook
263
+ ax3.plot(distancia_cook, marker='o', linestyle='None', color='orange')
264
+ ax3.axhline(y=1, color='red', linestyle='--', linewidth=1)
265
+ ax3.set_title('Gráfico da Distância de Cook')
266
+ ax3.set_xlabel('Número da Observação')
267
+ ax3.set_ylabel('Distância de Cook')
268
+ ax3.grid(True)
269
+
270
+ # Adicionando rótulos aos pontos
271
+ for i, txt in enumerate(df_final.iloc[:, 0]):
272
+ ax3.annotate(txt, (i, distancia_cook[i]))
273
+
274
+ # Ajustando a posição dos subplots
275
+ plt.tight_layout()
276
+
277
+ # Exibindo os subplots
278
+ plt.show()
279
+
280
+ # Listagem de pontos discrepantes
281
+ limite_cook = 4 / (len(df_final) - len(resultado.params))
282
+ pontos_discrepantes = []
283
+ for i, cook_dist in enumerate(distancia_cook):
284
+ if cook_dist > limite_cook:
285
+ pontos_discrepantes.append(df_final.iloc[i, 0]) # Usando a primeira coluna como rótulo
286
+ # Listagem de pontos influentes
287
+ limite_cook = 1
288
+ pontos_influentes = []
289
+ for i, cook_dist in enumerate(distancia_cook):
290
+ if cook_dist > limite_cook:
291
+ pontos_influentes.append(df_final.iloc[i, 0]) # Usando a primeira coluna como rótulo
292
+
293
+ #---------------------------------------Outputs----------------------------------#
294
+
295
+ 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
296
+
297
+ #df_filtrado,resultado_summary_df,
298
+
299
+ #--------------------------------------Interface---------------------------------#
300
+
301
+ numeros = [str(i) for i in range(0, 501)]
302
+
303
+ interface = gr.Interface(
304
+ fn=avaliacao_imovel,
305
+ inputs=[
306
+ gr.components.File(label="Upload planilha", type="file", info="Importação de planilha"),
307
+ gr.components.Checkbox(value=False, label="Variável independente 1"),
308
+ gr.components.Checkbox(value=False, label="Variável independente 2"),
309
+ gr.components.Checkbox(value=False, label="Variável independente 3"),
310
+ gr.components.Checkbox(value=False, label="Variável independente 4"),
311
+ gr.components.Checkbox(value=False, label="Variável independente 5"),
312
+ gr.components.Checkbox(value=False, label="Variável independente 6"),
313
+ gr.components.Checkbox(value=False, label="Variável independente 7"),
314
+ gr.Radio(['x', 'lnx', '1/x', 'x²'], label="Escala VARIÁVEL DEPENDENTE", value='x'),
315
+ gr.Radio(['x', 'lnx', '1/x', 'x²'], label="---> Escala variável independente 1", value='x'),
316
+ gr.Radio(['x', 'lnx', '1/x', 'x²'], label="---> Escala variável independente 2", value='x'),
317
+ gr.Radio(['x', 'lnx', '1/x', 'x²'], label="---> Escala variável independente 3", value='x'),
318
+ gr.Radio(['x', 'lnx', '1/x', 'x²'], label="---> Escala variável independente 4", value='x'),
319
+ gr.Radio(['x', 'lnx', '1/x', 'x²'], label="---> Escala variável independente 5", value='x'),
320
+ gr.Radio(['x', 'lnx', '1/x', 'x²'], label="---> Escala variável independente 6", value='x'),
321
+ gr.Radio(['x', 'lnx', '1/x', 'x²'], label="---> Escala variável independente 7", value='x'),
322
+ gr.components.CheckboxGroup(numeros, value=numeros[1:501], label="Selecionar dados", type="index"),
323
+ ],
324
+ outputs=[
325
+ gr.Dataframe(label="Planilha de dados original"),
326
+ #gr.Dataframe(label="Dados filtrados por linhas e variáveis com escalas convertidas"),
327
+ gr.Textbox(label ="Resultados Gerais do Modelo"),
328
+ gr.HTML(label="Resumo da Regress��o", info = "Resultados por variável"),
329
+ #gr.Dataframe(label="Resultados por variável"),
330
+ gr.Textbox(label ="Equação do Modelo"),
331
+ gr.Dataframe(label="Planilha Regressão Linear (Variáveis e escalas escolhidas e sem outliers)"),
332
+ gr.Dataframe(label="Resíduos Padronizados > 2"),
333
+ gr.Dataframe(label="Outliers (retirados)"),
334
+ gr.Dataframe(label="Valores Ajustados x Preços Observados"),
335
+ gr.Plot(label="Gráfico Dispersão var 1"),
336
+ gr.Plot(label="Gráfico Dispersão var 2"),
337
+ gr.Plot(label="Gráfico Dispersão var 3"),
338
+ gr.Plot(label="Gráfico Dispersão var 4"),
339
+ gr.Plot(label="Gráfico Dispersão var 5"),
340
+ gr.Plot(label="Gráfico Dispersão var 6"),
341
+ gr.Plot(label="Gráfico Dispersão var 7"),
342
+ #gr.Plot(label="Valores Ajustados x Preços Observados"),
343
+ gr.Plot(label="Análise Gráfica do Modelo de Regressão"),
344
+ gr.Textbox(label ="Listagem de pontos discrepantes"),
345
+ gr.Textbox(label ="Listagem de pontos Influenciantes (Distância de Cook > 1)"),
346
+
347
+ ],
348
+ theme=gr.themes.Monochrome(),
349
+ title = "<span style='color: gray; font-size: 48px;'>avalia.se</span>",
350
+ description=f"""
351
+ <p style="text-align: left;"><b><span style='color: orange; font-size: 30px;'>Módulo de Regressão Linear</span></b></p>
352
+ <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>
353
+ """
354
+ )
355
+
356
+ if __name__ == "__main__":
357
+ interface.launch(debug=True)