# importando bibliotecas necessárias
import pandas as pd
import numpy as np
import gradio as gr
from gradio import components
from gradio import Interface
import xlsxwriter
def renderizar_dataframe(df):
try:
# Renderize o DataFrame como uma tabela HTML com rolagem horizontal
df_html = df.to_html(classes='table table-striped',
table_id='planilha',
escape=False) # Não escapar caracteres especiais
# Use uma div com estilo CSS para permitir a rolagem horizontal
tabela_com_rolagem = f'
{df_html}
'
# Retorna a tabela com rolagem como HTML
return tabela_com_rolagem
except Exception as e:
return f"Erro ao processar o DataFrame: {str(e)}"
# Função de avaliação do imóvel
def avaliacao_imovel(planilha, num_linhas_desejadas=10):
# Lendo a aba 'avaliando' da planilha
df_avaliando = pd.read_excel(planilha.name, 'avaliando')
# Lendo a aba 'dados' da planilha, limitando o número de linhas
df_dados = pd.read_excel(planilha.name, 'dados').iloc[:int(num_linhas_desejadas)]
#-----------------#
# fator de atratividade local (fal)
df_transp = df_dados.copy()
df_transp = df_transp[['Atratividade local']]
df_transp['fal'] = round(df_avaliando['Atratividade local'][0] / df_transp['Atratividade local'], 2)
df_transp = df_transp[['fal']]
#-----------------#
# fator de correção da área construída (fac)
df_area_const = df_dados.copy()
df_area_const = df_area_const[['Área Construída']]
df_area_const['razao'] = (df_area_const['Área Construída'] / df_avaliando['Área Construída'][0])
df_area_const['dif'] = abs(df_area_const['Área Construída'] - df_avaliando['Área Construída'][0])
# 30% da área do terreno do avaliando
x_ac = 0.3 * df_avaliando['Área Construída'][0]
# coeficiente n conforme a diferença entre a área do avaliando e dos dados
df_area_const['n'] = df_area_const['dif'].apply(lambda dif: 0.250 if dif <= x_ac else 0.125)
df_area_const['fac'] = round((df_area_const['razao']) ** (df_area_const['n']), 2)
df_area_const = df_area_const[['fac']]
#-----------------#
# fator de correção da área do terreno (fat)
df_area_terreno = df_dados.copy()
df_area_terreno = df_area_terreno[['Área Terreno']]
df_area_terreno['razao'] = (df_area_terreno['Área Terreno'] / df_avaliando['Área Terreno'][0])
df_area_terreno['dif'] = abs(df_area_terreno['Área Terreno'] - df_avaliando['Área Terreno'][0])
# 30% da área do terreno do avaliando
x_at = 0.3 * df_avaliando['Área Terreno'][0]
# coeficiente n conforme a diferença entre a área do avaliando e dos dados
df_area_terreno['n'] = df_area_terreno['dif'].apply(lambda dif: 0.250 if dif <= x_at else 0.125)
df_area_terreno['fat'] = round((df_area_terreno['razao']) ** (df_area_terreno['n']), 2)
df_area_terreno = df_area_terreno[['fat']]
#-----------------#
# fator idade aparente e conservação (fic)
# dicionário padrão construtivo
dict_ic = {
'id<5_novo': 1.00,
'id<5_bom': 0.95,
'id<5_reparos simples': 0.80,
'id<5_reparos importantes': 0.45,
'id entre 6 e 10_novo': 0.95,
'id entre 6 e 10_bom': 0.90,
'id entre 6 e 10_reparos simples': 0.75,
'id entre 6 e 10_reparos importantes': 0.40,
'id entre 11 e 30_novo': 0.85,
'id entre 11 e 30_bom': 0.80,
'id entre 11 e 30_reparos simples': 0.65,
'id entre 11 e 30_reparos importantes': 0.35,
'id entre 31 e 50_novo': 0.55,
'id entre 31 e 50_bom': 0.50,
'id entre 31 e 50_reparos simples': 0.45,
'id entre 31 e 50_reparos importantes': 0.25,
'id>50_novo': 0.30,
'id>50_bom': 0.20,
'id>50_reparos simples': 0.15,
'id>50_reparos importantes': 0.10
}
# cria dataframe apenas com as colunas necessárias a partir do dataframe dos dados
df_idade_cons = df_dados.copy()
df_idade_cons = df_idade_cons[['Idade aparente e conservação']]
# cria dataframe apenas com as colunas necessárias a partir do dataframe do avaliando
df_idade_cons_aval = df_avaliando.copy()
df_idade_cons_aval = df_idade_cons_aval[['Idade aparente e conservação']]
# Função para mapear os valores de idade aparente e conservação para cod_id_cons usando o dicionário
def mapear_cod_id_cons(id_cons):
return dict_ic.get(id_cons, 0)
# Aplicando a função para criar a coluna cod_topo em df_dados e df_avaliando
df_idade_cons['coef_ic'] = df_idade_cons['Idade aparente e conservação'].apply(mapear_cod_id_cons)
df_idade_cons_aval['coef_ic'] = df_idade_cons_aval['Idade aparente e conservação'].apply(mapear_cod_id_cons)
df_idade_cons['fic'] = round(df_idade_cons_aval['coef_ic'][0] / df_idade_cons['coef_ic'],2)
df_idade_cons = df_idade_cons[['fic']]
#-----------------#
# fator padrão construtivo (fpd)
# dicionário padrão construtivo
dict_pad = {
'baixo_residencial': 1.00,
'médio/baixo_residencial': 1.15,
'médio_residencial': 1.30,
'médio/alto_residencial': 1.45,
'alto_residencial': 1.65,
'baixo_comercial': 1.00,
'médio/baixo_comercial': 1.08,
'médio_comercial': 1.15,
'médio/alto_comercial': 1.25,
'alto_comercial': 1.40
}
# cria dataframe apenas com as colunas necessárias a partir do dataframe dos dados
df_padrao = df_dados.copy()
df_padrao = df_padrao[['Padrão construtivo']]
# cria dataframe apenas com as colunas necessárias a partir do dataframe do avaliando
df_padrao_aval = df_avaliando.copy()
df_padrao_aval = df_padrao_aval[['Padrão construtivo']]
# Função para mapear os valores de padrão construtivo para cod_pad usando o dicionário
def mapear_cod_pad(padrao):
return dict_pad.get(padrao, 0) # 0 como valor padrão caso a topografia não esteja no dicionário
# Aplicando a função para criar a coluna cod_topo em df_dados e df_avaliando
df_padrao['coef_pd'] = df_padrao['Padrão construtivo'].apply(mapear_cod_pad)
df_padrao_aval['coef_pd'] = df_padrao_aval['Padrão construtivo'].apply(mapear_cod_pad)
df_padrao['fpd'] = round(df_padrao_aval['coef_pd'][0]/df_padrao['coef_pd'],2)
df_padrao = df_padrao[['fpd']]
#-----------------#
# fator vagas de estacionamento (fvg)
df_vaga = df_dados[['Vagas']].copy()
df_vaga_aval = df_avaliando[['Vagas']].copy()
# Calcular a diferença entre as colunas 'Vagas' nos dois DataFrames
df_vaga['dif'] = df_vaga['Vagas'] - df_vaga_aval['Vagas'][0]
# Definir a função para o cálculo da coluna 'fvg'
def calculate_fcg(dif, vagas):
if dif == 0:
return 1
else:
return 1 - 0.067 * dif
# Aplicar a função para calcular a coluna 'fcg'
df_vaga['fvg'] = round(df_vaga.apply(lambda row: calculate_fcg(row['dif'], row['Vagas']), axis=1), 2)
df_vaga = df_vaga[['fvg']]
#-----------------#
# fator extra (à critério do avaliador) (fex)
df_exc = df_dados.copy()
df_exc = df_exc[['Coeficiente extra']]
df_exc['fex'] = round(df_avaliando['Coeficiente extra'][0] / df_exc['Coeficiente extra'], 2)
df_exc = df_exc[['fex']]
#-----------------#
# concatemando o dataframe principal com as dataframes dos fatores
result = pd.concat([df_dados, df_transp, df_area_const, df_area_terreno, df_idade_cons, df_padrao, df_vaga, df_exc], axis=1)
result['Valor_desc'] = round(result['Valor']*(result['fof']), 2)
result['Vunit'] = round((result['Valor_desc']/result['Área Construída']), 2)
result = result[['Atratividade local', 'Área Construída', 'Área Terreno',
'Idade aparente e conservação', 'Padrão construtivo', 'Vagas',
'Coeficiente extra', 'Valor', 'fof','Valor_desc', 'Vunit','fal', 'fac', 'fat', 'fic',
'fpd', 'fvg', 'fex']]
result['Vunit_hom'] = round(result['Vunit'] * result['fal'] * \
result['fac'] * \
result['fat'] * \
result['fic'] * \
result['fpd'] * \
result['fvg'] * \
result['fex'], 2)
# RESULTADOS ESTATÍSTICOS INICIAIS
num = len(result)
media = round(result['Vunit_hom'].mean(), 2)
valor_hom_máximo = round(result['Vunit_hom'].max(), 2)
valor_hom_mínimo = round(result['Vunit_hom'].min(), 2)
limite_superior = round(media * 1.3 ,2)
limite_inferior = round(media * 0.7 ,2)
desvio_padrao = round(result['Vunit_hom'].std(), 2)
coef_variacao = round((desvio_padrao / media)*100, 2)
# CRITÉRIO DE CHAUVENET
dict_vc = {
2: 1.15,3: 1.38,4: 1.54,5: 1.65,6: 1.73,7: 1.80,8: 1.85,9: 1.91,10: 1.96,11: 1.99,
12: 2.03,13: 2.06,14: 2.10,15: 2.13,16: 2.16,17: 2.18,18: 2.20,19: 2.21,20: 2.24,
21: 2.26,22: 2.28,23: 2.30,24: 2.31,25: 2.33,26: 2.35,27: 2.36,28: 2.37,29: 2.38,
30: 2.93
}
vc = dict_vc[num]
vc
result['z-score'] = abs((result['Vunit_hom'] - media) / desvio_padrao)
result['Status'] = np.where(result['z-score'] > vc, 'rejeitado', 'aceito')
# para gerar uma tabela na interface
result_render = renderizar_dataframe(result)
# DADOS REMOVIDOS
outliers = result[result['Status'] == 'rejeitado']
# REMOÇÃO DE OUTLIERS PELO CRITÉRIO DE CHAUVENET
result = result[result['Status'] != 'rejeitado']
# RESULTADOS ESTATÍSTICOS FINAIS
num = len(result)
dados_outliers = len(outliers)
media = round(result['Vunit_hom'].mean(), 2)
valor_hom_máximo = round(result['Vunit_hom'].max(), 2)
valor_hom_mínimo = round(result['Vunit_hom'].min(), 2)
limite_superior = round(media * 1.3 ,2)
limite_inferior = round(media * 0.7 ,2)
desvio_padrao = round(result['Vunit_hom'].std(), 2)
coef_variacao = round((desvio_padrao / media)*100, 2)
# Crie uma string formatada com os RESULTADOS ESTATÍSTICOS FINAIS
resultados_formatados = f"""
Número de dados: {num} dados
Valor Crítico (Chauvenet): {vc}
Outliers: {dados_outliers} dado(s)
Média saneada: {media} R$/m²
Valor máximo: {valor_hom_máximo} R$/m²
Valor mínimo: {valor_hom_mínimo} R$/m²
Lim superior (Média*1,3): {limite_superior} R$/m²
Lim inferior (Média*0,7): {limite_inferior} R$/m²
Desvio padrão: {desvio_padrao} R$/m²
Coeficiente variação: {coef_variacao} %
"""
# INTEREVALO DE CONFIANÇA DE 80%
# importando a tabela de t de student
df_t = pd.read_excel('TABELAS.xlsx','t')
# número de dados
n = result.shape[0]-1
# "t" de student
gl = df_t[df_t['gl (n-1)'] == n]
tc = gl.iloc[0, 3]
# limites infeiror e superior do IC de 80% e amplitude
li_IC = round(media - tc * ((desvio_padrao/(num-1)**0.5)), 2)
ls_IC = round(media + tc * ((desvio_padrao/(num-1)**0.5)), 2)
A = round(ls_IC - li_IC, 2)
A_perc = round((A / media)*100, 2)
def calcular_grau(a):
if a <= 30:
return "Grau III"
elif a <= 40:
return "Grau II"
elif a <= 50:
return "Grau I"
else:
return "Fora dos critérios"
precisao = calcular_grau(A_perc)
# Crie uma string formatada com o INTEREVALO DE CONFIANÇA DE 80%
intervalo_confiança = f"""
t student: {tc}
Média saneada: {media} R$/m²
limite infeiror IC_80%: {li_IC} R$/m²
limite superior IC_80%: {ls_IC} R$/m²
Aplitude: {A} R$/m²
Aplitude percentual: {A_perc} %
Grau de Precisão: {precisao}
"""
# VALOR CALCULADO A PARTIR DOS VALORES HOMOGENEIZADOS UTILIZANDO O CRITÉRIO DE CLASSAS D0 ABUNAHMAN
# dividindo a amplitude em 3 classes
C = round((A / 3), 2)
# calculando os intervalos das 3 classes
C1 = round(result[(result['Vunit_hom'] >= li_IC) & (result['Vunit_hom'] <= li_IC + C)]['Vunit_hom'].count(), 2)
C2 = round(result[(result['Vunit_hom'] >= li_IC + C) & (result['Vunit_hom'] <= ls_IC - C)]['Vunit_hom'].count(), 2)
C3 = round(result[(result['Vunit_hom'] >= ls_IC - C) & (result['Vunit_hom'] <= ls_IC)]['Vunit_hom'].count(), 2)
# crinado listas com os valores encontrados nos intervalos
list_C1 = result[(result['Vunit_hom'] >= li_IC) & (result['Vunit_hom'] <= li_IC + C)]['Vunit_hom'].tolist()
list_C2 = result[(result['Vunit_hom'] >= li_IC + C) & (result['Vunit_hom'] <= ls_IC - C)]['Vunit_hom'].tolist()
list_C3 = result[(result['Vunit_hom'] >= ls_IC - C) & (result['Vunit_hom'] <= ls_IC)]['Vunit_hom'].tolist()
pC1 = round(sum(C1 * elemento for elemento in list_C1), 2)
pC2 = round(sum(C2 * elemento for elemento in list_C2), 2)
pC3 = round(sum(C3 * elemento for elemento in list_C3), 2)
divisor = ((C1 * C1) if C1 != 0 else 0) +((C2 * C2) if C2 != 0 else 0) + ((C3 * C3) if C3 != 0 else 0)
media_pond = round((pC1 + pC2 + pC3) / divisor, 2)
# VALORES CALCULADOS
Valor_imóvel = round(media * df_avaliando['Área Construída'], 2).item()
Valor_imóvel_2 = round((media_pond) * df_avaliando['Área Construída'], 2).item()
# Crie uma string formatada com os VALORES CALCULADOS
valores_finais = f"""
Área avaliando: {df_avaliando['Área Construída'].item()} m²
Valor (média simples): R$ {Valor_imóvel}
Vu (média simples): R$ {media}
Valor (critério classes): R$ {Valor_imóvel_2}
Vu (critério classes): R$ {media_pond}
"""
#-----------------#
# OUTPUTS
# Crie um objeto ExcelWriter para escrever no arquivo Excel
output_file = 'relatório.xlsx'
with pd.ExcelWriter(output_file, engine='xlsxwriter') as writer:
# Salve o DataFrame 'avaliando' na planilha 'relatório'
df_avaliando.to_excel(writer, sheet_name='avaliando', index=False)
#-----------------#
# Salve o DataFrame 'result' na planilha 'relatório'
df_dados.to_excel(writer, sheet_name='dados', index=False)
#-----------------#
# Salve o DataFrame 'dado_hom' na planilha 'relatório'
result.to_excel(writer, sheet_name='dados_hom', index=False)
#-----------------#
# Salve o DataFrame 'outliers' na planilha 'relatório'
outliers.to_excel(writer, sheet_name='outliers', index=False)
#-----------------#
# Crie um novo DataFrame com os resultados estatísticos
result_estatisticos = pd.DataFrame({
'Número de dados': [num],
'Média': [media],
'Valor homogeneizado máximo': [valor_hom_máximo],
'Valor homogeneizado mínimo': [valor_hom_mínimo],
'Limite superior (Média x 1,3)': [limite_superior],
'Limite inferior (Média x 0,7)': [limite_inferior],
'Desvio padrão': [desvio_padrao],
'Coeficiente_variacao (%)': [coef_variacao]
})
# Transponha o DataFrame
result_estatisticos = result_estatisticos.T.reset_index()
# Defina os nomes das colunas do novo DataFrame
result_estatisticos.columns = ['Nome da Coluna', 'Valor']
result_estatisticos.to_excel(writer, sheet_name='resultados', index=False)
#-----------------#
# Crie um novo DataFrame com os resultados do IC
result_ic = pd.DataFrame({
'Número de dados': [n],
't student': [tc],
'Limite superior do IC de 80%': [ls_IC],
'Limite inferior do IC de 80%': [li_IC],
'Amplitude': [A],
'Amplitude%':[A_perc],
'Grau de Precisão': [precisao]
})
# Transponha o DataFrame
result_ic = result_ic.T.reset_index()
# Defina os nomes das colunas do novo DataFrame
result_ic.columns = ['Nome da Coluna', 'Valor']
result_ic.to_excel(writer, sheet_name='IC', index=False)
#-----------------#
# Crie um novo DataFrame com os resultados do cálculo das classes de Abunahman
result_classes = pd.DataFrame({
'C = Amplitude / 3': [round(C, 2)],
'li_IC = limite inferior do IC': [round(li_IC, 2)],
'li_IC + C = limite inferior do IC + C': [round(li_IC + C, 2)],
'ls_IC - C = limite superior do IC + C': [round(ls_IC - C, 2)],
'ls_IC = limite superior do IC': [round(ls_IC, 2)],
'C1 = quantidade de dados na classe 1': [C1],
'C2 = quantidade de dados na classe 2': [C2],
'C3 = quantidade de dados na classe 3': [C3],
'list_C1 = listagem de dados na classe 1': [list_C1],
'list_C2 = listagem de dados na classe 2': [list_C2],
'list_C3 = listagem de dados na classe 3': [list_C3],
'Soma da multiplicação dos valor pelos pesos - classe 1': [pC1],
'Soma da multiplicação dos valor pelos pesos - classe 2': [pC2],
'Soma da multiplicação dos valor pelos pesos - classe 3': [pC3],
'Divisor da somas das classes': [divisor],
'Média ponderada': [media_pond]
})
# Transponha o DataFrame
result_classes = result_classes.T.reset_index()
# Defina os nomes das colunas do novo DataFrame
result_classes.columns = ['Nome da Coluna', 'Valor']
result_classes.to_excel(writer, sheet_name='classes', index=False)
#-----------------#
# Crie um novo DataFrame com os resultados do valor do imóvel
result_valores = pd.DataFrame({
'Valor total critério de ABUNAHMAN' : [Valor_imóvel_2],
'Valor total média simples' : [Valor_imóvel]
})
# Transponha o DataFrame
result_valores = result_valores.T.reset_index()
# Defina os nomes das colunas do novo DataFrame
result_valores.columns = ['Nome da Coluna', 'Valor']
result_valores.to_excel(writer, sheet_name='valor', index=False)
#-----------------#
# Salve o DataFrame 'result' em uma planilha
result.to_excel('relatório.xlsx', index=False)
#-----------------#
# Retorna tanto a planilha quanto os resultados formatados
return 'relatório.xlsx', result_render, resultados_formatados, intervalo_confiança, valores_finais
# Interface do Gradio com input como arquivo XLS ou XLSX
interface = gr.Interface(
fn=avaliacao_imovel,
inputs=[
gr.components.File(label="Upload planilha", type="file"),
gr.inputs.Number(label="Número de linhas desejadas", default=10),
],
outputs=[
gr.components.File(label="Download planilha"),
gr.outputs.HTML(label="Resultado Renderizado"),
gr.components.Textbox(label="Resultados estatísticos"),
gr.components.Textbox(label="Intervalo de confiança de 80%"),
gr.components.Textbox(label="Valores Calculados"),
],
live=True,
capture_session=True,
theme=gr.themes.Soft(),
title="avaliaFACTOR",
description="Aplicativo MCDDM com tratamento por fatores / Faça o upload de uma planilha XLS ou XLSX com os dados / Para um exemplo de estrutura de planilha, você pode baixar aqui.")
# Executar o aplicativo Gradio
if __name__ == "__main__":
interface.launch(debug=True)