avalia-se commited on
Commit
3c4de5e
·
verified ·
1 Parent(s): 8fd6479

Upload 8 files

Browse files
modules/dados.py ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import plotly.express as px
3
+ import plotly.graph_objects as go
4
+ import gradio as gr
5
+ from math import radians, sin, cos, sqrt, atan2
6
+ import googlemaps
7
+ import locale
8
+ from .shared_state import state # Importa o estado compartilhado
9
+
10
+ # Inicializando o cliente Google Maps com a chave da API
11
+ gmaps = googlemaps.Client(key='AIzaSyDoJ6C7NE2CHqFcaHTnhreOfgJeTk4uSH0')
12
+
13
+ # Configurando o locale para português do Brasil
14
+ locale.setlocale(locale.LC_ALL, 'pt_BR.UTF-8')
15
+
16
+ # Load the data
17
+ data_path = 'data_2.xlsx'
18
+ df = pd.read_excel(data_path, sheet_name='Planilha1')
19
+ # Garantir que a coluna "Data" seja do tipo datetime
20
+ df['Data'] = pd.to_datetime(df['Data'], errors='coerce')
21
+
22
+ # Função para calcular a distância haversine
23
+ def haversine(lat1, lon1, lat2, lon2):
24
+ raio_terra = 6371000 # Raio da Terra em metros
25
+ dlat = radians(lat2 - lat1)
26
+ dlon = radians(lon2 - lon1)
27
+ a = sin(dlat / 2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon / 2)**2
28
+ c = 2 * atan2(sqrt(a), sqrt(1 - a))
29
+ return raio_terra * c
30
+
31
+ # Função unificada para gerar mapa, estatísticas, DataFrame filtrado e arquivo de download
32
+ def unified_action(selected_types, selected_bairros, selected_fonte, min_atotal, max_atotal, min_apriv, max_apriv, min_ater, max_ater, min_date, max_date, address=None, radius=None):
33
+ filtered_df = df.copy()
34
+
35
+ # Filtrando os dados com base nos tipos
36
+ if "Todos" not in selected_types:
37
+ filtered_df = filtered_df[filtered_df['Tipo'].isin(selected_types)]
38
+
39
+ # Filtrando os dados com base nos bairros
40
+ if "Todos" not in selected_bairros:
41
+ filtered_df = filtered_df[filtered_df['Bairro'].isin(selected_bairros)]
42
+
43
+ # Filtrando os dados com base na fonte
44
+ if "Todos" not in selected_fonte:
45
+ filtered_df = filtered_df[filtered_df['Fonte'].isin(selected_fonte)]
46
+
47
+ # Filtrando por área total
48
+ if min_atotal is not None:
49
+ filtered_df = filtered_df[filtered_df['Atotal'] >= min_atotal]
50
+ if max_atotal is not None:
51
+ filtered_df = filtered_df[filtered_df['Atotal'] <= max_atotal]
52
+
53
+ # Filtrando por área privativa
54
+ if min_apriv is not None:
55
+ filtered_df = filtered_df[filtered_df['Apriv'] >= min_apriv]
56
+ if max_apriv is not None:
57
+ filtered_df = filtered_df[filtered_df['Apriv'] <= max_apriv]
58
+
59
+ # Filtrando por área de terreno
60
+ if min_ater is not None:
61
+ filtered_df = filtered_df[filtered_df['Ater'] >= min_ater]
62
+ if max_ater is not None:
63
+ filtered_df = filtered_df[filtered_df['Ater'] <= max_ater]
64
+
65
+ # Filtrando por data, se especificada
66
+ if min_date is not None:
67
+ filtered_df = filtered_df[filtered_df['Data'] >= pd.to_datetime(min_date)]
68
+
69
+ if max_date is not None:
70
+ filtered_df = filtered_df[filtered_df['Data'] <= pd.to_datetime(max_date)]
71
+
72
+ # Filtrando por endereço e raio, se fornecidos
73
+ if address:
74
+ try:
75
+ result = gmaps.geocode(address)
76
+ if result:
77
+ coordinates = result[0]['geometry']['location']
78
+ center_lat = coordinates['lat']
79
+ center_lon = coordinates['lng']
80
+
81
+ if radius: # Se o raio for especificado
82
+ # Calculando distâncias e filtrando
83
+ filtered_df['Distance'] = filtered_df.apply(
84
+ lambda row: haversine(center_lat, center_lon, row['Latitude'], row['Longitude']),
85
+ axis=1
86
+ )
87
+ filtered_df = filtered_df[filtered_df['Distance'] <= radius]
88
+ else: # Se nenhum raio for especificado
89
+ # Filtrar pelo nome da rua ou bairro
90
+ address_components = result[0]['address_components']
91
+ street = None
92
+ neighborhood = None
93
+
94
+ for component in address_components:
95
+ if 'route' in component['types']: # Rua
96
+ street = component['long_name']
97
+ if 'sublocality' in component['types'] or 'locality' in component['types']: # Bairro
98
+ neighborhood = component['long_name']
99
+
100
+ if street:
101
+ filtered_df = filtered_df[filtered_df['Localização'].str.contains(street, na=False)]
102
+ elif neighborhood:
103
+ filtered_df = filtered_df[filtered_df['Bairro'].str.contains(neighborhood, na=False)]
104
+ except Exception as e:
105
+ print(f"Erro ao filtrar pelo endereço: {e}")
106
+
107
+
108
+ # Criando o mapa
109
+ fig = px.scatter_mapbox(
110
+ filtered_df,
111
+ lat="Latitude",
112
+ lon="Longitude",
113
+ hover_name="Localização",
114
+ hover_data={
115
+ "Valor": True,
116
+ "Vunit_priv": True,
117
+ "Tipo": True,
118
+ "url": True,
119
+ },
120
+ color="Tipo",
121
+ size="Valor",
122
+ size_max=30,
123
+ zoom=10
124
+ )
125
+
126
+ fig.update_layout(
127
+ mapbox_style="open-street-map",
128
+ autosize=True,
129
+ height=600,
130
+ margin={"r": 0, "t": 0, "l": 0, "b": 0},
131
+ )
132
+
133
+ # Adicionando círculo ao mapa se endereço e raio forem fornecidos
134
+ if address and radius:
135
+ try:
136
+ raio_terra = 6371000
137
+ pontos_lat = []
138
+ pontos_lon = []
139
+ for angulo in range(360):
140
+ ang_rad = radians(angulo)
141
+ d_lat = (radius / raio_terra) * cos(ang_rad)
142
+ d_lon = (radius / (raio_terra * cos(radians(center_lat)))) * sin(ang_rad)
143
+ pontos_lat.append(center_lat + d_lat * (180 / 3.141592653589793))
144
+ pontos_lon.append(center_lon + d_lon * (180 / 3.141592653589793))
145
+
146
+ fig.add_trace(go.Scattermapbox(
147
+ lat=pontos_lat,
148
+ lon=pontos_lon,
149
+ mode='lines',
150
+ fill='toself',
151
+ fillcolor='rgba(0, 0, 255, 0.2)',
152
+ line=dict(color='blue', width=2),
153
+ name='Raio'
154
+ ))
155
+
156
+ fig.add_trace(go.Scattermapbox(
157
+ lat=[center_lat],
158
+ lon=[center_lon],
159
+ mode='markers',
160
+ marker=dict(size=10, color='red'),
161
+ name='Centro'
162
+ ))
163
+ except Exception as e:
164
+ print(f"Erro ao adicionar o círculo no mapa: {e}")
165
+
166
+ # Gerando estatísticas
167
+ if filtered_df.empty:
168
+ stats_text = "Nenhum dado disponível."
169
+ else:
170
+ stats_text = (f"Quantidade de Dados: {len(filtered_df):n}\n"
171
+ f"Média do Valor: {locale.format_string('%.2f', filtered_df['Valor'].mean(), grouping=True)}\n"
172
+ f"Máximo do Valor: {locale.format_string('%.2f', filtered_df['Valor'].max(), grouping=True)}\n"
173
+ f"Mínimo do Valor: {locale.format_string('%.2f', filtered_df['Valor'].min(), grouping=True)}")
174
+
175
+ # Salvando DataFrame filtrado em arquivo CSV
176
+ file_path = "dados_filtrados.xlsx"
177
+ filtered_df.to_excel(file_path)
178
+
179
+ return fig, stats_text, filtered_df, file_path
180
+
181
+ # List of unique property types, bairros, and fonte, with "Todos" as default
182
+ property_types = ["Todos"] + sorted(df['Tipo'].dropna().unique().tolist())
183
+ bairro_list = ["Todos"] + sorted(df['Bairro'].dropna().unique().tolist())
184
+ fonte_list = ["Todos"] + sorted(df['Fonte'].dropna().unique().tolist())
185
+
186
+
187
+ def dados_tab():
188
+ with gr.Tab("Pesquisar Dados"):
189
+ toggle_filters = gr.Checkbox(label="Exibir Campos de Pesquisa", value=True)
190
+
191
+ with gr.Row(visible=True) as filters:
192
+ tipo_filter = gr.Dropdown(label="Selecione os Tipos de Imóvel", choices=property_types, value=["Todos"], multiselect=True)
193
+ bairro_filter = gr.Dropdown(label="Selecione os Bairros", choices=bairro_list, value=["Todos"], multiselect=True)
194
+ fonte_filter = gr.Dropdown(label="Selecione a Fonte", choices=fonte_list, value=["Todos"], multiselect=True)
195
+
196
+ with gr.Row(visible=True) as area_filters:
197
+ min_atotal = gr.Number(label="Área Total Mínima", value=None)
198
+ max_atotal = gr.Number(label="Área Total Máxima", value=None)
199
+ min_apriv = gr.Number(label="Área Privativa Mínima", value=None)
200
+ max_apriv = gr.Number(label="Área Privativa Máxima", value=None)
201
+ min_ater = gr.Number(label="Área Terreno Mínima", value=None)
202
+ max_ater = gr.Number(label="Área Terreno Máxima", value=None)
203
+
204
+ with gr.Row(visible=True) as date_filters:
205
+ min_date = gr.Textbox(label="Data Inicial (AAAA-MM-DD)", value="")
206
+ max_date = gr.Textbox(label="Data Final (AAAA-MM-DD)", value="")
207
+
208
+ with gr.Row(visible=True) as address_filters:
209
+ address_input = gr.Textbox(label="Endereço (Opcional)")
210
+ radius_input = gr.Number(label="Raio em metros (Opcional)")
211
+
212
+ with gr.Row():
213
+ search_button = gr.Button("Pesquisar")
214
+ clear_button = gr.Button("Limpar")
215
+
216
+ map_output = gr.Plot()
217
+ stats_output = gr.Textbox(lines=4, label="Estatísticas")
218
+ filtered_df_output = gr.DataFrame(label="Dados Filtrados")
219
+ download_output = gr.File(label="Baixar Dados Filtrados")
220
+
221
+ def clear_action():
222
+ return (["Todos"], ["Todos"], ["Todos"], None, None, None, None, None, None, "", "", "", None, None, "", pd.DataFrame(), None)
223
+
224
+ toggle_filters.change(
225
+ lambda show: (
226
+ gr.update(visible=show),
227
+ gr.update(visible=show),
228
+ gr.update(visible=show),
229
+ gr.update(visible=show) # Adiciona o filtro de data na visibilidade
230
+ ),
231
+ inputs=[toggle_filters],
232
+ outputs=[filters, area_filters, address_filters, date_filters]
233
+ )
234
+
235
+
236
+ search_button.click(
237
+ unified_action,
238
+ inputs=[tipo_filter, bairro_filter, fonte_filter, min_atotal, max_atotal, min_apriv, max_apriv,
239
+ min_ater, max_ater, min_date, max_date, address_input, radius_input],
240
+ outputs=[map_output, stats_output, filtered_df_output, download_output]
241
+ )
242
+
243
+ clear_button.click(
244
+ clear_action,
245
+ outputs=[tipo_filter, bairro_filter, fonte_filter, min_atotal, max_atotal, min_apriv, max_apriv,
246
+ min_ater, max_ater, min_date, max_date, address_input, radius_input,
247
+ map_output, stats_output, filtered_df_output, download_output]
248
+ )
249
+
250
+ return locals(), filtered_df_output
251
+
252
+
253
+ ### implementar o KNN
254
+ ### Arrumar a questão de que somente clicando no botão "Limpar" é possível acionar os filtros
255
+ ### Filtro por data
256
+ ### Zoon oelo filtro de raio
257
+ ### Gráfico de linhas
modules/evo.py ADDED
@@ -0,0 +1,436 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ from datetime import datetime
4
+ from docx import Document
5
+ from docx.shared import Pt
6
+ from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
7
+ from num2words import num2words
8
+ import warnings # Somente se voc� realmente quer suprimir avisos
9
+
10
+
11
+ # Suprimir todos os avisos durante a execução do script
12
+ warnings.filterwarnings("ignore")
13
+
14
+ # Calcular a data mais recente do CUB fora da função
15
+ df_cub = pd.read_excel('TABELAS_evo.xlsx', sheet_name='CUB')
16
+ ultimo_cub = df_cub.columns[-1]
17
+
18
+ #função para escrever por extenso o valor atribuído
19
+ def numero_por_extenso(numero):
20
+ reais = int(numero)
21
+
22
+ extenso_reais = num2words(reais, lang='pt_BR')
23
+
24
+ if reais == 1:
25
+ extenso_reais += ' real'
26
+ else:
27
+ extenso_reais += ' reais'
28
+
29
+ return extenso_reais
30
+
31
+ # Função para calcular o valor do imóvel
32
+ def calcular_valor_imovel(
33
+ area=100, data_refer_str=None, data_const_str=None, tipo_cub="R 1-N (Res. Unifamiliar)",
34
+ data_cub_str=None, percentual_cub=1, est_custo_dir="-", BDI=22.5, BDI_tipo ="Arbitrado", fator_local = 1,
35
+ just_fator_local = "-", tipologia="APARTAMENTOS",
36
+ estado="B - entre novo e regular", VR=0.0, deprec="Arbitrada",
37
+ valor_terreno=0,
38
+ est_ter="Grau III",
39
+ fc=1, fc_just="Arbitrado"):
40
+
41
+ # Carregar dados dos arquivos Excel
42
+ df_cub = pd.read_excel('TABELAS_evo.xlsx', sheet_name='CUB')
43
+ df_vida = pd.read_excel('TABELAS_evo.xlsx', sheet_name='VUTIL')
44
+ df_dep = pd.read_excel('TABELAS_evo.xlsx', sheet_name='DEP')
45
+ df_estado_cons = pd.read_excel('TABELAS_evo.xlsx', sheet_name='CONS')
46
+
47
+ # Converter datas de entrada
48
+ if data_refer_str is None or data_refer_str == "":
49
+ data_refer = datetime.now()
50
+ else:
51
+ data_refer = datetime.strptime(data_refer_str, "%m/%Y")
52
+ data_const = datetime.strptime(data_const_str, "%m/%Y")
53
+ if data_cub_str is None or data_cub_str == "":
54
+ data_cub = datetime.now()
55
+ else:
56
+ data_cub = datetime.strptime(data_cub_str, "%m/%Y")
57
+
58
+ # Filtrar por tipo_cub
59
+ df_tipo_cub = df_cub[df_cub['CÓDIGO'] == tipo_cub]
60
+
61
+ # Obter o valor do CUB na coluna correspondente à data
62
+ valor_cub_column = data_cub.strftime("%m/%Y")
63
+ valor_cub = df_tipo_cub.at[df_tipo_cub.index[0], valor_cub_column]
64
+
65
+ # Idade
66
+ idade = data_refer.toordinal() - data_const.toordinal()
67
+ if idade > 1:
68
+ idade = idade // 365
69
+ else:
70
+ idade = 1
71
+
72
+ # Filtrar por %de Vida
73
+ vdu = df_vida.loc[(df_vida['FINAL'] == tipologia)]
74
+
75
+ # % de vida útil
76
+ perc_vdu = (idade / vdu['VIDAUTIL']) * 100
77
+ perc_vdu = int(round(perc_vdu, 0))
78
+
79
+ if perc_vdu >= 100:
80
+ percentual_vdu = 100
81
+ elif perc_vdu < 2:
82
+ percentual_vdu = 2
83
+ else:
84
+ percentual_vdu = perc_vdu
85
+
86
+ # Filtrar conforme o % de vida útil
87
+ df_conserv = df_dep.loc[df_dep['%deVida'] == percentual_vdu]
88
+
89
+ # Converter o valor residual de string para número (float)
90
+ try:
91
+ VR = float(VR.strip()) if isinstance(VR, str) and VR.strip() != "" else 0.0
92
+ except ValueError:
93
+ VR = 0.0
94
+ # Obter da depreciação
95
+ coef_HH = float(df_conserv[estado]/100)
96
+ coef_HH = round(coef_HH, 3)
97
+
98
+ # Valor do "Kd"
99
+ kd = VR + (1 - coef_HH) * (1 - VR)
100
+ kd = round(kd, 3)
101
+
102
+ # Converter o valor do terreno de string para número (float)
103
+ #try:
104
+ #valor_terreno = float(valor_terreno.strip()) if isinstance(valor_terreno, str) and valor_terreno.strip() != "" else 0.0
105
+ #except ValueError:
106
+ #valor_terreno = 0.0
107
+
108
+ # Cálculos
109
+ Valor_sem_deprec = round(area * valor_cub * percentual_cub * (1 + BDI / 100) * fator_local, 2)
110
+ Valor_com_deprec = Valor_sem_deprec * kd
111
+ Valor_com_deprec = round(Valor_com_deprec, 2)
112
+ valor_imovel = round((valor_terreno + Valor_com_deprec) * float(fc), 0)
113
+
114
+
115
+ # Atributo da coluna "cons" pelo qual você deseja fazer a correspondência
116
+ atributo_desejado = estado
117
+ # Encontrar o valor da coluna "obs" com base no atributo da coluna "cons"
118
+ valor_obs = df_estado_cons.loc[df_estado_cons['cons'] == atributo_desejado, 'obs'].iloc[0]
119
+
120
+ # -------------------------------------- #
121
+
122
+ # GRAU DE FUNDAMENTAÇÃO CUSTOS
123
+
124
+ # item_1 - Graus de Fundamentação (Estimativa do custo direto)
125
+ if est_custo_dir == "Elaboração de orçamento, no mínimo sintético":
126
+ cust_1 = 3
127
+ elif est_custo_dir == "Utilização CUB para projeto semelhante ao projeto padrão":
128
+ cust_1 = 2
129
+ else:
130
+ cust_1 = 1
131
+
132
+ # item_2 - Graus de Fundamentação (BDI)
133
+ if BDI_tipo == "Calculado":
134
+ cust_2 = 3
135
+ elif BDI_tipo == "Justificado":
136
+ cust_2 = 2
137
+ else:
138
+ cust_2 = 1
139
+
140
+ # item_3 - Graus de Fundamentação (Depreciação física)
141
+ if deprec == "Por levantamento do custo de recuperação do bem, para deixá-lo no estado de novo ou caso de bens novos ou projetos hipotéticos":
142
+ cust_3 = 3
143
+ elif deprec == "Por métodos técnicos consagrados, considerando-se idade, vida útil e estado de conservação":
144
+ cust_3 = 2
145
+ else:
146
+ cust_3 = 1
147
+
148
+ # enquadramento
149
+ soma_custo = cust_1 + cust_2 + cust_3
150
+ if soma_custo >= 7 and cust_1 == 3 and cust_2 >= 2 and cust_3 >= 2:
151
+ est_cr = "Grau III"
152
+ elif soma_custo >= 5 and cust_1 >= 2 and cust_2 >= 2:
153
+ est_cr = "Grau II"
154
+ elif soma_custo >= 3 and cust_1 >= 1 and cust_2 >= 1 and cust_3 >= 1:
155
+ est_cr = "Grau I"
156
+ else:
157
+ est_cr = "Fora dos critérios"
158
+
159
+ # -------------------------------------- #
160
+
161
+ # GRAU DE FUNDAMENTAÇÃO EVOLUTIVO
162
+
163
+ # item_1 - Graus de Fundamentação (Estimativa do valor do terreno)
164
+ if est_ter == "Grau III":
165
+ evo_1 = 3
166
+ elif est_ter == "Grau II":
167
+ evo_1 = 2
168
+ else:
169
+ evo_1 = 1
170
+
171
+ # item_2 - Graus de Fundamentação (Estimativa dos custos de reedição)
172
+ if est_cr == "Grau III":
173
+ evo_2 = 3
174
+ elif est_cr == "Grau II":
175
+ evo_2 = 2
176
+ else:
177
+ evo_2 = 1
178
+
179
+ # item_3 - Graus de Fundamentação (Forma de cálculo do FC)
180
+ if fc_just == "Inferido em mercado semelhante":
181
+ evo_3 = 3
182
+ elif fc_just == "Justificado:":
183
+ evo_3 = 2
184
+ else:
185
+ evo_3 = 1
186
+
187
+ # enquadramento
188
+ soma_evo = evo_1 + evo_2 + evo_3
189
+ if soma_evo >= 8 and evo_1 == 3 and evo_2 == 3 and evo_3 >= 2: # confirmar!!!!!
190
+ fundamentacao_evolutivo = "Grau III"
191
+ elif soma_evo >= 5 and evo_1 >= 2 and evo_2 >= 2:
192
+ fundamentacao_evolutivo = "Grau II"
193
+ elif soma_evo >= 3 and evo_1 >= 1 and evo_2 >= 1 and evo_3 >= 1:
194
+ fundamentacao_evolutivo = "Grau I"
195
+ else:
196
+ fundamentacao_evolutivo = "Fora dos critérios"
197
+
198
+ # -------------------------------------- #
199
+
200
+ # criação de strings para os relatórios da interface e do word
201
+
202
+ #####
203
+ tipo_cub = tipo_cub.replace('.', '@').replace(',', '.').replace('@', ',')
204
+ est_custo_dir = est_custo_dir.replace('.', '@').replace(',', '.').replace('@', ',')
205
+ just_fator_local = just_fator_local.replace('.', '@').replace(',', '.').replace('@', ',')
206
+ valor_inicial = f"""
207
+ Área construída : {area:,.2f} m²
208
+ Data de referência: {data_refer.strftime("%m/%Y")}
209
+ Data da construção: {data_const_str}
210
+ Data do CUB: {data_cub.strftime("%m/%Y")}
211
+ Tipo de CUB: {tipo_cub}
212
+ Fator para adequação do CUB: {percentual_cub}
213
+ Estimativa do custo direto: {est_custo_dir}
214
+ BDI (%): {BDI}
215
+ Método de elaboração do BDI: {BDI_tipo}
216
+ Valor CUB: R$ {valor_cub:,.2f}
217
+ Fator local: {fator_local}
218
+ Fator local(justificativa): {just_fator_local}
219
+ Valor antes da depreciação = área construída * CUB * fator adequação CUB * (1 + BDI / 100) * fator local
220
+ Valor sem depreciação: R$ {Valor_sem_deprec:,.2f}
221
+ """
222
+
223
+ # Substituindo ponto por vírgula
224
+ valor_inicial = valor_inicial.replace('.', '@')
225
+ valor_inicial = valor_inicial.replace(',', '.')
226
+ valor_inicial = valor_inicial.replace('@', ',')
227
+
228
+ #####
229
+ valor_obs = valor_obs.replace('.', '@').replace(',', '.').replace('@', ',')
230
+ deprec = deprec.replace('.', '@').replace(',', '.').replace('@', ',')
231
+ deprec = f"""
232
+ Tipologia: {tipologia}
233
+ Vida útil da tipologia: {int(vdu['VIDAUTIL'])}
234
+ Estado de conservação: {estado}
235
+ Estado de conservação - descrição: {valor_obs}
236
+ % de Vida Útil: {percentual_vdu}
237
+ Coeficiente de Depreciação: {coef_HH}
238
+ Valor residual (0, 0.1 ou 0.2): {VR}
239
+ Forma de cálculo da depreciação física: {deprec}
240
+ Kd: {kd}
241
+ onde: Kd = (Valor residual + (1 - percentual de depreciação)*(1 - Valor residual))
242
+ Valor depois da depreciação = (Valor antes da depreciação) x Kd (com coeficiente de valor residual)
243
+ Valor final construção: R$ {Valor_com_deprec:,.2f}
244
+ Especificação da Avaliação (benfeitorias) - Método da Quantificação do Custo: {est_cr}
245
+ """
246
+ # Substituindo ponto por vírgula
247
+ deprec = deprec.replace('.', '@')
248
+ deprec = deprec.replace(',', '.')
249
+ deprec = deprec.replace('@', ',')
250
+
251
+ #####
252
+ valor_ter = f"""
253
+ Valor do Terreno: R$ {valor_terreno:,.2f}
254
+ Especificação da Avaliação (terreno ou gleba) - Método Comparativo ou Involutivo: {est_ter}
255
+ """
256
+ # Substituindo ponto por vírgula
257
+ valor_ter = valor_ter.replace('.', '@')
258
+ valor_ter = valor_ter.replace(',', '.')
259
+ valor_ter = valor_ter.replace('@', ',')
260
+
261
+ #####
262
+ valor_ext = numero_por_extenso(valor_imovel)
263
+
264
+ v_relat = f"{valor_imovel:,.2f}"
265
+ v_relat = v_relat.replace('.', '@')
266
+ v_relat = v_relat.replace(',', '.')
267
+ v_relat = v_relat.replace('@', ',')
268
+
269
+ valor_final = f"""
270
+ FC (Fator de Comercialização): {fc}
271
+ Observação sobre o FC: {fc_just}
272
+ ---------------------
273
+ VI = (VT + CA) * FC
274
+ Onde:
275
+ VI: Valor estimado do imóvel;
276
+ VT: Valor estimado do terreno;
277
+ CA: Custo de reedição das benfeitorias;
278
+ FC: Fator de comercialização.
279
+ ---------------------
280
+ Valor do Imóvel (c/ arredondamento): R$ {v_relat}
281
+ ({valor_ext})
282
+ ---------------------
283
+ Especificação da Avaliação - Método Evolutivo: {fundamentacao_evolutivo}
284
+ """
285
+
286
+ # -------------------------------------- #
287
+
288
+ # Criação de um relatório da avaliação no word
289
+ # Criar um novo documento do Word
290
+ doc = Document()
291
+
292
+ # Definir o título do documento
293
+ doc.add_heading('Relatório de Avaliação de Imóvel', level=1)
294
+
295
+ # Definir as seções do relatório
296
+ sections = [
297
+ (valor_inicial, "Valor Inicial da Construção"),
298
+ (deprec, "Cálculo da Depreciação"),
299
+ (valor_ter, "Valor Estimado para o Terreno"),
300
+ (valor_final, "Valor Final do Imóvel"),
301
+ ]
302
+
303
+ for content, title in sections:
304
+ doc.add_heading(title, level=2)
305
+ p = doc.add_paragraph()
306
+ run = p.add_run(content)
307
+ run.font.size = Pt(12)
308
+
309
+ if title == "": # Se for a seção de assinatura
310
+ p.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT # Define o alinhamento para à direita
311
+ else:
312
+ p.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT # Define o alinhamento para à esquerda
313
+
314
+ # Salvar o documento em um arquivo .doc
315
+ doc.save('relatorio_avaliacao.doc')
316
+
317
+ # -------------------------------------- #
318
+
319
+ # Outputs
320
+ return valor_inicial, deprec, valor_ter, valor_final, 'relatorio_avaliacao.doc'
321
+
322
+ # -------------------------------------- #
323
+
324
+ # Interface Gradio
325
+
326
+ def evo_tab():
327
+ with gr.Tab("Evolutivo"):
328
+ with gr.Row():
329
+ with gr.Column():
330
+ # Valor Inicial da Construção
331
+ with gr.Row():
332
+ area = gr.Number(label="Área (m²)", value=100, info="Área construída", scale=0.5) # Remova a vírgula aqui
333
+ data_r = gr.Textbox(label="Data referência (mm/aaaa)", value=ultimo_cub, info="Data do fato gerador da demanda", scale=1) # Remova a vírgula aqui
334
+ data_c = gr.Textbox(label="Data construção (mm/aaaa)", value=ultimo_cub, info="Data de construção do imóvel", scale=1)
335
+ with gr.Group():
336
+ with gr.Row():
337
+ cub = gr.Dropdown(label="Tipo de CUB",
338
+ choices=["R 1-B (Res. Unifamiliar)", "R 1-N (Res. Unifamiliar)", "R 1-A (Res. Unifamiliar)",
339
+ "PP 4-B (Prédio Popular)", "PP 4-N (Prédio Popular)", "R 8-B (Res. Multifamiliar)",
340
+ "R 8-N (Res. Multifamiliar)", "R 8-A (Res. Multifamiliar)", "R 16-N (Res. Multifamiliar)",
341
+ "R 16-A (Res. Multifamiliar)", "PIS (Projeto Inter. Social)", "RP1Q (Residência Popular)",
342
+ "CAL 8-N (Com. Andar Livres)", "CAL 8-A (Com. Andar Livres)",
343
+ "CSL 8-N (Com.Salas e Lojas)", "CSL 8-A (Com.Salas e Lojas)",
344
+ "CSL 16-N (Com.Salas e Lojas)", "CSL 16-A (Com.Salas e Lojas)", "GI (Galpão Industrial)"],
345
+ value="R 1-N (Res. Unifamiliar)", scale=1)
346
+ data_cub = gr.Textbox(label="Data do CUB (mm/aaaa)", value=ultimo_cub, scale=1)
347
+ fator_cub = gr.Slider(0.5, 2.0, value=1, label="Fator para adequação do CUB",
348
+ info="Para contemplar insumos/serviços que não constam na composição", step=0.1)
349
+ forma_cub = gr.Dropdown(["Utilização CUB para projeto semelhante ao projeto padrão",
350
+ "Utilização CUB para projeto diferente do projeto padrão, com os devidos ajustes"],
351
+ label="Estimativa do custo direto", value="Utilização CUB para projeto semelhante ao projeto padrão")
352
+ with gr.Row():
353
+ bdi = gr.Number(label="BDI (%)", value=22.5, scale=0.5)
354
+ tipo_bdi = gr.Dropdown(["Calculado", "Justificado", "Arbitrado"], label="Tipo de BDI", value="Justificado", scale=1)
355
+ with gr.Row():
356
+ fator_local = gr.Slider(0.5, 1.5, value=1, label="Fator local", info="Atribua um coeficiente de valorização se necessário", step=0.1)
357
+ just_local = gr.Textbox(label="Justificativa para o Fator Local", value="-", info="Justifique tecnicamente o fator")
358
+
359
+ # Cálculo da Depreciação
360
+ with gr.Group():
361
+ with gr.Row():
362
+ tipo = gr.Dropdown(label="Tipologia", choices=["APARTAMENTOS", "BANCOS", "CASAS DE ALVENARIA",
363
+ "CASAS DE MADEIRA", "HOTÉIS", "LOJAS", "TEATROS",
364
+ "ARMAZÉNS", "FÁBRICAS", "CONST. RURAIS", "GARAGENS",
365
+ "EDIFÍCIOS DE ESCRITÓRIOS", "GALPÕES (DEPÓSITOS)", "SILOS"], value="CASAS DE ALVENARIA", scale=1)
366
+ rst_con = gr.Dropdown(label="Estado de conservação", choices=["A - novo", "B - entre novo e regular",
367
+ "C - regular", "D - entre regular e reparos simples",
368
+ "E - reparos simples", "F - entre reparos simples e importantes",
369
+ "G - reparos importantes", "H - entre reparos importantes e sem valor"], value="A - novo", scale=1)
370
+ vr = gr.Dropdown(label="Valor residual", choices=["0", "0.1", "0.2"], value="0", scale=0.5)
371
+ deprec = gr.Dropdown(["Por levantamento do custo de recuperação do bem, para deixá-lo no estado de novo ou caso de bens novos ou projetos hipotéticos",
372
+ "Por métodos técnicos consagrados, considerando-se idade, vida útil e estado de conservação",
373
+ "Arbitrado"],
374
+ label="Depreciação Física",
375
+ info="Forma pela qual a depreciação física foi calculada",
376
+ value="Por métodos técnicos consagrados, considerando-se idade, vida útil e estado de conservação")
377
+ #-------------------------------------------------------#
378
+ button_1 = gr.Button("Calcular Construção")
379
+ #-------------------------------------------------------#
380
+
381
+ # Valor do Terreno
382
+ with gr.Row():
383
+ vt_inp = gr.Number(label="Valor do Terreno", info="Campo não precisade de preenchimento p/ o cálculo do Custo de Reprodução", value=0)
384
+ grau_t = gr.Radio(["Grau III", "Grau II", "Grau I"], info="Escolha o Grau de Fundamentação alcançado pela avaliação do terreno", label="", value="Grau III")
385
+
386
+ # Valor final do imóvel
387
+ fc = gr.Slider(0.1, 2.0, value=1.0, label="FC (Fator de Comercialização)", info="O Fator de Comercialização, também chamado de Terceiro Componente ou Vantagem da Coisa Feita, é definido no item 3.20 da NBR 14653-1:2001: “Fator de comercialização: Razão entre o valor de mercado de um bem e o seu custo de reedição ou de substituição, que pode ser maior ou menor que 1", step=0.1)
388
+ forma_fc = gr.Radio(["Inferido em mercado semelhante", "Justificado", "Arbitrado"], label="", info="Estipule como foi elaborado o FC", value="Justificado")
389
+
390
+ #-------------------------------------------------------#
391
+ button_2 = gr.Button("Calcular Terreno + Construção")
392
+ #-------------------------------------------------------#
393
+
394
+ with gr.Column():
395
+ vi = gr.Textbox(label="Valor Inicial da Contrução")
396
+ cd = gr.Textbox(label="Cálculo da Depreciação")
397
+ vt_out = gr.Textbox(label="Valor estimado para o terreno")
398
+ vf = gr.Textbox(label="Valor final do imóvel")
399
+ la = gr.File(label="Laudo de Avaliação")
400
+
401
+ inputs = [
402
+ area, # Área construída (m²)
403
+ data_r, # Data de referência (mm/aaaa)
404
+ data_c, # Data da construção (mm/aaaa)
405
+ cub, # Tipo de CUB
406
+ data_cub, # Data do CUB (mm/aaaa)
407
+ fator_cub, # Fator para adequação do CUB
408
+ forma_cub, # Estimativa do custo direto
409
+ bdi, # BDI (%)
410
+ tipo_bdi, # Tipo de BDI
411
+ fator_local, # Fator local
412
+ just_local, # Justificativa para o Fator Local
413
+ tipo, # Tipologia
414
+ rst_con, # Estado de conservação
415
+ vr, # Valor residual (0, 0.1 ou 0.2)
416
+ deprec, # Depreciação Física
417
+ vt_inp, # Valor do Terreno
418
+ grau_t, # Grau de Fundamentação alcançado pela avaliação do terreno
419
+ fc, # FC (Fator de Comercialização)
420
+ forma_fc # Forma como foi elaborado o FC
421
+ ]
422
+
423
+ outputs = [
424
+ vi, # Valor Inicial da Construção
425
+ cd, # Cálculo da Depreciação
426
+ vt_out, # Valor estimado para o terreno
427
+ vf, # Valor final do imóvel
428
+ la # Laudo de Avaliação (arquivo)
429
+ ]
430
+
431
+ button_1.click(calcular_valor_imovel, inputs=inputs, outputs=outputs)
432
+ button_2.click(calcular_valor_imovel, inputs=inputs, outputs=outputs)
433
+
434
+ return locals()
435
+
436
+ # Substituir a tabela pelo c�lculo da deprecia��o
modules/ml.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import matplotlib.pyplot as plt
3
+ from sklearn.linear_model import LinearRegression, Ridge, BayesianRidge
4
+ from sklearn.tree import DecisionTreeRegressor
5
+ from sklearn.ensemble import RandomForestRegressor
6
+ from sklearn.svm import SVR
7
+ from sklearn.neural_network import MLPRegressor
8
+ from sklearn.neighbors import KNeighborsRegressor
9
+ from sklearn.metrics import r2_score
10
+ from sklearn.model_selection import train_test_split
11
+ from sklearn.preprocessing import MinMaxScaler
12
+ from .shared_state import state # Estado compartilhado
13
+ import io
14
+ from PIL import Image
15
+
16
+ # Global model state to save the trained model
17
+ global_model = {"model": None, "scaler": None, "columns": None}
18
+
19
+ # Train the model
20
+ def apply_ml(df, var_dep, ml_model_name, test_size):
21
+ if df is None:
22
+ df = state.get('new_df') # Busca o DataFrame no estado compartilhado
23
+ if df is None:
24
+ raise ValueError("Nenhum DataFrame disponível para aplicação.")
25
+ df = df.dropna()
26
+ y = df[var_dep]
27
+ X = df.drop(columns=[var_dep])
28
+
29
+ # Remover a coluna "Índice" se ela existir
30
+ if "Índice" in X.columns:
31
+ X = X.drop(columns=["Índice"])
32
+
33
+ # Normalizar os dados com MinMaxScaler
34
+ scaler = MinMaxScaler()
35
+ X = scaler.fit_transform(X)
36
+
37
+ # Divisão em treino e teste com test_size ajustável
38
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=1)
39
+
40
+ # Escolha do modelo
41
+ if ml_model_name == "Linear Regression":
42
+ model = LinearRegression()
43
+ elif ml_model_name == "Ridge Regression":
44
+ model = Ridge(alpha=0.5)
45
+ elif ml_model_name == "Bayesian Ridge":
46
+ model = BayesianRidge()
47
+ elif ml_model_name == "Decision Tree":
48
+ model = DecisionTreeRegressor()
49
+ elif ml_model_name == "Random Forest":
50
+ model = RandomForestRegressor()
51
+ elif ml_model_name == "Support Vector Regression (SVR)":
52
+ model = SVR()
53
+ elif ml_model_name == "Neural Network (MLP)":
54
+ model = MLPRegressor(max_iter=5000, tol=0.1, random_state=1)
55
+ elif ml_model_name == "K-Neighbors Regressor":
56
+ model = KNeighborsRegressor(n_neighbors=5)
57
+ else:
58
+ raise ValueError("Modelo de ML inválido.")
59
+
60
+ # Treinamento e avaliação
61
+ model.fit(X_train, y_train)
62
+ train_r2 = r2_score(y_train, model.predict(X_train))
63
+ test_r2 = r2_score(y_test, model.predict(X_test))
64
+
65
+ print(f"Train R²: {train_r2}, Test R²: {test_r2}")
66
+
67
+ # Save the trained model, scaler, and column names for prediction
68
+ global_model["model"] = model
69
+ global_model["scaler"] = scaler
70
+ global_model["columns"] = df.drop(columns=[var_dep]).columns.tolist()
71
+
72
+ # Gerar o gráfico
73
+ plt.figure(figsize=(6, 4))
74
+ plt.bar(["Treino", "Teste"], [train_r2, test_r2], color=["blue", "orange"])
75
+ plt.title(f"Desempenho do Modelo: {ml_model_name} - Test Size: {test_size}")
76
+ plt.ylabel("R²")
77
+ plt.ylim(0, 1) # Limite entre 0 e 1 para facilitar a visualização
78
+ plt.tight_layout()
79
+
80
+ # Salvar o gráfico em um buffer
81
+ buffer = io.BytesIO()
82
+ plt.savefig(buffer, format='png')
83
+ buffer.seek(0)
84
+ plt.close()
85
+
86
+ # Convert the buffer to a PIL Image
87
+ image = Image.open(buffer)
88
+
89
+ return image
90
+
91
+ # Função para atualizar as opções de variáveis dependentes
92
+ def update_var_dep_dropdown(df):
93
+ if df is None:
94
+ df = state.get('new_df') # Busca o DataFrame no estado compartilhado
95
+ if df is None:
96
+ return gr.update(choices=[])
97
+ return gr.update(choices=df.columns.tolist())
98
+
99
+ def predict_new_values(*inputs):
100
+ if global_model["model"] is None:
101
+ return "O modelo ainda não foi treinado. Execute o modelo primeiro."
102
+
103
+ # Reshape input to match model expectation
104
+ new_data = [float(value) for value in inputs]
105
+ new_data_scaled = global_model["scaler"].transform([new_data])
106
+
107
+ # Predict
108
+ prediction = global_model["model"].predict(new_data_scaled)[0]
109
+ return f"Previsão: {prediction:.4f}"
110
+
111
+ # Função para criar a aba Machine Learning
112
+ def ml_tab(new_df_output):
113
+ with gr.Tab("Machine Learning"):
114
+ var_dep_dropdown = gr.Dropdown(choices=[], label="Variável Dependente")
115
+ ml_model_dropdown = gr.Dropdown(
116
+ choices=[
117
+ "Linear Regression", "Ridge Regression", "Bayesian Ridge",
118
+ "Decision Tree", "Random Forest", "Support Vector Regression (SVR)",
119
+ "Neural Network (MLP)", "K-Neighbors Regressor"
120
+ ],
121
+ label="Modelo de Machine Learning"
122
+ )
123
+ test_size_slider = gr.Slider(minimum=0.1, maximum=0.5, step=0.05, value=0.3, label="Tamanho do Teste")
124
+ submit_button = gr.Button("Executar Modelo")
125
+ r2_graph_output = gr.Image(label="Gráfico de Desempenho")
126
+
127
+ # Callback to execute the function
128
+ submit_button.click(
129
+ apply_ml,
130
+ inputs=[new_df_output, var_dep_dropdown, ml_model_dropdown, test_size_slider],
131
+ outputs=[r2_graph_output]
132
+ )
133
+
134
+ # Update dropdown options
135
+ new_df_output.change(update_var_dep_dropdown, inputs=[new_df_output], outputs=[var_dep_dropdown])
136
+
137
+ # Add prediction section
138
+ gr.Markdown("### Previsão de Novos Valores")
139
+
140
+ inputs = []
141
+ if global_model["columns"]: # Check if columns exist
142
+ for col in global_model["columns"]:
143
+ inputs.append(gr.Textbox(label=f"Valor para '{col}'"))
144
+ else:
145
+ gr.Markdown("O modelo ainda não foi treinado. Execute o modelo primeiro para realizar previsões.")
146
+
147
+ predict_button = gr.Button("Prever Valores")
148
+ prediction_output = gr.Textbox(label="Resultado da Previsão")
149
+
150
+ # Predict only if inputs were generated
151
+ if inputs:
152
+ predict_button.click(predict_new_values, inputs=inputs, outputs=prediction_output)
153
+
154
+ return locals()
modules/otimiza.py ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ from sklearn.linear_model import LinearRegression
4
+ from sklearn.metrics import r2_score
5
+ from itertools import product
6
+ from .shared_state import state # Importa o estado compartilhado
7
+
8
+ # OTIMIZA
9
+ def apply_transformation(data, transformation):
10
+ if transformation == "exp" and (data > 50).any():
11
+ return data
12
+ if transformation == "direct":
13
+ return data
14
+ elif transformation == "inverse":
15
+ return 1 / (data + 0.001)
16
+ elif transformation == "log":
17
+ return np.log(data + 0.001)
18
+ elif transformation == "exp":
19
+ return np.exp(data)
20
+ elif transformation == "square":
21
+ return data ** 2
22
+
23
+ def find_best_transformations(df, var_dep, ignore_dichotomous):
24
+ if df is None:
25
+ df = state.get('new_df') # Busca o DataFrame no estado compartilhado
26
+ if df is None:
27
+ raise ValueError("Nenhum DataFrame disponível para otimização.")
28
+ df = df.dropna()
29
+ y = df[var_dep]
30
+ X = df.drop(columns=[var_dep])
31
+
32
+ # Remover a coluna "Índice" se ela existir
33
+ if "Índice" in X.columns:
34
+ X = X.drop(columns=["Índice"])
35
+
36
+ dichotomous_columns = [col for col in X.columns if set(X[col].unique()).issubset({0, 1})]
37
+ if ignore_dichotomous:
38
+ X = X.drop(columns=dichotomous_columns)
39
+ transformations = ["direct", "inverse", "log", "exp", "square"]
40
+ scores = []
41
+ for y_transformation in transformations:
42
+ y_transformed = apply_transformation(y, y_transformation)
43
+ for transformation_combo in product(transformations, repeat=X.shape[1]):
44
+ X_transformed = X.copy()
45
+ for i, transformation in enumerate(transformation_combo):
46
+ column = X.iloc[:, i]
47
+ X_transformed.iloc[:, i] = apply_transformation(column, transformation)
48
+ model = LinearRegression()
49
+ try:
50
+ model.fit(X_transformed, y_transformed)
51
+ predictions = model.predict(X_transformed)
52
+ score = r2_score(y_transformed, predictions)
53
+ scores.append((transformation_combo, y_transformation, score, model))
54
+ except ValueError as e:
55
+ if "Input X contains NaN" in str(e):
56
+ raise ValueError("O conjunto de dados apresenta valores nulos.") from e
57
+ else:
58
+ raise e # Propague outras exceções
59
+
60
+ scores = sorted(scores, key=lambda x: x[2], reverse=True)[:5]
61
+ top_equations = []
62
+ top_transformation_info = []
63
+ top_scores = []
64
+ for combo, y_trans, score, model in scores:
65
+ equation = f"y = {model.intercept_:.4f} " + " ".join(
66
+ [f"{'+' if coef >= 0 else '-'} ({abs(coef):.4f}) * {trans}" for coef, trans in zip(model.coef_, X.columns)]
67
+ )
68
+ transformation_info = {"y": y_trans}
69
+ transformation_info.update(dict(zip(X.columns, combo)))
70
+ top_equations.append([equation])
71
+ top_transformation_info.append(transformation_info)
72
+ top_scores.append([float(score)])
73
+ return top_equations, top_transformation_info, top_scores
74
+
75
+ def update_var_dep_dropdown(df):
76
+ if df is None:
77
+ df = state.get('new_df') # Busca o DataFrame no estado compartilhado
78
+ if df is None:
79
+ return gr.update(choices=[])
80
+ return gr.update(choices=df.columns.tolist())
81
+
82
+ def otimiza_tab(new_df_output):
83
+ with gr.Tab("Otimizar Modelo"):
84
+ var_dep_dropdown = gr.Dropdown(
85
+ choices=[], # Inicialmente vazio
86
+ label="Variável Dependente"
87
+ )
88
+ ignore_dichotomous_checkbox = gr.Checkbox(
89
+ label="Ignorar Variáveis Dicotômicas", value=False
90
+ )
91
+ submit_button = gr.Button("Otimizar variáveis")
92
+
93
+ with gr.Row():
94
+ equations_output = gr.Dataframe(headers=["Equação"], label="Equações (Top 5)")
95
+ with gr.Row():
96
+ transformations_output = gr.JSON(label="Transformações Aplicadas (Top 5)")
97
+ with gr.Row():
98
+ scores_output = gr.Dataframe(headers=["R2_Score"], label="R2_Scores (Top 5)")
99
+
100
+ # Callback para executar a função
101
+ submit_button.click(
102
+ find_best_transformations,
103
+ inputs=[new_df_output, var_dep_dropdown, ignore_dichotomous_checkbox],
104
+ outputs=[equations_output, transformations_output, scores_output]
105
+ )
106
+
107
+ # Atualiza o dropdown de variáveis dependentes quando o DataFrame é atualizado
108
+ new_df_output.change(
109
+ update_var_dep_dropdown,
110
+ inputs=[new_df_output],
111
+ outputs=[var_dep_dropdown]
112
+ )
113
+
114
+ return locals()
115
+
116
+
117
+ ### Fixar variáveis para efeutar a otimização
118
+ ### Trocar o y pelo nome da variável dependente
119
+ ### Exibir resultados estatísticos simples (como o SISREG)
120
+ ### Exportar para o ML e RL
modules/planilha.py ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ from modules.utils import create_new_dataframe_with_index_and_value_unit # Importe a função necessária
4
+ from .shared_state import state # Importa o estado compartilhado
5
+
6
+ # Variável global para armazenar o DataFrame original
7
+ original_df = None
8
+
9
+ # PLANILHA
10
+ def list_sheets(file):
11
+ if file is None:
12
+ return "Nenhum arquivo carregado.", []
13
+ excel_file = pd.ExcelFile(file.name)
14
+ sheet_names = excel_file.sheet_names
15
+ return "\n".join(sheet_names), sheet_names
16
+
17
+ def load_sheet(file, sheet_name):
18
+ if file is None or not sheet_name:
19
+ return pd.DataFrame({"Erro": ["Carregue um arquivo e selecione uma aba."]}), "", []
20
+ df = pd.read_excel(file.name, sheet_name=sheet_name)
21
+ rows, cols = df.shape
22
+ column_list = df.columns.tolist()
23
+ return df, f"{rows} linhas e {cols} colunas", column_list
24
+
25
+ def update_column_selector(file, sheet_name):
26
+ if file is None or not sheet_name:
27
+ return gr.update(choices=[], value=[])
28
+ df = pd.read_excel(file.name, sheet_name=sheet_name)
29
+ columns = df.columns.tolist()
30
+ return gr.update(choices=columns, value=columns)
31
+
32
+ def select_all_columns(select_all, choices):
33
+ if select_all:
34
+ return gr.update(value=choices)
35
+ else:
36
+ return gr.update(value=[])
37
+
38
+ def toggle_sheet_visibility(view_sheet):
39
+ return gr.update(visible=view_sheet)
40
+
41
+ def toggle_operations_inputs(enable_operations):
42
+ return gr.update(visible=enable_operations)
43
+
44
+ def add_new_variable(file, sheet_name, first_var, operation, second_var, new_var_name):
45
+ if file is None or not sheet_name or not first_var or not second_var or not new_var_name:
46
+ return pd.DataFrame({"Erro": ["Preencha todos os campos necessários."]})
47
+ df = pd.read_excel(file.name, sheet_name=sheet_name)
48
+ if first_var not in df.columns or second_var not in df.columns:
49
+ return pd.DataFrame({"Erro": ["Variáveis selecionadas não existem no DataFrame."]})
50
+
51
+ try:
52
+ if operation == "Adição":
53
+ df[new_var_name] = df[first_var] + df[second_var]
54
+ elif operation == "Subtração":
55
+ df[new_var_name] = df[first_var] - df[second_var]
56
+ elif operation == "Multiplicação":
57
+ df[new_var_name] = df[first_var] * df[second_var]
58
+ elif operation == "Divisão":
59
+ df[new_var_name] = df[first_var] / df[second_var]
60
+ except ZeroDivisionError:
61
+ return pd.DataFrame({"Erro": ["Divisão por zero detectada."]})
62
+ except Exception as e:
63
+ return pd.DataFrame({"Erro": [f"Erro ao realizar a operação: {str(e)}"]})
64
+
65
+ return df
66
+
67
+ def update_variable_choices(file, sheet_name):
68
+ if file is None or not sheet_name:
69
+ return gr.update(choices=[]), gr.update(choices=[])
70
+ df = pd.read_excel(file.name, sheet_name=sheet_name)
71
+ return gr.update(choices=df.columns.tolist()), gr.update(choices=df.columns.tolist())
72
+
73
+ def update_dropdown(file):
74
+ sheet_names_text, sheet_names = list_sheets(file)
75
+ return sheet_names_text, gr.update(choices=sheet_names)
76
+
77
+ def update_columns(file, sheet_name):
78
+ df, info, columns = load_sheet(file, sheet_name)
79
+ return (
80
+ df,
81
+ info,
82
+ columns,
83
+ gr.update(choices=columns, value=[], interactive=True)
84
+ )
85
+
86
+ # Função para restaurar o DataFrame ao estado inicial
87
+ def restore_dataframe():
88
+ global original_df
89
+ if original_df is not None:
90
+ return original_df, None # Retorna o DataFrame e um valor nulo para limpar o download
91
+ return pd.DataFrame(), None # Retorna DataFrame vazio e nenhum arquivo
92
+
93
+ def finalize_dataframe(file, sheet_name, selected_columns, first_var, operation, second_var, new_var_name, add_index):
94
+ if file is None or not sheet_name:
95
+ return pd.DataFrame({"Erro": ["Carregue um arquivo e selecione uma aba."]})
96
+ df = pd.read_excel(file.name, sheet_name=sheet_name)
97
+
98
+ # Adiciona a nova variável, se necessário
99
+ if new_var_name and first_var and second_var:
100
+ try:
101
+ if operation == "Adição":
102
+ df[new_var_name] = df[first_var] + df[second_var]
103
+ elif operation == "Subtração":
104
+ df[new_var_name] = df[first_var] - df[second_var]
105
+ elif operation == "Multiplicação":
106
+ df[new_var_name] = df[first_var] * df[second_var]
107
+ elif operation == "Divisão":
108
+ df[new_var_name] = df[first_var] / df[second_var]
109
+ except ZeroDivisionError:
110
+ return pd.DataFrame({"Erro": ["Divisão por zero detectada."]})
111
+ except Exception as e:
112
+ return pd.DataFrame({"Erro": [f"Erro ao realizar a operação: {str(e)}"]})
113
+
114
+ # Adiciona a nova variável às colunas selecionadas, se existir
115
+ if new_var_name and new_var_name in df.columns:
116
+ selected_columns.append(new_var_name)
117
+
118
+ if selected_columns:
119
+ df = df[selected_columns]
120
+
121
+ # Adiciona índice na primeira coluna, se necessário
122
+ if add_index:
123
+ df.insert(0, 'Índice', range(1, len(df) + 1))
124
+
125
+ # Salvando DataFrame filtrado em arquivo CSV
126
+ file_path = "Planilha_final.xlsx"
127
+ df.to_excel(file_path)
128
+
129
+ return df, file_path
130
+
131
+ def planilha_tab(filtered_df_output):
132
+ # Criação da aba
133
+ with gr.Tab("Carregar Planilha"):
134
+ # Checkbox para escolher entre usar o arquivo da aba anterior ou carregar um novo arquivo
135
+ use_filtered_df = gr.Checkbox(label="Usar arquivo da aba anterior", value=True)
136
+
137
+ # Upload do arquivo Excel
138
+ with gr.Row():
139
+ excel_file = gr.File(label="Carregue sua planilha Excel", file_types=[".xls", ".xlsx"], elem_classes=["small-file-upload"], visible=False)
140
+
141
+ with gr.Row():
142
+ list_button = gr.Button("Listar Abas")
143
+
144
+ # Exibição das abas disponíveis e seleção de aba
145
+ with gr.Row():
146
+ sheet_output = gr.Textbox(label="Abas disponíveis", interactive=False)
147
+ sheet_dropdown = gr.Dropdown(label="Selecione uma aba")
148
+
149
+ # Botão para carregar aba e exibir colunas
150
+ with gr.Row():
151
+ load_button = gr.Button("Carregar Aba")
152
+
153
+ # Informações e exibição de colunas da aba carregada
154
+ with gr.Row():
155
+ sheet_info = gr.Text(label="Informação de Linhas e Colunas")
156
+ sheet_columns = gr.JSON(label="Lista de Colunas", visible=False)
157
+ view_sheet_checkbox = gr.Checkbox(label="Visualizar a planilha", value=False)
158
+
159
+ # Exibição do conteúdo da aba selecionada
160
+ with gr.Row():
161
+ sheet_content = gr.Dataframe(
162
+ label="Conteúdo da Aba Selecionada",
163
+ visible=False
164
+ )
165
+
166
+ # CheckboxGroup para seleção de colunas
167
+ with gr.Row():
168
+ column_selector = gr.CheckboxGroup(
169
+ label="Selecione colunas para análise",
170
+ choices=[], # Inicia vazio
171
+ interactive=True
172
+ )
173
+
174
+ # Checkbox para adicionar índice na primeira coluna
175
+ with gr.Row():
176
+ add_index_checkbox = gr.Checkbox(label="Adicionar índice na primeira coluna", value=False)
177
+
178
+ # Checkbox para habilitar operações com variáveis
179
+ operations_checkbox = gr.Checkbox(label="Operações com variáveis", value=False)
180
+
181
+ # Elementos relacionados às operações, inicialmente invisíveis
182
+ with gr.Row(visible=False) as operations_inputs:
183
+ variable_name_textbox = gr.Textbox(
184
+ label="Nome da nova variável",
185
+ placeholder="Digite o nome da nova variável",
186
+ interactive=True
187
+ )
188
+ first_variable_dropdown = gr.Dropdown(
189
+ label="Selecione a primeira variável",
190
+ choices=[],
191
+ interactive=True
192
+ )
193
+ operation_dropdown = gr.Dropdown(
194
+ label="Selecione a operação",
195
+ choices=["Adição", "Subtração", "Multiplicação", "Divisão"],
196
+ interactive=True
197
+ )
198
+ second_variable_dropdown = gr.Dropdown(
199
+ label="Selecione a segunda variável",
200
+ choices=[],
201
+ interactive=True
202
+ )
203
+
204
+ # Associações de eventos
205
+ use_filtered_df.change(lambda x: gr.update(visible=not x), inputs=[use_filtered_df], outputs=[excel_file])
206
+ list_button.click(update_dropdown, inputs=[excel_file], outputs=[sheet_output, sheet_dropdown])
207
+ load_button.click(update_columns, inputs=[excel_file, sheet_dropdown], outputs=[sheet_content, sheet_info, sheet_columns])
208
+ load_button.click(update_column_selector, inputs=[excel_file, sheet_dropdown], outputs=[column_selector])
209
+ view_sheet_checkbox.change(toggle_sheet_visibility, inputs=[view_sheet_checkbox], outputs=[sheet_content])
210
+ operations_checkbox.change(toggle_operations_inputs, inputs=[operations_checkbox], outputs=[operations_inputs])
211
+
212
+ apply_operations_button = gr.Button("Criar Nova Variável")
213
+ new_df_output = gr.Dataframe(label="Novo DataFrame", interactive=True)
214
+ apply_operations_button.click(add_new_variable, inputs=[excel_file, sheet_dropdown, first_variable_dropdown, operation_dropdown, second_variable_dropdown, variable_name_textbox], outputs=[new_df_output])
215
+ load_button.click(update_variable_choices, inputs=[excel_file, sheet_dropdown], outputs=[first_variable_dropdown, second_variable_dropdown])
216
+
217
+ # Botão para finalizar o DataFrame
218
+ finalize_button = gr.Button("Finalizar DataFrame")
219
+ download_output = gr.File(label="Baixar Novo Dataframe")
220
+ finalize_button.click(finalize_dataframe, inputs=[excel_file, sheet_dropdown, column_selector, first_variable_dropdown, operation_dropdown, second_variable_dropdown, variable_name_textbox, add_index_checkbox], outputs=[new_df_output, download_output])
221
+
222
+ # Adicionar botões "Restaurar" e "Limpar"
223
+ with gr.Row():
224
+ restore_button = gr.Button("Restaurar")
225
+ clear_button = gr.ClearButton(components=[excel_file, sheet_output, sheet_dropdown, sheet_info, sheet_columns, view_sheet_checkbox, sheet_content, column_selector, add_index_checkbox, operations_checkbox, variable_name_textbox, first_variable_dropdown, operation_dropdown, second_variable_dropdown, new_df_output, download_output],
226
+ value="Limpar")
227
+
228
+ # Associações de eventos para os botões "Restaurar"
229
+ restore_button.click(restore_dataframe, outputs=[new_df_output, download_output])
230
+
231
+ # Se a opção "Usar arquivo da aba anterior" estiver marcada, carregue o filtered_df_output
232
+ def load_filtered_df(use_filtered_df, filtered_df_output):
233
+ if use_filtered_df:
234
+ df = pd.DataFrame(filtered_df_output)
235
+ return df, f"{df.shape[0]} linhas e {df.shape[1]} colunas", df.columns.tolist(), df.columns.tolist()
236
+ return None, "", [], []
237
+
238
+ use_filtered_df.change(load_filtered_df, inputs=[use_filtered_df, filtered_df_output], outputs=[sheet_content, sheet_info, column_selector, column_selector])
239
+
240
+ return locals(), new_df_output
241
+
242
+
243
+
244
+
245
+
246
+ ### Manipulação de colunas
247
+ ### Receber planilha da aba dados
modules/rl.py ADDED
@@ -0,0 +1,1477 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import numpy as np
4
+ import statsmodels.api as sm
5
+ import matplotlib.pyplot as plt
6
+ import seaborn as sns
7
+ import plotly.graph_objects as go
8
+ import plotly.express as px
9
+ import scipy.stats as stats
10
+ from joblib import dump
11
+ import joblib
12
+ import os
13
+ import locale
14
+
15
+ # Configurar o locale para o Brasil
16
+ locale.setlocale(locale.LC_ALL, 'pt_BR.UTF-8')
17
+
18
+ # Função para carregar a planilha de dados
19
+ def carregar_planilha(file):
20
+ try:
21
+ # Carregar o arquivo Excel sem forçar o tipo inicialmente
22
+ df = pd.read_excel(file.name)
23
+
24
+ # Garantir que todas as colunas sejam convertidas para float, ignorando erros
25
+ for col in df.columns:
26
+ df[col] = pd.to_numeric(df[col], errors='coerce') # Converte para número, valores inválidos viram NaN
27
+
28
+ # Substituir NaN por zero ou outro valor padrão, se necessário
29
+ df.fillna(0, inplace=True)
30
+
31
+ # Garantir que os cabeçalhos sejam strings
32
+ df.columns = [str(col) for col in df.columns]
33
+
34
+ # Adicionar índice baseado na posição
35
+ df.insert(0, "Dado", range(1, len(df) + 1))
36
+
37
+ # Arredondar colunas de tipo float para 4 casas decimais
38
+ for col in df.select_dtypes(include=[float]).columns:
39
+ df[col] = df[col].round(4)
40
+
41
+ cabecalhos = list(df.columns)
42
+ return cabecalhos, df
43
+ except Exception as e:
44
+ print(f"Erro ao carregar a planilha: {e}")
45
+ return [], pd.DataFrame()
46
+
47
+ # Função para aplicar a transformação selecionada
48
+ def aplicar_transformacao(df, coluna, transformacao):
49
+ try:
50
+ if transformacao == "1/x":
51
+ return 1 / df[coluna].replace(0, np.nan).fillna(0) # Evitar divisão por zero
52
+ elif transformacao == "ln(x)":
53
+ return np.log(df[coluna].replace(0, np.nan).fillna(0)) # Evitar log de zero
54
+ elif transformacao == "x²":
55
+ return df[coluna] ** 2
56
+ elif transformacao == "exp(x)":
57
+ return np.exp(df[coluna])
58
+ else:
59
+ return df[coluna] # Sem transformação, retorna a coluna original
60
+ except Exception as e:
61
+ return df[coluna] # Retorna original em caso de erro
62
+
63
+ # Função para criar gráficos de dispersão para análise exploratória com transformações
64
+ def grafico_dispersao(df, y_coluna, transformacao_y, x_coluna, transformacao_x, dados_out):
65
+ if df.empty or x_coluna not in df.columns or y_coluna not in df.columns:
66
+ return None # Retornar None se o DataFrame estiver vazio ou as colunas não forem válidas
67
+
68
+ # Copiar o DataFrame para manipulação
69
+ df_grafico = df.copy()
70
+ # Convertendo a entrada manual em uma lista de inteiros
71
+ dados_out = [int(num.strip()) for num in dados_out.split(",") if num.strip()]
72
+ # Removendo os outliers dos DataFrames
73
+ df_grafico = df_grafico[~df_grafico["Dado"].isin(dados_out)]
74
+ # Aplicar transformações nas colunas x e y
75
+ x = aplicar_transformacao(df_grafico, x_coluna, transformacao_x)
76
+ y = aplicar_transformacao(df_grafico, y_coluna, transformacao_y)
77
+ # Calcular a linha de tendência
78
+ coef = np.polyfit(x, y, 1) # Coeficientes da linha de tendência (linear)
79
+ linha_tendencia = np.poly1d(coef)
80
+ y_tendencia = linha_tendencia(x)
81
+ # Calcular resíduos (distância dos pontos à linha de tendência)
82
+ residuos = np.abs(y - y_tendencia)
83
+ # Normalizar os resíduos para aplicar o colormap
84
+ residuos_norm = (residuos - residuos.min()) / (residuos.max() - residuos.min())
85
+ # Calcular o valor de correlação
86
+ correlacao = np.corrcoef(x, y)[0, 1]
87
+ # Criar o gráfico de dispersão com Plotly
88
+ fig = go.Figure()
89
+ # Adicionar os pontos ao gráfico com colormap
90
+ fig.add_trace(go.Scatter(
91
+ x=x,
92
+ y=y,
93
+ mode='markers',
94
+ marker=dict(
95
+ size=8,
96
+ color=residuos_norm, # Colormap com base nos resíduos
97
+ colorscale='Spectral', # Escolher o esquema de cores (pode ser ajustado)
98
+ showscale=False, # Desabilitar a barra de cores
99
+ ),
100
+ text=[f"Índice: {idx}<br>{x_coluna}: {x_val:.2f}<br>{y_coluna}: {y_val:.2f}<br>Resíduo: {resid:.2f}"
101
+ for idx, x_val, y_val, resid in zip(df_grafico["Dado"], x, y, residuos)], # Informações no tooltip
102
+ hoverinfo="text"
103
+ ))
104
+
105
+ # Adicionar a linha de tendência ao gráfico
106
+ fig.add_trace(go.Scatter(
107
+ x=x,
108
+ y=y_tendencia,
109
+ mode='lines',
110
+ line=dict(color='darkred', width=2), # Linha de tendência com vermelho escuro
111
+ ))
112
+
113
+ # Atualizar o layout do gráfico
114
+ fig.update_layout(
115
+ title=f"Gráfico de Dispersão: {x_coluna} vs {y_coluna}<br>Correlação: {correlacao:.2f}",
116
+ xaxis_title=f"{x_coluna} ({transformacao_x})",
117
+ yaxis_title=f"{y_coluna} ({transformacao_y})",
118
+ template="plotly_white",
119
+ showlegend=False
120
+ )
121
+
122
+ return fig
123
+
124
+ # Função para criar boxplot para análise exploratória com transformações
125
+ def grafico_boxplot(df, y_coluna, transformacao_y, x_coluna, transformacao_x, dados_out):
126
+ if df.empty or y_coluna not in df.columns:
127
+ return None # Retorna None se o DataFrame estiver vazio ou as colunas não forem válidas
128
+
129
+ # Copiar o DataFrame para manipulação
130
+ df_boxplot = df.copy()
131
+
132
+ # Convertendo a entrada manual em uma lista de inteiros
133
+ dados_out = [int(num.strip()) for num in dados_out.split(",") if num.strip()]
134
+ # Removendo os outliers dos DataFrames
135
+ df_boxplot = df_boxplot[~df_boxplot["Dado"].isin(dados_out)]
136
+
137
+ # Aplicar transformação na coluna Y
138
+ y = aplicar_transformacao(df_boxplot, y_coluna, transformacao_y)
139
+
140
+ # Criar lista de textos personalizados para hover
141
+ hover_text = [
142
+ f"Índice: {idx}<br>{y_coluna}: {y_val:.2f}"
143
+ for idx, y_val in zip(df_boxplot["Dado"], y)
144
+ ]
145
+
146
+ # Criar o gráfico de boxplot com Plotly
147
+ fig = go.Figure()
148
+
149
+ # Adicionar os dados ao gráfico
150
+ fig.add_trace(go.Box(
151
+ y=y,
152
+ name=y_coluna,
153
+ boxpoints='all', # Mostra todos os pontos, incluindo outliers
154
+ jitter=0.8, # Espalhamento horizontal dos pontos
155
+ pointpos=-1.8, # Posição relativa dos pontos em relação ao boxplot
156
+ marker=dict(
157
+ color='orange',
158
+ size=8
159
+ ),
160
+ line=dict(color='gray'),
161
+ hovertemplate="%{text}", # Personaliza o hover
162
+ text=hover_text # Insere a lista de textos no hover
163
+ ))
164
+
165
+ # Atualizar o layout do gráfico
166
+ fig.update_layout(
167
+ title=f"Boxplot da Coluna: {y_coluna} ({transformacao_y})",
168
+ yaxis_title=f"{y_coluna} ({transformacao_y})",
169
+ template="plotly_white",
170
+ showlegend=False
171
+ )
172
+
173
+ return fig
174
+
175
+ # Função para atualizar os dropdowns
176
+ def atualizar_dropdowns(cabeçalhos):
177
+ if cabeçalhos:
178
+ # Remover 'Índice' das opções, se não for relevante para as análises
179
+ cabecalhos_sem_indice = [col for col in cabeçalhos if col != "Dado"]
180
+ dropdown_update_x = gr.update(choices=cabecalhos_sem_indice, value=cabecalhos_sem_indice)
181
+ dropdown_update = gr.update(choices=cabecalhos_sem_indice, value=[])
182
+ return [dropdown_update_x] + [dropdown_update] * 4 + [dropdown_update] # Inclui var_dep
183
+ else:
184
+ dropdown_reset = gr.update(choices=[], value=[])
185
+ return [dropdown_reset] * 5 + [dropdown_reset] # Inclui var_dep
186
+
187
+ # Função para criar os cabeçalhos e colocar os limites por variável sem os outliers
188
+ def criar_dataframe_cabecalhos(cabecalhos, x, ln_x, exp_x, inv_x, quad_x, dados, dados_out, var_dep):
189
+ if dados.empty:
190
+ return pd.DataFrame(), {}
191
+
192
+ # Remover os outliers antes de calcular os limites
193
+ if dados_out:
194
+ dados_out = [int(num.strip()) for num in dados_out.split(",") if num.strip()]
195
+ dados = dados[~dados["Dado"].isin(dados_out)]
196
+
197
+ # Criar um dicionário com as seleções
198
+ escalas = {
199
+ col: [escala] for col, escala in zip(
200
+ x + ln_x + exp_x + inv_x + quad_x,
201
+ ["(x)"] * len(x) + ["ln(x)"] * len(ln_x) + ["exp(x)"] * len(exp_x)
202
+ + ["1/(x)"] * len(inv_x) + ["(x)²"] * len(quad_x)
203
+ )
204
+ }
205
+
206
+ # Criar o DataFrame base
207
+ df = pd.DataFrame.from_dict(escalas, orient='index', columns=['Escala']).transpose()
208
+
209
+ # Reorganizar as colunas para garantir que 'var_dep' seja a primeira
210
+ if var_dep in df.columns:
211
+ cols = [var_dep] + [col for col in df.columns if col != var_dep]
212
+ df = df[cols]
213
+
214
+ # Calcular as linhas adicionais (máximo, mínimo, média) com duas casas decimais
215
+ limites = {
216
+ "Máximo": dados.max().round(2),
217
+ "Mínimo": dados.min().round(2),
218
+ "Média": dados.mean().round(2)
219
+ }
220
+
221
+ # Adicionar as linhas ao DataFrame
222
+ for label, valores in limites.items():
223
+ linha = {col: valores[col] if col in valores else '' for col in df.columns}
224
+ df = pd.concat([df, pd.DataFrame([linha], index=[label])])
225
+
226
+ return df, escalas
227
+
228
+ # Função para criar DataFrames original, escalado, correlação e outliers
229
+ def criar_dataframes(dados, x, ln_x, exp_x, inv_x, quad_x, dados_out, var_dep):
230
+ if dados.empty:
231
+ return pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), None
232
+
233
+ # Selecionar as colunas escolhidas e incluir "Dado" como identificador
234
+ colunas_escolhidas = x + ln_x + exp_x + inv_x + quad_x
235
+ df_original = dados[["Dado"] + colunas_escolhidas] # Incluindo "Dado"
236
+
237
+ # Aplicar escalas e manter "Dado"
238
+ df_escalado = pd.DataFrame()
239
+ df_escalado["Dado"] = dados["Dado"] # Preservar "Dado" no escalado
240
+
241
+ for col in x:
242
+ df_escalado[col] = dados[col] # (x)
243
+ for col in ln_x:
244
+ df_escalado[col] = np.log(dados[col].replace(0, np.nan)).fillna(0) # ln(x), evitando log de zero
245
+ for col in exp_x:
246
+ df_escalado[col] = np.exp(dados[col]) # exp(x)
247
+ for col in inv_x:
248
+ df_escalado[col] = 1 / dados[col].replace(0, np.nan).fillna(0) # 1/(x), evitando divisão por zero
249
+ for col in quad_x:
250
+ df_escalado[col] = dados[col] ** 2 # (x)²
251
+
252
+ # Reorganizar colunas para que var_dep fique como a segunda coluna
253
+ if var_dep in df_original.columns:
254
+ colunas_reorganizadas_original = (
255
+ ["Dado", var_dep] + [col for col in df_original.columns if col not in ["Dado", var_dep]]
256
+ )
257
+ df_original = df_original[colunas_reorganizadas_original]
258
+
259
+ if var_dep in df_escalado.columns:
260
+ colunas_reorganizadas_escalado = (
261
+ ["Dado", var_dep] + [col for col in df_escalado.columns if col not in ["Dado", var_dep]]
262
+ )
263
+ df_escalado = df_escalado[colunas_reorganizadas_escalado]
264
+
265
+ # Criando o novo DataFrame com a coluna 'variáveis' sem índice
266
+ df_variaveis = pd.DataFrame({'variáveis': df_original.columns})
267
+ df_variaveis.reset_index(drop=True, inplace=True)
268
+
269
+ # Verificar se dados_out está em branco
270
+ if not dados_out.strip():
271
+ df_outliers = pd.DataFrame() # DataFrame vazio para outliers
272
+ else:
273
+ # Convertendo a entrada manual em uma lista de inteiros
274
+ dados_out = [int(num.strip()) for num in dados_out.split(",") if num.strip()]
275
+ # Criando o DataFrame de outliers
276
+ df_outliers = df_original[df_original["Dado"].isin(dados_out)] # Filtrar com base nos valores de dados_out
277
+ # Removendo os outliers dos DataFrames originais e escalados
278
+ df_original = df_original[~df_original["Dado"].isin(dados_out)]
279
+ df_escalado = df_escalado[~df_escalado["Dado"].isin(dados_out)]
280
+
281
+ # Criar matriz de correlação
282
+ correlation_matrix = df_escalado.drop(columns=["Dado"]).corr().round(2) # "Dado" não entra na correlação
283
+
284
+ return df_original, df_escalado, df_outliers # , correlation_matrix
285
+
286
+ # Função para Regressão Linear
287
+ def realizar_regressao(var_dep, dados_transformados, df_original, escalas):
288
+ if isinstance(dados_transformados, pd.DataFrame) and not dados_transformados.empty:
289
+ try:
290
+ import statsmodels.api as sm
291
+ import numpy as np
292
+
293
+ if var_dep in dados_transformados.columns:
294
+ # Separando X e y
295
+ y = dados_transformados[var_dep]
296
+ X = dados_transformados.drop(columns=[var_dep, "Dado"])
297
+
298
+ # Número de variáveis independentes
299
+ num_variaveis = X.shape[1]
300
+
301
+ # Adicionando constante
302
+ X = sm.add_constant(X)
303
+
304
+ # Ajustando modelo
305
+ modelo = sm.OLS(y, X).fit()
306
+
307
+ # Inicializar resultados gerais
308
+ resultados_gerais = ""
309
+
310
+ # Estatísticas gerais do modelo
311
+ residuos = modelo.resid
312
+ desvio_padrao_residuos = round(np.std(residuos), 8)
313
+ erro_padronizado = np.round(residuos / desvio_padrao_residuos, 8)
314
+ estatistica_F = round(modelo.fvalue, 8)
315
+ nivel_significancia = round(modelo.f_pvalue, 8)
316
+ r_squared = round(modelo.rsquared, 8)
317
+ r_squared_adjusted = round(modelo.rsquared_adj, 8)
318
+ num_observacoes = int(round(modelo.nobs, 0))
319
+ coef_correlacao = round(np.sqrt(r_squared), 8)
320
+
321
+ # Comparação com a curva normal de resíduos
322
+ intervalos = [(-1.00, 1.00), (-1.64, 1.64), (-1.96, 1.96)]
323
+ percentuais = []
324
+ for intervalo in intervalos:
325
+ min_intervalo, max_intervalo = intervalo
326
+ count = np.sum((erro_padronizado >= min_intervalo) & (erro_padronizado <= max_intervalo))
327
+ percentual = round(count / len(erro_padronizado) * 100, 0)
328
+ percentuais.append(f"{percentual:.0f}%")
329
+ perc_resid = ", ".join(percentuais)
330
+
331
+ # Teste Kolmogorov-Smirnov (KS)
332
+ ks_test = sm.stats.diagnostic.kstest_normal(residuos)
333
+ ks_test_formatted = tuple(f"{val:.4f}" for val in ks_test)
334
+
335
+ import statsmodels.api as sm
336
+
337
+ # Teste Kolmogorov-Smirnov (KS)
338
+ ks_test = sm.stats.diagnostic.kstest_normal(residuos)
339
+ ks_test_formatted = tuple(f"{val:.4f}" for val in ks_test)
340
+
341
+ # Interpretando o resultado
342
+ estatistica_ks, p_valor_ks = ks_test # Desempacotando os valores
343
+
344
+ if p_valor_ks > 0.05:
345
+ ks_interpretacao = "Não há evidências estatísticas suficientes para rejeitar a hipótese nula. Os resíduos podem seguir uma distribuição normal."
346
+ else:
347
+ ks_interpretacao = "Rejeitamos a hipótese nula. Há evidências estatísticas de que os resíduos não seguem uma distribuição normal."
348
+
349
+
350
+ # Distância de Cook
351
+ influencia = modelo.get_influence()
352
+ distancia_cook = influencia.cooks_distance[0]
353
+
354
+ # Criar DataFrame com resultados por variável
355
+ coeficientes = modelo.params
356
+ erros_padrao = modelo.bse
357
+ t_values = modelo.tvalues
358
+ p_values = modelo.pvalues
359
+
360
+ # Adicionar a coluna Escala com base no dicionário de escalas
361
+ escalas_coluna = [escalas[var][0] if var in escalas else "Nenhuma" for var in coeficientes.index]
362
+
363
+ resultados_vars = pd.DataFrame({
364
+ "Variável": coeficientes.index,
365
+ "Escala": escalas_coluna, # Adicionando a coluna Escala
366
+ "Coeficiente": coeficientes.values.round(4),
367
+ "Erro Padrão": erros_padrao.values.round(4),
368
+ "t-valor": t_values.values.round(4),
369
+ "P>|t|": p_values.values.round(4)
370
+ })
371
+
372
+ # Expressão da equação do modelo com a variável dependente transformada
373
+ if var_dep in escalas:
374
+ escala_y = escalas[var_dep][0] # Obter a escala associada
375
+ if escala_y == "ln(x)":
376
+ y_label_transformada = f"ln({var_dep})"
377
+ ajustar_termo = lambda termo: f"exp({termo})" # Aplicar exponencial
378
+ elif escala_y == "1/(x)":
379
+ y_label_transformada = f"1/({var_dep})"
380
+ ajustar_termo = lambda termo: f"1/({termo})" # Aplicar inverso
381
+ elif escala_y == "(x)²":
382
+ y_label_transformada = f"({var_dep})²"
383
+ ajustar_termo = lambda termo: f"sqrt({termo})" # Aplicar raiz quadrada
384
+ elif escala_y == "exp(x)":
385
+ y_label_transformada = f"exp({var_dep})"
386
+ ajustar_termo = lambda termo: f"ln({termo})" # Aplicar logaritmo natural
387
+ else:
388
+ y_label_transformada = var_dep # Sem transformação
389
+ ajustar_termo = lambda termo: termo # Sem ajuste
390
+ else:
391
+ y_label_transformada = var_dep # Sem transformação
392
+ ajustar_termo = lambda termo: termo # Sem ajuste
393
+
394
+ # Construir os termos da equação
395
+ termos = []
396
+ for var, coef in zip(coeficientes.index, coeficientes.values):
397
+ if var == 'const':
398
+ interseção = f"{coef:.4f}"
399
+ else:
400
+ if var in escalas:
401
+ escala_var = escalas[var][0] # Obter a escala associada
402
+ if escala_var == "ln(x)":
403
+ var_label = f"ln({var})"
404
+ elif escala_var == "1/(x)":
405
+ var_label = f"1/({var})"
406
+ elif escala_var == "(x)²":
407
+ var_label = f"({var})²"
408
+ elif escala_var == "exp(x)":
409
+ var_label = f"exp({var})"
410
+ else:
411
+ var_label = var # Sem transformação
412
+ else:
413
+ var_label = var # Sem transformação
414
+ termos.append(f"{coef:.4f} * {var_label}")
415
+
416
+ # Montar a equação com a variável dependente transformada
417
+ lado_direito = interseção + " + " + " + ".join(termos)
418
+ equacao_transformada = f"{y_label_transformada} = {lado_direito}"
419
+ # Montar a equação com a variável dependente na escala direta
420
+ equacao_revertida = f"{var_dep} = {ajustar_termo(lado_direito)}"
421
+ # Substituir pontos por vírgulas nas equações
422
+ equacao_transformada = equacao_transformada.replace('.', ',')
423
+ equacao_revertida = equacao_revertida.replace('.', ',')
424
+ # Adicionar as duas formas da equação aos resultados gerais
425
+ #resultados_gerais += f"\nEquação do modelo (variável dependente transformada): {equacao_transformada}"
426
+ resultados_gerais += f"\nEquação do modelo (variável dependente na escala direta): {equacao_revertida}"
427
+
428
+ # Classificar variáveis com base nos p-valores
429
+ def classificar(valor):
430
+ if valor > 0.3:
431
+ return "Fora dos critérios"
432
+ elif valor > 0.2:
433
+ return "Grau I"
434
+ elif valor > 0.1:
435
+ return "Grau II"
436
+ else:
437
+ return "Grau III"
438
+
439
+ resultados_vars['Classificação'] = resultados_vars['P>|t|'].apply(classificar)
440
+
441
+ # Determinar grau único considerando todas as variáveis
442
+ def determinar_grau_unico(classificacoes):
443
+ if "Fora dos critérios" in classificacoes:
444
+ return "Fora dos critérios"
445
+ elif "Grau I" in classificacoes:
446
+ return "Grau I"
447
+ elif "Grau II" in classificacoes:
448
+ return "Grau II"
449
+ else:
450
+ return "Grau III"
451
+
452
+ tab5 = determinar_grau_unico(resultados_vars['Classificação'])
453
+
454
+ # Enquadramento na NBR 14.653-2
455
+ # Item 2 da tabela
456
+ if num_observacoes >= 6 * (num_variaveis + 1):
457
+ tab2 = "Grau III"
458
+ elif num_observacoes >= 4 * (num_variaveis + 1):
459
+ tab2 = "Grau II"
460
+ elif num_observacoes >= 3 * (num_variaveis + 1):
461
+ tab2 = "Grau I"
462
+ else:
463
+ tab2 = "Fora dos critérios"
464
+
465
+ # Item 6 da tabela
466
+ if nivel_significancia <= 0.01:
467
+ tab6 = "Grau III"
468
+ elif nivel_significancia <= 0.02:
469
+ tab6 = "Grau II"
470
+ elif nivel_significancia <= 0.05:
471
+ tab6 = "Grau I"
472
+ else:
473
+ tab6 = "Fora dos critérios"
474
+
475
+ # Resultados gerais formatados
476
+ resultados_gerais = f"""
477
+ Desvio Padrão dos Resíduos: {desvio_padrao_residuos}
478
+ Estatística F: {estatistica_F} | Nível de Significância: {nivel_significancia}
479
+ R²: {r_squared} | R² Ajustado: {r_squared_adjusted}
480
+ Correlação: {coef_correlacao}
481
+ Número de Observações: {num_observacoes}
482
+ Número de Variáveis Independentes: {num_variaveis}
483
+
484
+ Fundamentação - Quant. min. dados (Item 2 tab 9.2.1 NBR 14.653-2): {tab2}
485
+ Fundamentação - Signif. Regressores (Item 5 tab 9.2.1 NBR 14.653-2): {tab5}
486
+ Fundamentação - Signif. Modelo (Item 6 tab 9.2.1 NBR 14.653-2): {tab6}
487
+
488
+ Testes de normalidade:
489
+ 1) Comparação (curva normal) - Percentuais atingidos: {perc_resid}
490
+ Ideal 68% - aceitável de 64% a 75%
491
+ Ideal 90% - aceitável de 88% a 95%
492
+ Ideal 95% - aceitável de 95% a 100%
493
+
494
+ Teste Kolmogorov-Smirnov: Estatística = {ks_test_formatted[0]}, Valor-p = {ks_test_formatted[1]} - ({ks_interpretacao})
495
+
496
+ Distância de Cook (Máxima): {np.max(distancia_cook):.8f}
497
+
498
+ Equação do modelo: {equacao_revertida}
499
+ """
500
+
501
+ # Adicionando a coluna de erro padronizado ao df_final
502
+ df_original_res = df_original.copy()
503
+ df_original_res['Erro Padronizado'] = erro_padronizado
504
+
505
+ # Criar DataFrame apenas com os dados cujo erro padronizado é maior que 2
506
+ df_grandes_residuos = df_original_res[abs(df_original_res['Erro Padronizado']) > 2].copy()
507
+ df_grandes_residuos['Erro Abs'] = abs(df_grandes_residuos['Erro Padronizado'])
508
+
509
+ # Listagem de pontos com resíduos > 2
510
+ listagem_grandes_residuos = ", ".join(map(str, df_grandes_residuos.iloc[:, 0].tolist()))
511
+
512
+ # Listagem dos pontos influenciantes
513
+ limite_cook = 1
514
+ pontos_influentes = []
515
+ for i, cook_dist in enumerate(distancia_cook):
516
+ if cook_dist > limite_cook:
517
+ pontos_influentes.append(dados_transformados.iloc[i]["Dado"]) # Usando a primeira coluna como rótulo
518
+
519
+ # Transformando a lista em uma string separada por vírgula
520
+ listagem_pontos_influentes = ", ".join(map(str, pontos_influentes))
521
+
522
+ # Criação de um dataframe para valores previstos
523
+ valores_previstos = modelo.predict(X)
524
+ valores_previstos_trans = valores_previstos.copy()
525
+ # Reverter a escala da variável dependente, se aplicável
526
+ if var_dep in escalas:
527
+ escala_var_dep = escalas[var_dep][0] # Obtém a escala associada
528
+
529
+ if escala_var_dep == "ln(x)":
530
+ valores_previstos = np.exp(valores_previstos) # Reverte ln(x) para x
531
+ elif escala_var_dep == "1/(x)":
532
+ valores_previstos = 1 / valores_previstos # Reverte 1/(x) para x
533
+ elif escala_var_dep == "(x)²":
534
+ valores_previstos = np.sqrt(valores_previstos) # Reverte (x)² para x
535
+ elif escala_var_dep == "exp(x)":
536
+ valores_previstos = np.log(valores_previstos) # Reverte exp(x) para x
537
+ # Caso não seja necessário reverter, mantém os valores ajustados como estão
538
+
539
+ # Adicionando os valores ajustados como uma nova coluna ao DataFrame original
540
+ df_calc_obs = df_original.copy()
541
+ df_calc_obs['Valores Ajustados'] = round(valores_previstos, 8)
542
+ # Resíduo
543
+ df_calc_obs['Resíduo'] = (df_calc_obs[var_dep].replace(0, np.nan) - df_calc_obs['Valores Ajustados']).round(4)
544
+ # Erro padronizado
545
+ df_calc_obs['Erro Padronizado'] = erro_padronizado.round(4)
546
+ # Adicionando a coluna de Erro
547
+ # Certifique-se de evitar divisão por zero
548
+ df_calc_obs['Erro'] = df_calc_obs['Valores Ajustados'] / df_calc_obs[var_dep].replace(0, np.nan)
549
+ # Arredondar os valores da coluna 'Erro' para melhorar a apresentação
550
+ df_calc_obs['Erro'] = df_calc_obs['Erro'].round(4)
551
+ # Criando a coluna de erro percentual
552
+ df_calc_obs['Erro Percentual (%)'] = (abs(df_calc_obs['Erro'] - 1) * 100).round(4)
553
+
554
+ # Adicionando os valores ajustados como uma nova coluna ao DataFrame original
555
+ df_calc_obs_trans = dados_transformados.copy()
556
+ df_calc_obs_trans['Valores Ajustados'] = round(valores_previstos_trans, 8)
557
+
558
+ return resultados_gerais, resultados_vars, df_grandes_residuos, listagem_grandes_residuos, listagem_pontos_influentes, df_calc_obs, df_calc_obs_trans, erro_padronizado, modelo
559
+ else:
560
+ return "Erro: A variável dependente não está nos dados transformados.", pd.DataFrame(), pd.DataFrame(), "Erro", "Erro", pd.DataFrame(), pd.DataFrame(), [], None
561
+ except Exception as e:
562
+ return f"Erro na regressão: {str(e)}", pd.DataFrame(), pd.DataFrame(), "Erro", "Erro", pd.DataFrame(), pd.DataFrame(), [], None
563
+ else:
564
+ return "Erro: Dados transformados inválidos ou vazios.", pd.DataFrame(), pd.DataFrame(), "Erro", "Erro", pd.DataFrame(), pd.DataFrame(), [], None
565
+
566
+ # Função para plotar gráficos do modelo
567
+ def graficos(escala_dependente, df_calc_obs, df_calc_obs_trans, erro_padronizado, var_dep, num_bins=20):
568
+
569
+ # Gráfico 1: Resíduos Padronizados
570
+ # Normalizar os resíduos padronizados para o colormap
571
+ residuos_norm = (np.abs(erro_padronizado) - np.abs(erro_padronizado).min()) / \
572
+ (np.abs(erro_padronizado).max() - np.abs(erro_padronizado).min())
573
+
574
+ fig1 = go.Figure()
575
+ fig1.add_trace(go.Scatter(
576
+ x=df_calc_obs_trans['Valores Ajustados'],
577
+ y=erro_padronizado,
578
+ mode='markers',
579
+ marker=dict(
580
+ size=8,
581
+ color=residuos_norm, # Aplicar o colorscale
582
+ colorscale='Spectral', # Escolher a paleta de cores
583
+ ),
584
+ text=df_calc_obs_trans.iloc[:, 0],
585
+ hovertemplate="<b>Índice: %{text}</b><br>Valores Ajustados: %{x:.2f}<br>Resíduos: %{y:.2f}<extra></extra>"
586
+ ))
587
+ fig1.add_hline(y=0, line_dash="dash", line_color="black")
588
+ fig1.add_hline(y=2, line_dash="dot", line_color="red")
589
+ fig1.add_hline(y=-2, line_dash="dot", line_color="red")
590
+ fig1.update_layout(
591
+ title="Gráfico de Resíduos Padronizados",
592
+ xaxis_title="Valores Ajustados",
593
+ yaxis_title="Resíduos Padronizados",
594
+ template="plotly_white"
595
+ )
596
+
597
+ # Gráfico 2: Histograma dos Resíduos Padronizados com Curva Normal
598
+ # Calcula média e desvio padrão dos resíduos
599
+ mean_residuos = np.mean(erro_padronizado)
600
+ std_residuos = np.std(erro_padronizado)
601
+
602
+ # Dados para a curva normal
603
+ x_vals = np.linspace(mean_residuos - 4 * std_residuos, mean_residuos + 4 * std_residuos, 500)
604
+ y_vals = stats.norm.pdf(x_vals, mean_residuos, std_residuos) # PDF da curva normal
605
+
606
+ # Criar o histograma (frequência normalizada)
607
+ hist_values, bin_edges = np.histogram(erro_padronizado, bins=num_bins, density=True)
608
+ scale_factor = max(hist_values) / max(y_vals) # Ajustar altura da curva normal
609
+ y_vals_scaled = y_vals * scale_factor
610
+
611
+ # Calcular o valor médio dos resíduos absolutos para cada bin
612
+ bin_centers = bin_edges[:-1] + np.diff(bin_edges) / 2
613
+ bin_colors = 1 - (np.abs(bin_centers) - np.abs(bin_centers).min()) / (np.abs(bin_centers).max() - np.abs(bin_centers).min())
614
+
615
+ fig2 = go.Figure()
616
+ fig2.add_trace(go.Bar(
617
+ x=bin_centers, # Centraliza as barras
618
+ y=hist_values,
619
+ width=np.diff(bin_edges),
620
+ marker=dict(
621
+ color=bin_colors, # Aplicar o colorscale
622
+ colorscale='Reds',
623
+ ),
624
+ opacity=0.7,
625
+ name='Histograma'
626
+ ))
627
+
628
+ # Adicionar a curva normal ajustada
629
+ fig2.add_trace(go.Scatter(
630
+ x=x_vals,
631
+ y=y_vals_scaled,
632
+ mode='lines',
633
+ line=dict(color='red', width=2),
634
+ name='Curva Normal'
635
+ ))
636
+
637
+ fig2.update_layout(
638
+ title="Histograma dos Resíduos Padronizados com Curva Normal",
639
+ xaxis_title="Resíduos Padronizados",
640
+ yaxis_title="Frequência Normalizada",
641
+ template="plotly_white",
642
+ )
643
+
644
+ # Gráfico 3: Valores Ajustados vs Preços Observados
645
+ if escala_dependente == "Direta":
646
+ df_graf_ao = df_calc_obs
647
+ else:
648
+ df_graf_ao = df_calc_obs_trans
649
+
650
+ # Definir os eixos
651
+ valores_observados = df_graf_ao.iloc[:, 1] # Segunda coluna do DataFrame
652
+ valores_calculados = df_graf_ao['Valores Ajustados']
653
+
654
+ # Cálculo dos resíduos normalizados
655
+ residuos = np.abs(valores_observados - valores_calculados)
656
+ residuos_norm = (residuos - residuos.min()) / (residuos.max() - residuos.min()) # Normalizar para o colorscale
657
+
658
+ # Ajustar a reta de regressão linear com statsmodels
659
+ X = sm.add_constant(valores_observados) # Adicionar uma constante (intercepto)
660
+ modelo = sm.OLS(valores_calculados, X).fit() # Ajustar o modelo OLS
661
+ x_reta = np.linspace(valores_observados.min(), valores_observados.max(), 100) # Valores de X para a reta
662
+ y_reta = modelo.predict(sm.add_constant(x_reta)) # Predizer Y com base no modelo
663
+
664
+ # Criar o gráfico
665
+ fig3 = go.Figure()
666
+ fig3.add_trace(go.Scatter(
667
+ x=valores_observados,
668
+ y=valores_calculados,
669
+ mode='markers',
670
+ marker=dict(
671
+ size=8,
672
+ color=residuos_norm, # Aplicar o colorscale
673
+ colorscale='Spectral', # Escolher a paleta de cores
674
+ showscale=False
675
+ ),
676
+ text=df_graf_ao.iloc[:, 0], # Índice ou outra coluna para hover
677
+ hovertemplate="<b>Índice: %{text}</b><br>Observado: %{x:.2f}<br>Ajustado: %{y:.2f}<extra></extra>",
678
+ showlegend=False # Remover legenda deste trace
679
+ ))
680
+
681
+ # Adicionar a reta ajustada (linha de regressão)
682
+ fig3.add_trace(go.Scatter(
683
+ x=x_reta,
684
+ y=y_reta,
685
+ mode="lines",
686
+ line=dict(color="green", dash="solid"),
687
+ name="Reta Ajustada"
688
+ ))
689
+
690
+ # Configuração do layout
691
+ fig3.update_layout(
692
+ title="Valores Ajustados vs Preços Observados",
693
+ xaxis_title="Preços Observados",
694
+ yaxis_title="Valores Ajustados",
695
+ template="plotly_white",
696
+ showlegend=False # Remover legenda
697
+ )
698
+
699
+
700
+
701
+ # Gráfico 4: Matriz de Correlações
702
+ corr_matrix = df_calc_obs_trans.drop(columns=["Dado", "Valores Ajustados"], errors='ignore').corr()
703
+
704
+ # Criar o Heatmap diretamente com texto
705
+ fig4 = go.Figure()
706
+
707
+ # Adicionar os valores manualmente como anotação no gráfico
708
+ for i, row in enumerate(corr_matrix.index):
709
+ for j, col in enumerate(corr_matrix.columns):
710
+ # Determinar a cor do texto com base nas condições
711
+ if row == col:
712
+ color = "black" # Preto para a diagonal (mesma variável)
713
+ elif corr_matrix.loc[row, col] > 0.8: # Correlação acima de 0.8
714
+ if row == var_dep or col == var_dep:
715
+ color = "blue" #tr Azul para correlação com var_dep
716
+ else:
717
+ color = "red" # Vermelho para correlação alta entre variáveis independentes
718
+ else:
719
+ color = "black" # Preto para todas as outras correlações
720
+
721
+ # Adicionar o texto no gráfico
722
+ fig4.add_trace(go.Scatter(
723
+ x=[col],
724
+ y=[row],
725
+ text=[f"{corr_matrix.loc[row, col]:.2f}"],
726
+ mode="text",
727
+ textfont=dict(size=12, color=color), # Aplicar a cor
728
+ ))
729
+
730
+ # Atualizar o layout
731
+ fig4.update_layout(
732
+ title="Matriz de Correlações",
733
+ xaxis=dict(title="Variáveis", tickmode='array', tickvals=corr_matrix.columns),
734
+ yaxis=dict(title="Variáveis", tickmode='array', tickvals=corr_matrix.index),
735
+ template="plotly_white",
736
+ showlegend=False
737
+ )
738
+
739
+ return fig1, fig2, fig3, fig4
740
+
741
+ # Função para exportar para o excel
742
+ def exportar_para_excel(nome_arquivo, df_planilha, df_infos, df_original, df_escalado, df_outliers, resultados_gerais, resultados_vars, df_calc_obs, df_calc_obs_trans):
743
+ try:
744
+ # Criar um arquivo Excel com múltiplas abas
745
+ with pd.ExcelWriter(nome_arquivo, engine='xlsxwriter') as writer:
746
+ # Adicionar os DataFrames em abas específicas
747
+ df_planilha.to_excel(writer, sheet_name='Dados Originais', index=False)
748
+ df_infos.to_excel(writer, sheet_name='Infos', index=False)
749
+ df_original.to_excel(writer, sheet_name='Dados Modelo', index=False)
750
+ #df_escalado.to_excel(writer, sheet_name='Dados Modelo Transformados', index=False)
751
+ df_outliers.to_excel(writer, sheet_name='Outliers', index=False)
752
+
753
+ # Converter "Resultados Gerais" para um DataFrame formatado
754
+ resultados_lista = [linha.strip() for linha in resultados_gerais.split("\n") if linha.strip()]
755
+ resultados_df = pd.DataFrame({"Descrição": resultados_lista})
756
+ resultados_df.to_excel(writer, sheet_name='Resultados Gerais', index=False)
757
+
758
+ # Resultados por variável
759
+ resultados_vars.to_excel(writer, sheet_name='Resultados Variáveis', index=False)
760
+
761
+ # Valores calculados x observados
762
+ df_calc_obs.to_excel(writer, sheet_name='Calc x Obs', index=False)
763
+
764
+ # Valores calculados transformados
765
+ #df_calc_obs_trans.to_excel(writer, sheet_name='Calculados Transformados', index=False)
766
+
767
+ return f"Arquivo '{nome_arquivo}' criado com sucesso."
768
+ except Exception as e:
769
+ return f"Erro ao criar o arquivo Excel: {str(e)}"
770
+
771
+ # Função para salvar o modelo
772
+ def exportar_modelo_completo_avse(nome_pacote, modelo, resultados_gerais, df_planilha, df_infos, df_original, df_outliers, resultados_vars, df_calc_obs):
773
+ try:
774
+ # Verificar se o nome do pacote está vazio
775
+ if not nome_pacote:
776
+ return "Erro: O nome do arquivo não pode estar vazio."
777
+
778
+ # Garantir que o nome do pacote tenha a extensão .avse
779
+ if not nome_pacote.endswith(".avse"):
780
+ nome_pacote += ".avse"
781
+
782
+ # Empacotar todos os itens em um dicionário
783
+ pacote = {
784
+ "modelo": modelo,
785
+ "Resultados Gerais": resultados_gerais,
786
+ "df_planilha": df_planilha,
787
+ "df_infos": df_infos,
788
+ "df_original": df_original,
789
+ "df_outliers": df_outliers,
790
+ "resultados_vars": resultados_vars,
791
+ "df_calc_obs": df_calc_obs
792
+ }
793
+
794
+ # Salvar o pacote usando joblib
795
+ dump(pacote, nome_pacote)
796
+ return f"Pacote '{nome_pacote}' criado com sucesso."
797
+ except Exception as e:
798
+ return f"Erro ao criar o pacote: {str(e)}"
799
+
800
+ # Função para carregar o modelo
801
+ def carregar_modelo(nome_pacote):
802
+ try:
803
+ # Carregar o pacote salvo
804
+ pacote = joblib.load(nome_pacote)
805
+
806
+ # Recuperar os objetos do pacote
807
+ modelo = pacote.get("modelo", None) # Objeto do modelo salvo
808
+ resultados_gerais = pacote.get("Resultados Gerais", "") # Resultados gerais do modelo
809
+ df_planilha = pacote.get("df_planilha", pd.DataFrame())
810
+ df_infos = pacote.get("df_infos", pd.DataFrame())
811
+ df_original = pacote.get("df_original", pd.DataFrame())
812
+ df_outliers = pacote.get("df_outliers", pd.DataFrame())
813
+ resultados_vars = pacote.get("resultados_vars", pd.DataFrame())
814
+ df_calc_obs = pacote.get("df_calc_obs", pd.DataFrame())
815
+
816
+ # Adicionar uma linha em branco no df_infos se ele não estiver vazio
817
+ if not df_infos.empty:
818
+ df_infos.loc[len(df_infos)] = [None] * len(df_infos.columns)
819
+
820
+ # Transpor o DataFrame
821
+ df_infos_transposed = df_infos.T
822
+
823
+ # Renomear as colunas
824
+ df_infos_transposed.columns = ['Escalas', 'Máximo', 'Mínimo', 'Médio', 'Avaliando']
825
+
826
+ # Adicionar a coluna 'Variáveis' com os nomes das colunas originais
827
+ df_infos_transposed.insert(0, 'Variáveis', df_infos.columns)
828
+
829
+ # Atribuir o valor padrão "------" à célula da primeira linha da última coluna
830
+ df_infos_transposed.iloc[0, -1] = "Variável dependente"
831
+
832
+ # Obter apenas o nome do arquivo, sem o caminho
833
+ nome_arquivo = os.path.basename(nome_pacote)
834
+
835
+ # Criar mensagem de sucesso com o nome do modelo
836
+ mensagem_sucesso = f"Modelo '{nome_arquivo}' carregado com sucesso."
837
+
838
+ # Retornar todos os componentes necessários
839
+ return (
840
+ mensagem_sucesso, # Mensagem de sucesso com o nome do modelo
841
+ modelo, # Modelo carregado para previsões
842
+ resultados_gerais, # Resultados gerais do modelo
843
+ df_planilha, # Dados originais
844
+ df_original, # Dados usados no modelo
845
+ df_outliers, # Outliers identificados
846
+ resultados_vars, # Resultados por variável
847
+ df_calc_obs, # Dados calculados x observados
848
+ df_infos_transposed, # Informações adicionais do modelo
849
+ )
850
+ except Exception as e:
851
+ # Retornar valores padrão em caso de erro
852
+ return (
853
+ "Carregue o modelo antes de clicar no botão VISUALIZAR MODELO",
854
+ None, # Modelo não carregado
855
+ "", # Resultados gerais vazio
856
+ pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), pd.DataFrame(),
857
+ )
858
+
859
+
860
+
861
+ def realizar_previsoes(modelo, tab_infos_carregada):
862
+ try:
863
+ if modelo is None or tab_infos_carregada.empty:
864
+ return "Erro: Modelo não carregado ou tabela de informações vazia.", pd.DataFrame(), pd.DataFrame(), ""
865
+
866
+ # Identificar as escalas das variáveis independentes e dependente
867
+ escalas_independentes = tab_infos_carregada.iloc[1:, 1].to_list() # a partir da 2ª linha da 2ª coluna
868
+ escala_dependente = tab_infos_carregada.iloc[0, 1] # 1ª linha da 2ª coluna
869
+
870
+ # Valores para previsão estão a partir da 2ª linha da 6ª coluna
871
+ valores_entrada = tab_infos_carregada.iloc[1:, 5].values
872
+
873
+ # Converter valores para numéricos, substituindo inválidos por NaN
874
+ valores_entrada = pd.to_numeric(valores_entrada, errors='coerce')
875
+
876
+ # Aplicar escalas às variáveis independentes
877
+ valores_transformados = []
878
+ for valor, escala in zip(valores_entrada, escalas_independentes):
879
+ if np.isnan(valor):
880
+ valores_transformados.append(np.nan) # Manter NaN se o valor for inválido
881
+ elif escala == "ln(x)":
882
+ valores_transformados.append(np.log(valor) if valor > 0 else np.nan) # Evitar log de zero ou negativo
883
+ elif escala == "1/(x)":
884
+ valores_transformados.append(1 / valor if valor != 0 else np.nan) # Evitar divisão por zero
885
+ elif escala == "(x)²":
886
+ valores_transformados.append(valor ** 2)
887
+ elif escala == "exp(x)":
888
+ valores_transformados.append(np.exp(valor))
889
+ else:
890
+ valores_transformados.append(valor)
891
+
892
+ # Transformar em DataFrame para manter o formato necessário
893
+ df_previsao = pd.DataFrame([valores_transformados], columns=tab_infos_carregada.iloc[1:, 0])
894
+
895
+ # Adicionar constante ao modelo para previsão
896
+ X = sm.add_constant(df_previsao, has_constant='add')
897
+
898
+ # Garantir que as colunas em X correspondam às usadas no modelo
899
+ colunas_modelo = modelo.model.exog_names
900
+ X = X.reindex(columns=colunas_modelo, fill_value=0) # Reordenar e preencher colunas faltantes com 0
901
+
902
+ # Verificar se existem valores NaN nos dados transformados
903
+ if X.isnull().values.any():
904
+ return "Erro: Existem valores inválidos após a transformação. Verifique os dados de entrada.", df_previsao, pd.DataFrame(), ""
905
+
906
+ # Realizar a previsão
907
+ previsao_transformada = modelo.predict(X).iloc[0]
908
+
909
+ # Ajustar para a escala direta da variável dependente
910
+ if escala_dependente == "ln(x)":
911
+ previsao_final = np.exp(previsao_transformada)
912
+ elif escala_dependente == "1/(x)":
913
+ previsao_final = 1 / previsao_transformada
914
+ elif escala_dependente == "(x)²":
915
+ previsao_final = np.sqrt(previsao_transformada)
916
+ elif escala_dependente == "exp(x)":
917
+ previsao_final = np.log(previsao_transformada)
918
+ else:
919
+ previsao_final = previsao_transformada
920
+
921
+ # Calcular limites do campo de arbítrio
922
+ limite_inferior_arbitrio = previsao_final * 0.85
923
+ limite_superior_arbitrio = previsao_final * 1.15
924
+
925
+ # Calcular intervalo de confiança de 80%
926
+ intervalos = modelo.get_prediction(X).conf_int(alpha=0.2)
927
+ limite_inferior_ic = intervalos[0, 0] # Acessar diretamente o valor do array
928
+ limite_superior_ic = intervalos[0, 1] # Acessar diretamente o valor do array
929
+
930
+ # Ajustar limites de IC para a escala direta, se necessário
931
+ if escala_dependente == "ln(x)":
932
+ limite_inferior_ic = np.exp(limite_inferior_ic)
933
+ limite_superior_ic = np.exp(limite_superior_ic)
934
+ elif escala_dependente == "1/(x)":
935
+ limite_inferior_ic = 1 / limite_inferior_ic
936
+ limite_superior_ic = 1 / limite_superior_ic
937
+ elif escala_dependente == "(x)²":
938
+ limite_inferior_ic = np.sqrt(limite_inferior_ic)
939
+ limite_superior_ic = np.sqrt(limite_superior_ic)
940
+ elif escala_dependente == "exp(x)":
941
+ limite_inferior_ic = np.log(limite_inferior_ic)
942
+ limite_superior_ic = np.log(limite_superior_ic)
943
+
944
+ # Cálculo da extrapolação
945
+ extrapolacao_info = ""
946
+ valores_ajustados = valores_entrada.copy()
947
+ contagem_extrapolacoes = 0
948
+ fora_dos_criterios = False
949
+ for i, valor in enumerate(valores_entrada):
950
+ maximo = pd.to_numeric(tab_infos_carregada.iloc[i+1, 2], errors='coerce') # Coluna 3 (Mínimo)
951
+ minimo = pd.to_numeric(tab_infos_carregada.iloc[i+1, 3], errors='coerce') # Coluna 4 (Máximo)
952
+
953
+ if not np.isnan(valor):
954
+ if valor < minimo:
955
+ percentual_extrapolacao = ((minimo - valor) / minimo) * -100
956
+ extrapolacao_info += f"Variável '{tab_infos_carregada.iloc[i+1, 0]}' está {percentual_extrapolacao:.2f}% abaixo do mínimo da amostra.\n"
957
+ valores_ajustados[i] = minimo # Ajustar valor para o mínimo
958
+ contagem_extrapolacoes += 1
959
+ if percentual_extrapolacao < -50:
960
+ fora_dos_criterios = True
961
+ elif valor > maximo:
962
+ percentual_extrapolacao = ((valor - maximo) / maximo) * 100
963
+ extrapolacao_info += f"Variável '{tab_infos_carregada.iloc[i+1, 0]}' está {percentual_extrapolacao:.2f}% acima do máximo da amostra.\n"
964
+ valores_ajustados[i] = maximo # Ajustar valor para o máximo
965
+ contagem_extrapolacoes += 1
966
+ if percentual_extrapolacao > 100:
967
+ fora_dos_criterios = True
968
+
969
+ # Criar novos DataFrames para cada variável que extrapolou
970
+ previsoes_extrapoladas = []
971
+ for i, (valor, ajustado) in enumerate(zip(valores_entrada, valores_ajustados)):
972
+ if valor != ajustado:
973
+ valores_transformados_ext = []
974
+ for valor_ext, escala in zip(valores_ajustados, escalas_independentes):
975
+ if np.isnan(valor_ext):
976
+ valores_transformados_ext.append(np.nan)
977
+ elif escala == "ln(x)":
978
+ valores_transformados_ext.append(np.log(valor_ext) if valor_ext > 0 else np.nan)
979
+ elif escala == "1/(x)":
980
+ valores_transformados_ext.append(1 / valor_ext if valor_ext != 0 else np.nan)
981
+ elif escala == "(x)²":
982
+ valores_transformados_ext.append(valor_ext ** 2)
983
+ elif escala == "exp(x)":
984
+ valores_transformados_ext.append(np.exp(valor_ext))
985
+ else:
986
+ valores_transformados_ext.append(valor_ext)
987
+
988
+ df_previsao_ext = pd.DataFrame([valores_transformados_ext], columns=tab_infos_carregada.iloc[1:, 0])
989
+ X_ext = sm.add_constant(df_previsao_ext, has_constant='add')
990
+ X_ext = X_ext.reindex(columns=colunas_modelo, fill_value=0)
991
+
992
+ if X_ext.isnull().values.any():
993
+ continue
994
+
995
+ previsao_transformada_ext = modelo.predict(X_ext).iloc[0]
996
+
997
+ if escala_dependente == "ln(x)":
998
+ previsao_final_ext = np.exp(previsao_transformada_ext)
999
+ elif escala_dependente == "1/(x)":
1000
+ previsao_final_ext = 1 / previsao_transformada_ext
1001
+ elif escala_dependente == "(x)²":
1002
+ previsao_final_ext = np.sqrt(previsao_transformada_ext)
1003
+ elif escala_dependente == "exp(x)":
1004
+ previsao_final_ext = np.log(previsao_transformada_ext)
1005
+ else:
1006
+ previsao_final_ext = previsao_transformada_ext
1007
+
1008
+ previsoes_extrapoladas.append((df_previsao_ext, previsao_final_ext))
1009
+
1010
+ # Determinar a fundamentação da extrapolação
1011
+ if fora_dos_criterios:
1012
+ fundamentacao = "Fundamentação - Extrapolação (Item 4 (a) tab 9.2.1 NBR 14.653-2): Fora dos critérios"
1013
+ elif contagem_extrapolacoes == 1:
1014
+ fundamentacao = "Fundamentação - Extrapolação (Item 4 (a) tab 9.2.1 NBR 14.653-2): Grau II"
1015
+ elif contagem_extrapolacoes > 1:
1016
+ fundamentacao = "Fundamentação - Extrapolação (Item 4 (a) tab 9.2.1 NBR 14.653-2): Grau I"
1017
+ else:
1018
+ fundamentacao = ""
1019
+
1020
+ # Retornar as informações
1021
+ resultado_texto = (
1022
+ f"Valor estimado central: {locale.currency(previsao_final, grouping=True)}\n"
1023
+ "------------------------------------\n"
1024
+ f"Limite inferior do campo de arbítrio (- 15% do Valor estimado central): {locale.currency(limite_inferior_arbitrio, grouping=True)}\n"
1025
+ f"Limite superior do campo de arbítrio (+ 15% do Valor estimado central): {locale.currency(limite_superior_arbitrio, grouping=True)}\n"
1026
+ "------------------------------------\n"
1027
+ f"Limite inferior do Intervalo de Confiança de 80%: {locale.currency(limite_inferior_ic, grouping=True)}\n"
1028
+ f"Limite superior do Intervalo de Confiança de 80%: {locale.currency(limite_superior_ic, grouping=True)}\n"
1029
+ "------------------------------------\n"
1030
+ f"{extrapolacao_info.strip()}\n"
1031
+ f"{fundamentacao}\n"
1032
+ )
1033
+
1034
+
1035
+ resultado_df = df_previsao
1036
+ resultado_df_ext = pd.DataFrame()
1037
+ resultado_texto_ext = ""
1038
+
1039
+ if previsoes_extrapoladas:
1040
+ for df_ext, previsao_ext in previsoes_extrapoladas:
1041
+ resultado_df_ext = df_ext
1042
+ resultado_texto_ext = (
1043
+ f"Valor estimado central (na fronteira amostral): {locale.currency(previsao_ext, grouping=True)}\n"
1044
+ "------------------------------------\n"
1045
+ )
1046
+
1047
+ # Cálculo da variação percentual
1048
+ variacao_percentual = abs((previsao_final - previsao_ext) / previsao_final) * 100
1049
+
1050
+ # Determinar a fundamentação com base na variação percentual
1051
+ if variacao_percentual > 20:
1052
+ fundamentacao_ext = "Fundamentação - Extrapolação (Item 4 (b) tab 9.2.1 NBR 14.653-2): Fora dos critérios"
1053
+ elif variacao_percentual > 15:
1054
+ fundamentacao_ext = "Fundamentação - Extrapolação (Item 4 (b) tab 9.2.1 NBR 14.653-2): Grau I"
1055
+ else:
1056
+ fundamentacao_ext = "Fundamentação - Extrapolação (Item 4 (b) tab 9.2.1 NBR 14.653-2): Grau II"
1057
+
1058
+ resultado_texto_ext += f"{fundamentacao_ext}\n"
1059
+
1060
+ return resultado_df, resultado_texto, resultado_df_ext, resultado_texto_ext
1061
+
1062
+ except Exception as e:
1063
+ return pd.DataFrame(), "Erro ao realizar a previsão: {str(e)}", pd.DataFrame(), ""
1064
+
1065
+
1066
+ #--------------------------------------------INTERFACE-------------------------------------------#
1067
+
1068
+ def rl_tab():
1069
+ # Criação da aba
1070
+ with gr.Tab("Regressão Linear"):
1071
+ planilha_input = gr.File(label="Carregar Planilha", file_types=[".xls", ".xlsx"], elem_classes=["small-file-upload"])
1072
+
1073
+ with gr.Group():
1074
+
1075
+ #---------ESTADOS DE ARMAZENAMENTO-------------#
1076
+
1077
+ # Estado para armazenamentos
1078
+ cabeçalhos_state = gr.State([])
1079
+ dados_state = gr.State(pd.DataFrame())
1080
+ escalas_state = gr.State({})
1081
+ erro_padronizado_state = gr.State([])
1082
+ # Estados para armazenar os gráficos Plotly gerados
1083
+ grafico_residuos_state = gr.State(None)
1084
+ grafico_histograma_state = gr.State(None)
1085
+ grafico_ajustados_state = gr.State(None)
1086
+ matriz_corr_state = gr.State(None)
1087
+ # Estado para armazenar o modelo gerado
1088
+ modelo_state = gr.State(None)
1089
+
1090
+ #---------PLANILHA DE ENTRADA-------------#
1091
+
1092
+ # Checkbox para controlar a visibilidade da planilha carregada
1093
+ mostrar_planilha = gr.Checkbox(label="MOSTRAR PLANILHA CARREGADA e GRÁFICOS PARA ANÁLISE EXPLORATÓRIA (Os gráficos de dispersão e boxplot são atualizados com a retirada de dados)", value=False)
1094
+ tabela_planilha = gr.Dataframe(visible=False, max_height=250, elem_classes=["small span"]) # Oculto por padrão
1095
+
1096
+ #---------GRÁFICOS DE DISPERSÃO-------------#
1097
+
1098
+ # Gráficos de dispersão
1099
+ with gr.Row(equal_height=True):
1100
+ coluna_y_dispersao = gr.Dropdown(label="Eixo Y (Dispersão)", choices=[], interactive=True, visible=False, scale=3)
1101
+ transformacao_y = gr.Dropdown(
1102
+ label="Transformação para Eixo Y",
1103
+ choices=["Nenhuma", "1/x", "ln(x)", "x²", "exp(x)"],
1104
+ value="Nenhuma",
1105
+ interactive=True,
1106
+ visible=False,
1107
+ scale=2
1108
+ )
1109
+ coluna_x_dispersao = gr.Dropdown(label="Eixo X (Dispersão)", choices=[], interactive=True, visible=False, scale=3)
1110
+ transformacao_x = gr.Dropdown(
1111
+ label="Transformação para Eixo X",
1112
+ choices=["Nenhuma", "1/x", "ln(x)", "x²", "exp(x)"],
1113
+ value="Nenhuma",
1114
+ interactive=True,
1115
+ visible=False,
1116
+ scale=2
1117
+ )
1118
+ # Adicionando os gráficos de dispersão e boxplot lado a lado com o mesmo botão
1119
+ botao_dispersao_boxplot = gr.Button("Gerar Gráficos de Dispersão e Boxplot", visible=False)
1120
+ with gr.Row():
1121
+ grafico_dispersao_saida = gr.Plot(label="Gráfico de Dispersão", visible=False, scale=3)
1122
+ grafico_boxplot_saida = gr.Plot(label="Gráfico Boxplot", visible=False, scale=1)
1123
+
1124
+ #---------ESCOLHA DAS VARIÁVEIS-------------#
1125
+
1126
+ # Checkbox para controlar a visibilidade dos dropdowns
1127
+ mostrar_dropdowns = gr.Checkbox(label="VARIÁVEIS E ESCALAS (Variável dependente e variáveis independentes)", value=False, elem_classes="checkbox-yellow")
1128
+ # Dropdown multi-select para cabeçalhos
1129
+ # Título do conjunto
1130
+ with gr.Group():
1131
+ var_ind = gr.Markdown("Selecione as variáveis desejadas no dropdown da escala para a transformação", visible=False) # Adiciona um título ao grupo de dropdowns
1132
+ with gr.Row():
1133
+ colunas_x = gr.Dropdown(label="(Direta: y ou x)", multiselect=True, choices=[], value=[], interactive=True, visible=False)
1134
+ colunas_ln_x = gr.Dropdown(label="Logarítmica: ln(y) ou ln(x)", multiselect=True, choices=[], interactive=True, visible=False)
1135
+ colunas_exp_x = gr.Dropdown(label="Exponencial: exp(y) ou exp(x)", multiselect=True, choices=[], interactive=True, visible=False)
1136
+ colunas_inv_x = gr.Dropdown(label="Inversa: 1/(y) ou 1/(x)", multiselect=True, choices=[], interactive=True, visible=False)
1137
+ colunas_quad_x = gr.Dropdown(label="Quadrática: (x)² ou (y²) ", multiselect=True, choices=[], interactive=True, visible=False)
1138
+ # Escolha da variável dependente
1139
+ var_dep = gr.Dropdown(label="Variável Dependente", multiselect=False, choices=[], interactive=True, visible=False)
1140
+
1141
+ #---------DATAFRAMES-------------#
1142
+
1143
+ with gr.Row(equal_height=True):
1144
+ # Botão para gerar DataFrames
1145
+ botao_gerar_df = gr.Button("Gerar Planilhas", scale=1)
1146
+ # Checkbox para controlar visibilidade dos DataFrames gerados
1147
+ mostrar_dataframes = gr.Checkbox(label="MOSTRAR PLANILHAS (Escalas e limites, Variáveis transformadas e Outliers)", value=False, scale=3)
1148
+ # DataFrames para visualização
1149
+ tabela_cabecalhos = gr.Dataframe(label="Planilha com Cabeçalhos, Escalas, Máximo, Mínimo e Média das variáveis utilizadas", max_height=200, visible=False, elem_classes=["small span"])
1150
+ tabela_original = gr.Dataframe(label="Planilha original com Variáveis Escolhidas", max_height=250, visible=False, elem_classes=["small span"])
1151
+ tabela_escalada = gr.Dataframe(label="Planilha com Variáveis Transformadas", max_height=250, visible=False, interactive=True, headers=None, elem_classes=["small span"])
1152
+ #matriz_correl = gr.Dataframe(label="Matriz de correlações", max_height=250, visible=False, interactive=True, headers=None, elem_classes=["small span"])
1153
+ df_out = gr.Dataframe(label="Outliers", max_height=150, visible=False, interactive=True, headers=None, elem_classes=["small span"])
1154
+
1155
+ #---------MODELO-------------#
1156
+
1157
+ with gr.Row(equal_height=True):
1158
+ # Adicionando botão para executar a regressão
1159
+ botao_regressao = gr.Button("Gerar Modelo", scale=1)
1160
+ # Checkbox para visualizar os resultados
1161
+ mostrar_resultados = gr.Checkbox(label="REGRESSÃO LINEAR (Resultados gerais e por variável, Resíduos > 2 e Pontos Influenciantes, Valores calculados x valores observados)", value=False, scale=3)
1162
+ # Resultados gerais e por variáveis
1163
+ with gr.Row():
1164
+ resultado_geral = gr.Textbox(label="Resultados Gerais", lines=25, interactive=False, visible=False, scale=1)
1165
+ resultado_coef = gr.Dataframe(label="Resultados por Variável", interactive=False, visible=False, scale=1, elem_classes=["small span"])
1166
+ # Resíduos (dataframe e listagem)
1167
+ residuos = gr.Dataframe(label="Resíduos padronizados > 2", interactive=False, max_height=250, visible=False, scale=1, elem_classes=["small span"])
1168
+ with gr.Row():
1169
+ # Resíduos > 2
1170
+ residuos_list = gr.Textbox(label="Listagem resíduos padronizados > 2", lines=2, interactive=False, visible=False, scale=2)
1171
+ # Pontos influenciantes
1172
+ pontos_inf = gr.Textbox(label="Listagem dos Pontos Influenciantes", lines=2, interactive=False, visible=False, scale=1)
1173
+ # Entrada dinâmica
1174
+ entrada_dinamica = gr.Textbox(label="Retirar dados", lines=2, placeholder="Copie e cole os dados da caixa de texto ao lado ou escolha o dado a ser retirado",
1175
+ interactive=True, visible=False, scale=2)
1176
+
1177
+ # Adicionando a visualização para df_calc_obs
1178
+ calc_obs = gr.Dataframe(label="Calculados x Observados", max_height=250, visible=False, interactive=True, headers=None, elem_classes=["small span"])
1179
+ calc_obs_trans = gr.Dataframe(label="Calculados Transformados", max_height=250, visible=False, interactive=True, elem_classes=["small span"])
1180
+
1181
+ #---------GRÁFICOS DO MODELO-------------#
1182
+
1183
+ with gr.Row(equal_height=True):
1184
+ # Adicionar botão para gerar gráficos
1185
+ botao_graficos = gr.Button("Gerar Gráficos", scale=1)
1186
+ # Checkbox para controlar a visibilidade da seção de gráficos do modelo
1187
+ mostrar_graficos = gr.Checkbox(label="GRÁFICOS DO MODELO (Resíduos padronizados, histograma e valores ajustados vs observados, Matriz de Correlações)", value=False, scale=3)
1188
+ # Escolha a escala da variável dependente para o gráfico Ajustados x Observado
1189
+ escala_graf_ao = gr.Dropdown(label="Escolha a escala da variável dependente para o gráfico Valores Ajustados x Observado", choices=["Transformada", "Direta"])
1190
+
1191
+ # Adicionar rádio para selecionar o gráfico
1192
+ grafico_selecao = gr.Radio(
1193
+ choices=["Resíduos Padronizados", "Histograma", "Valores Ajustados vs Observados", "Matriz de Correlações"],
1194
+ label="Selecione o Gráfico",
1195
+ interactive=True,
1196
+ visible=False
1197
+ )
1198
+
1199
+ # Adicionar saída para o gráfico selecionado
1200
+ grafico_saida = gr.Plot(label="Gráfico Selecionado", visible=False)
1201
+
1202
+ #---------EXPORTAR PARA O EXCEL-------------#
1203
+
1204
+ with gr.Row(equal_height=True):
1205
+ botao_exportar_excel = gr.Button("Exportar Planilha")
1206
+ arquivo_excel = gr.File(label="Baixar Excel", interactive=False, visible=False)
1207
+
1208
+ #---------SALVAR MODELO-------------#
1209
+
1210
+ with gr.Row(equal_height=True):
1211
+ # Adicionar campo de entrada para o nome do arquivo
1212
+ nome_arquivo_modelo = gr.Textbox(
1213
+ label="Nome do Arquivo do Modelo",
1214
+ placeholder="Digite o nome do modelo e clique no botão ao lado para salvar",
1215
+ interactive=True,
1216
+ scale=3
1217
+ )
1218
+ # Adicionar botão "SALVAR MODELO" e output para indicar o sucesso/erro
1219
+ botao_salvar_modelo = gr.Button("Salvar Modelo", scale=1)
1220
+ saida_salvar_modelo = gr.Textbox(
1221
+ label="Status do Salvamento do Modelo",
1222
+ interactive=False,
1223
+ visible=False,
1224
+ lines=2
1225
+ )
1226
+
1227
+ #---------CARREGAR MODELO-------------#
1228
+
1229
+ with gr.Row(equal_height=True):
1230
+ # Entrada para carregar o modelo
1231
+ modelo_input = gr.File(label="Carregar Modelo", file_types=[".avse"], elem_classes=["small-file-upload"])
1232
+ # Botão para carregar o modelo
1233
+ botao_carregar_modelo = gr.Button("Visualizar Modelo")
1234
+ # Checkbox abaixo do botão "Visualizar Modelo"
1235
+ mostrar_modelo_checkbox = gr.Checkbox(
1236
+ label="MOSTRAR DETALHES DO MODELO",
1237
+ value=False,
1238
+ elem_classes=["checkbox-yellow"]
1239
+ )
1240
+ # Mensagem de status para aparecer logo abaixo do modelo_input
1241
+ status_carregamento = gr.Textbox(
1242
+ label="Status do Carregamento do Modelo",
1243
+ interactive=False,
1244
+ visible=False, # Certifique-se de que está visível
1245
+ lines=1,
1246
+ elem_classes=["small span"]
1247
+ )
1248
+
1249
+ # TextBox para exibir os resultados gerais
1250
+ resultado_geral_carregado = gr.Textbox(
1251
+ label="Resultados Gerais (Carregados)",
1252
+ interactive=False,
1253
+ visible=False,
1254
+ lines=25, # Ajuste o número de linhas conforme necessário
1255
+ elem_classes=["small span"]
1256
+ )
1257
+
1258
+ # DataFrames para exibição
1259
+ tabela_planilha_carregada = gr.Dataframe(label="Dados Originais", visible=False, max_height=250, elem_classes=["small span"])
1260
+ tabela_original_carregada = gr.Dataframe(label="Dados Modelo", visible=False, max_height=250, elem_classes=["small span"])
1261
+ tabela_outliers_carregada = gr.Dataframe(label="Outliers", visible=False, max_height=250, elem_classes=["small span"])
1262
+ tabela_resultados_vars_carregada = gr.Dataframe(label="Resultados Variáveis", visible=False, max_height=250, elem_classes=["small span"])
1263
+ tabela_calc_obs_carregada = gr.Dataframe(label="Calculados x Observados", visible=False, max_height=250, elem_classes=["small span"])
1264
+ tab_infos_carregada = gr.Dataframe(label="Variáveis, escalas, limites e avaliando", interactive=True, visible=False, elem_classes=["small span"])
1265
+
1266
+ #---------AVALIAÇÃO-------------#
1267
+
1268
+ botao_previsao = gr.Button("Realizar Previsão")
1269
+ tabela_previsao = gr.Dataframe(label="Valores Transformados para Previsão", visible=True, max_height=250)
1270
+ previsao_saida = gr.Textbox(label="Resultado da Previsão", lines=8, interactive=False, visible=True)
1271
+
1272
+ # Adicionar DataFrames para exibir os resultados das previsões ajustadas
1273
+ tabela_previsao_ajustada = gr.Dataframe(label="Valores Transformados para Previsão Ajustada", visible=True, max_height=250)
1274
+ previsao_ajustada_saida = gr.Textbox(label="Resultado da Previsão Ajustada", lines=8, interactive=False, visible=True)
1275
+
1276
+ # 1. CONTROLE DE VISIBILIDADE
1277
+
1278
+ # 1.1. Mostrar ou ocultar a planilha carregada e os gráficos
1279
+ mostrar_planilha.change(
1280
+ lambda visible, dados: [gr.update(visible=visible, value=dados)] * 8,
1281
+ inputs=[mostrar_planilha, dados_state],
1282
+ outputs=[
1283
+ tabela_planilha, coluna_y_dispersao, transformacao_y, coluna_x_dispersao,
1284
+ transformacao_x, botao_dispersao_boxplot,
1285
+ grafico_dispersao_saida, grafico_boxplot_saida
1286
+ ]
1287
+ )
1288
+
1289
+ # 1.2. Mostrar ou ocultar os dropdowns para escolha de variáveis transformadas
1290
+ mostrar_dropdowns.change(
1291
+ lambda visible: [gr.update(visible=visible)] * 7,
1292
+ inputs=[mostrar_dropdowns],
1293
+ outputs=[var_ind, colunas_x, colunas_ln_x, colunas_exp_x, colunas_inv_x, colunas_quad_x, var_dep]
1294
+ )
1295
+
1296
+ # 1.3. Mostrar ou ocultar os DataFrames gerados (cabeçalhos, escalas, correlação, etc.)
1297
+ mostrar_dataframes.change(
1298
+ lambda visible: [gr.update(visible=visible)] * 3,
1299
+ inputs=[mostrar_dataframes],
1300
+ outputs=[tabela_cabecalhos, tabela_escalada, df_out] #matriz_correl,
1301
+ )
1302
+
1303
+ # 1.4. Mostrar ou ocultar os resultados da regressão (resultados gerais, resíduos, etc.)
1304
+ mostrar_resultados.change(
1305
+ lambda visible: [gr.update(visible=visible)] * 7,
1306
+ inputs=[mostrar_resultados],
1307
+ outputs=[resultado_geral, resultado_coef, residuos, residuos_list, pontos_inf, entrada_dinamica, calc_obs]
1308
+ )
1309
+
1310
+ # 1.5. Mostrar ou ocultar a seção de gráficos e componentes associados
1311
+ mostrar_graficos.change(
1312
+ lambda visible: [gr.update(visible=visible)] * 2,
1313
+ inputs=[mostrar_graficos],
1314
+ outputs=[grafico_selecao, grafico_saida]
1315
+ )
1316
+
1317
+ # 1.6. Mostrar ou ocultar os detalhes do modelo carregado
1318
+ mostrar_modelo_checkbox.change(
1319
+ lambda visible: [gr.update(visible=visible)] * 8,
1320
+ inputs=[mostrar_modelo_checkbox],
1321
+ outputs=[
1322
+ resultado_geral_carregado, tabela_planilha_carregada, tabela_original_carregada,
1323
+ tabela_outliers_carregada, tabela_resultados_vars_carregada, tabela_calc_obs_carregada,
1324
+ tab_infos_carregada, status_carregamento
1325
+ ]
1326
+ )
1327
+
1328
+ # 2. CARREGAMENTO DE PLANILHA E ATUALIZAÇÃO DE DADOS
1329
+
1330
+ # 2.1. Carregar a planilha e extrair cabeçalhos e dados
1331
+ planilha_input.change(
1332
+ lambda file: carregar_planilha(file),
1333
+ inputs=[planilha_input],
1334
+ outputs=[cabeçalhos_state, dados_state]
1335
+ )
1336
+
1337
+ # 2.2. Atualizar as opções de dropdown para o gráfico de dispersão ao carregar uma planilha
1338
+ cabeçalhos_state.change(
1339
+ lambda cabecalhos: [gr.update(choices=cabecalhos, value=None)] * 2,
1340
+ inputs=[cabeçalhos_state],
1341
+ outputs=[coluna_y_dispersao, coluna_x_dispersao]
1342
+ )
1343
+
1344
+ # 2.3. Atualizar os dropdowns para transformações e seleção de variáveis dependentes/independentes
1345
+ cabeçalhos_state.change(
1346
+ atualizar_dropdowns,
1347
+ inputs=[cabeçalhos_state],
1348
+ outputs=[colunas_x, colunas_ln_x, colunas_exp_x, colunas_inv_x, colunas_quad_x, var_dep]
1349
+ )
1350
+
1351
+ # 2.4. Atualizar o gráfico exibido com base na seleção do usuário
1352
+ grafico_selecao.change(
1353
+ lambda escala, selecao, fig1, fig2, fig3, fig4: (
1354
+ fig1 if selecao == "Resíduos Padronizados" else
1355
+ (fig2 if selecao == "Histograma" else
1356
+ (fig3 if selecao == "Valores Ajustados vs Observados" else fig4))
1357
+ ),
1358
+ inputs=[escala_graf_ao, grafico_selecao, grafico_residuos_state, grafico_histograma_state, grafico_ajustados_state, matriz_corr_state],
1359
+ outputs=[grafico_saida]
1360
+ )
1361
+
1362
+ # 3. BOTÕES
1363
+ # 3.1. Botão para conectar à função de Gerar os gráficos de dispersão e boxplot (GERAR DISPERSÃO E BOXPLOT)
1364
+ botao_dispersao_boxplot.click(
1365
+ lambda df, y_coluna, transformacao_y, x_coluna, transformacao_x, dados_out: (
1366
+ grafico_dispersao(df, y_coluna, transformacao_y, x_coluna, transformacao_x, dados_out),
1367
+ grafico_boxplot(df, y_coluna, transformacao_y, x_coluna, transformacao_x, dados_out)
1368
+ ),
1369
+ inputs=[dados_state, coluna_y_dispersao, transformacao_y, coluna_x_dispersao, transformacao_x, entrada_dinamica],
1370
+ outputs=[grafico_dispersao_saida, grafico_boxplot_saida]
1371
+ )
1372
+
1373
+ # 3.2. Botão para conectar à função de Gerar os dataframes cabeçalhos, escalas e estatísticas básicas (máximo, mínimo, média) e
1374
+ # transformados, escalados e correlação (GERAR PLANILHAS)
1375
+ botao_gerar_df.click(
1376
+ criar_dataframe_cabecalhos,
1377
+ inputs=[cabeçalhos_state, colunas_x, colunas_ln_x, colunas_exp_x, colunas_inv_x, colunas_quad_x, dados_state, entrada_dinamica, var_dep],
1378
+ outputs=[tabela_cabecalhos, escalas_state]
1379
+ )
1380
+
1381
+ botao_gerar_df.click(
1382
+ criar_dataframes,
1383
+ inputs=[dados_state, colunas_x, colunas_ln_x, colunas_exp_x, colunas_inv_x, colunas_quad_x, entrada_dinamica, var_dep],
1384
+ outputs=[tabela_original, tabela_escalada, df_out] # , matriz_correl
1385
+ )
1386
+
1387
+ # 3.3. Botão para conectar à função de realizar regressão linear com base nas variáveis selecionadas (GERAR MODELO)
1388
+ botao_regressao.click(
1389
+ realizar_regressao,
1390
+ inputs=[var_dep, tabela_escalada, tabela_original, escalas_state],
1391
+ outputs=[resultado_geral, resultado_coef, residuos, residuos_list, pontos_inf, calc_obs, calc_obs_trans,
1392
+ erro_padronizado_state, modelo_state]
1393
+ )
1394
+
1395
+ # 3.4. Botão para conectar à função de Gerar gráficos do modelo (GERAR GRÁFICOS - resíduos, histograma, ajustados vs observados)
1396
+ botao_graficos.click(
1397
+ graficos, # Função que gera os gráficos Plotly
1398
+ inputs=[escala_graf_ao, calc_obs, calc_obs_trans, erro_padronizado_state, var_dep],
1399
+ outputs=[grafico_residuos_state, grafico_histograma_state, grafico_ajustados_state, matriz_corr_state]
1400
+ )
1401
+
1402
+ # 3.5. Botão para conectar à função de exportar para o excel (EXPORTAR PLANILHA)
1403
+ botao_exportar_excel.click(
1404
+ lambda df_planilha, df_infos, df_original, df_escalado, df_out, resultados_gerais, resultados_vars, df_calc_obs, df_calc_obs_trans: (
1405
+ "resultado.xlsx",
1406
+ exportar_para_excel(
1407
+ "resultado.xlsx", df_planilha, df_infos, df_original, df_escalado, df_out,
1408
+ resultados_gerais, resultados_vars, df_calc_obs, df_calc_obs_trans
1409
+ )
1410
+ )[0],
1411
+ inputs=[
1412
+ dados_state, tabela_cabecalhos, tabela_original, tabela_escalada, df_out,
1413
+ resultado_geral, resultado_coef, calc_obs, calc_obs_trans
1414
+ ],
1415
+ outputs=[arquivo_excel]
1416
+ )
1417
+ # Atualizar visibilidade do status após clique no botão
1418
+ botao_exportar_excel.click(
1419
+ lambda *args: gr.update(visible=True),
1420
+ inputs=[],
1421
+ outputs=[arquivo_excel]
1422
+ )
1423
+
1424
+ # 3.6. Botão para conectar à função de salvar o modelo (SALVAR MODELO)
1425
+ botao_salvar_modelo.click(
1426
+ lambda nome_arquivo, modelo, resultados_gerais, df_planilha, df_infos, df_original, df_outliers, resultados_vars, df_calc_obs: (
1427
+ exportar_modelo_completo_avse(
1428
+ nome_arquivo, modelo, resultados_gerais, df_planilha, df_infos, df_original,
1429
+ df_outliers, resultados_vars, df_calc_obs
1430
+ )
1431
+ ),
1432
+ inputs=[
1433
+ nome_arquivo_modelo, modelo_state, resultado_geral, dados_state, tabela_cabecalhos,
1434
+ tabela_original, df_out, resultado_coef, calc_obs
1435
+ ],
1436
+ outputs=[saida_salvar_modelo]
1437
+ )
1438
+ # Atualizar visibilidade do status após clique no botão
1439
+ botao_salvar_modelo.click(
1440
+ lambda: gr.update(visible=True),
1441
+ inputs=[],
1442
+ outputs=[saida_salvar_modelo]
1443
+ )
1444
+
1445
+ # 3.7. Botão para conectar à função de carregamento do modelo (VISUALIZAR MODELO)
1446
+ botao_carregar_modelo.click(
1447
+ carregar_modelo,
1448
+ inputs=[modelo_input],
1449
+ outputs=[
1450
+ status_carregamento, # Mensagem de status aparece logo abaixo da caixa de upload
1451
+ modelo_state, # Estado para armazenar o modelo carregado
1452
+ resultado_geral_carregado,
1453
+ tabela_planilha_carregada, tabela_original_carregada, tabela_outliers_carregada,
1454
+ tabela_resultados_vars_carregada, tabela_calc_obs_carregada, tab_infos_carregada
1455
+ ]
1456
+ )
1457
+
1458
+ # 3.8. Botão para conectar à função de realizar previsões (REALIZAR PREVISÃO)
1459
+ botao_previsao.click(
1460
+ realizar_previsoes,
1461
+ inputs=[modelo_state, tab_infos_carregada],
1462
+ outputs=[tabela_previsao, previsao_saida, tabela_previsao_ajustada, previsao_ajustada_saida]
1463
+ )
1464
+
1465
+ return locals()
1466
+
1467
+
1468
+ ### Pontos de máximo e mínimo
1469
+ ### Colunas com Coordenadas (ter a possibilidade de dizer se há ou não coordenadas para criar uma dispesão espacial)
1470
+ ### Endereços
1471
+ ### Colunas que possuem valor 0, não podem ser utilizados na ln ou inversa (mensagem de erro?)
1472
+ ### Micronumerosidade
1473
+ ### Média, mediana e moda
1474
+ ### Problema no ordenamento dos dataframes
1475
+ ### Implementar avaliação em massa
1476
+ ### Implementar relatório em word
1477
+ ### Conectar a elaboração do modelo com o carregamento
modules/shared_state.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ state = {}
2
+
3
+
modules/utils.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Fri Nov 22 11:36:45 2024
4
+
5
+ @author: fernando.schwartzer
6
+ """
7
+ import pandas as pd
8
+ from .shared_state import state
9
+
10
+ def create_new_dataframe_with_index_and_value_unit(file, sheet_name, selected_columns, add_index, calculate_unit_value, col_value, col_area):
11
+ if file is None or not sheet_name or not selected_columns:
12
+ return pd.DataFrame({"Erro": ["Carregue um arquivo, selecione uma aba e colunas."]})
13
+
14
+ # Carrega o DataFrame da aba especificada
15
+ df = pd.read_excel(file.name, sheet_name=sheet_name)
16
+
17
+ # Seleciona apenas as colunas especificadas
18
+ new_df = df[selected_columns]
19
+
20
+ # Adiciona um índice se necessário
21
+ if add_index:
22
+ new_df.insert(0, "Índice", range(1, len(new_df) + 1))
23
+
24
+ # Renomeia e formata a coluna de valor total
25
+ if col_value:
26
+ new_df.rename(columns={col_value: "Valor Total"}, inplace=True)
27
+ new_df["Valor Total"] = new_df["Valor Total"].round(2)
28
+ cols = new_df.columns.tolist()
29
+ cols.insert(1, cols.pop(cols.index("Valor Total")))
30
+ new_df = new_df[cols]
31
+
32
+ # Calcula o valor unitário se necessário
33
+ if calculate_unit_value and col_value and col_area:
34
+ try:
35
+ new_df["Valor Unitário"] = (new_df["Valor Total"] / new_df[col_area]).round(2)
36
+ cols = new_df.columns.tolist()
37
+ cols.insert(2, cols.pop(cols.index("Valor Unitário")))
38
+ new_df = new_df[cols]
39
+ except ZeroDivisionError:
40
+ new_df["Valor Unitário"] = "Erro: Divisão por zero"
41
+ except KeyError:
42
+ new_df["Valor Unitário"] = "Erro: Coluna inválida"
43
+
44
+ # Salva o novo DataFrame no estado compartilhado
45
+ new_df.columns = new_df.columns.map(str)
46
+ state['new_df'] = new_df
47
+ return new_df