Atividade3 / src /streamlit_app.py
ricardoadriano's picture
Update src/streamlit_app.py
e79b163 verified
#!/usr/bin/env python
# coding: utf-8
# =====================================================
# Dashboard - Testes de Hipóteses com AmesHousing
# =====================================================
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import numpy as np
from scipy import stats
from scipy.stats import shapiro, levene, kruskal
from statsmodels.formula.api import ols
import statsmodels.api as sm
# -----------------------------------------------------
# Configuração da Página
# -----------------------------------------------------
st.set_page_config(
page_title="Dashboard - Testes de Hipóteses com AmesHousing",
layout="wide",
initial_sidebar_state="expanded"
)
st.markdown("<h1 style='text-align:center;color:#003366;'>Simulador de Testes de Hipótese</h1>", unsafe_allow_html=True)
st.markdown("<h3 style='text-align:center;color:#003366;'>Análise do Dataset AmesHousing</h3>", unsafe_allow_html=True)
st.markdown("---")
# -----------------------------------------------------
# Abas do Dashboard
# -----------------------------------------------------
tabs = st.tabs(["Simulações Teóricas", "Análise AmesHousing"])
# -----------------------------------------------------
# Aba 1: Simulações Teóricas
# -----------------------------------------------------
with tabs[0]:
st.subheader("Teste de Hipótese para cálculo do valor das casas")
st.sidebar.markdown("### Parâmetros do Teste (Proporção)")
p_pop = st.sidebar.slider("Proporção populacional (H0)", 0.0, 1.0, 0.1, 0.01, key="p_pop")
p_sample = st.sidebar.slider("Proporção amostral", 0.0, 1.0, 0.12, 0.01, key="p_sample")
n = st.sidebar.slider("Tamanho da amostra", 100, 10000, 1000, 10, key="n_sample")
alpha_prop = st.sidebar.slider("Nível de significância (α)", 0.01, 0.10, 0.05, 0.01, key="alpha_prop")
se = np.sqrt(p_pop*(1-p_pop)/n)
z = (p_sample - p_pop)/se
p_value = 2*(1 - stats.norm.cdf(abs(z)))
st.write(f"**Z** = {z:.4f}")
st.write(f"**p-valor** = {p_value:.4f}")
if p_value < alpha_prop:
st.write("**Rejeitamos H0**: diferença significativa.")
else:
st.write("**Não rejeitamos H0**: sem diferença significativa.")
# -----------------------------------------------------
# Aba 2: Análise AmesHousing
# -----------------------------------------------------
with tabs[1]:
st.subheader("Análise de Variância - AmesHousing Dataset")
st.markdown("---")
# Leitura do CSV
casa_data = pd.read_csv("../Dados/AmesHousing.csv")
casa_data.columns = casa_data.columns.str.strip().str.replace(" ", "_")
# -----------------------------
# Amostragem
# -----------------------------
n_amostra = st.session_state.get("n_sample", len(casa_data))
if n_amostra < len(casa_data):
dados = casa_data.sample(n=n_amostra, random_state=42)
else:
dados = casa_data.copy()
# -----------------------------
# Filtro interativo no sidebar
# -----------------------------
st.sidebar.markdown("### Filtros AmesHousing")
bairros = st.sidebar.multiselect(
"Selecione bairros",
options=sorted(dados["Neighborhood"].dropna().unique()),
default=None
)
# Aplicar filtro
dados_filtrados = dados.copy()
if bairros:
dados_filtrados = dados_filtrados[dados_filtrados["Neighborhood"].isin(bairros)]
# -------------------------------------------------
# Análise Exploratória
# -------------------------------------------------
st.markdown("### Distribuição do Preço de Venda")
if not dados_filtrados.empty:
fig, ax = plt.subplots(figsize=(8,5))
sns.histplot(dados_filtrados['SalePrice'], kde=True, ax=ax)
ax.set_title("Distribuição do Preço de Venda")
st.pyplot(fig)
else:
st.warning("Nenhum dado disponível com os filtros aplicados.")
# Boxplots
st.markdown("### Boxplots das Variáveis Selecionadas")
variavel = st.selectbox(
"Escolha a variável categórica para comparar preços:",
["Neighborhood","Garage_Type","Fireplaces"]
)
if not dados_filtrados.empty:
if len(dados_filtrados[variavel].dropna().unique()) > 1:
fig2, ax2 = plt.subplots(figsize=(12,6))
sns.boxplot(x=variavel, y="SalePrice", data=dados_filtrados, ax=ax2)
plt.xticks(rotation=90)
ax2.set_title(f"Preço de Venda por {variavel}")
st.pyplot(fig2)
else:
st.warning(f"Não é possível gerar boxplot: apenas uma categoria em {variavel} após os filtros.")
# Scatter interativo (média de preço por bairro)
st.markdown("### Preço Médio de Venda por Bairro")
if not dados_filtrados.empty:
bairro_grouped = dados_filtrados.groupby('Neighborhood').agg(
count=('SalePrice','size'),
mean_price=('SalePrice','mean')
).reset_index()
bairro_filtered = bairro_grouped[bairro_grouped['count'] >= 5]
if not bairro_filtered.empty:
fig3 = px.scatter(
bairro_filtered,
x='mean_price',
y='Neighborhood',
size='count',
color='Neighborhood',
title='Preço Médio de Venda vs Bairro (Ames, Iowa)',
labels={'mean_price': 'Preço Médio de Venda', 'Neighborhood':'Bairro'},
opacity=0.8
)
st.plotly_chart(fig3, use_container_width=True)
else:
st.warning("Não há bairros suficientes após filtros para gerar o gráfico.")
# -------------------------------------------------
# ANOVA
# -------------------------------------------------
st.markdown("### ANOVA para Neighborhood, Garage_Type e Fireplaces")
alpha = st.sidebar.slider(
"Nível de significância (α) - ANOVA AmesHousing",
0.01,0.10,0.05,0.01,
key="alpha_ames"
)
if not dados_filtrados.empty:
for nome in ["Neighborhood", "Garage_Type", "Fireplaces"]:
categorias = dados_filtrados[nome].dropna().unique()
if len(categorias) < 2:
st.warning(f"ANOVA não pôde ser realizada para **{nome}** (menos de 2 grupos após os filtros).")
continue
modelo = ols(f'SalePrice ~ C({nome})', data=dados_filtrados).fit()
st.markdown(f"#### ANOVA - {nome}")
anova = sm.stats.anova_lm(modelo, typ=2)
st.dataframe(anova)
# -------------------------------------------------
# Validação dos Pressupostos
# -------------------------------------------------
st.markdown("### Validação dos Pressupostos da ANOVA")
st.markdown("#### Teste de Normalidade (Shapiro-Wilk)")
for nome in ["Neighborhood","Garage_Type","Fireplaces"]:
categorias = dados_filtrados[nome].dropna().unique()
if len(categorias) < 2:
st.warning(f"Shapiro-Wilk não pôde ser realizado para **{nome}** (menos de 2 grupos após os filtros).")
continue
modelo = ols(f'SalePrice ~ C({nome})', data=dados_filtrados).fit()
residuos = modelo.resid
stat, p = shapiro(residuos.dropna())
st.write(f"{nome}: estatística={stat:.3f}, p={p:.3f} "
+ ("resíduos normais" if p >= alpha else "violação de normalidade"))
st.markdown("#### Teste de Homocedasticidade (Levene)")
for nome in ["Neighborhood","Garage_Type","Fireplaces"]:
grupos = [grupo["SalePrice"].dropna() for _, grupo in dados_filtrados.groupby(nome)]
if len(grupos) < 2:
st.warning(f"Levene não pôde ser realizado para **{nome}** (menos de 2 grupos após os filtros).")
continue
stat, p = levene(*grupos)
st.write(f"{nome}: estatística={stat:.3f}, p={p:.3f} "
+ ("variâncias iguais" if p >= alpha else "variâncias diferentes"))
# -------------------------------------------------
# Kruskal-Wallis
# -------------------------------------------------
st.markdown("### Teste não-paramétrico (Kruskal-Wallis)")
for nome in ["Neighborhood","Garage_Type","Fireplaces"]:
grupos = [grupo["SalePrice"].dropna() for _, grupo in dados_filtrados.groupby(nome)]
if len(grupos) < 2:
st.warning(f"Kruskal-Wallis não pôde ser realizado para **{nome}** (menos de 2 grupos após os filtros).")
continue
stat, p = kruskal(*grupos)
st.write(f"{nome}: estatística={stat:.3f}, p={p:.3f} "
+ ("diferenças significativas" if p < alpha else "sem diferença significativa"))