Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +84 -152
src/streamlit_app.py
CHANGED
|
@@ -1,159 +1,91 @@
|
|
| 1 |
-
#!/usr/bin/env python
|
| 2 |
-
# coding: utf-8
|
| 3 |
-
|
| 4 |
-
# =====================================================
|
| 5 |
-
# Dashboard - Testes de Hipóteses com AmesHousing
|
| 6 |
-
# =====================================================
|
| 7 |
-
|
| 8 |
import streamlit as st
|
| 9 |
import pandas as pd
|
| 10 |
import matplotlib.pyplot as plt
|
| 11 |
import seaborn as sns
|
| 12 |
import plotly.express as px
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
# -----------------------
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
)
|
| 28 |
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
#
|
| 35 |
-
#
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
# -----------------------
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
fig, ax = plt.subplots(figsize=(8,5))
|
| 79 |
-
sns.histplot(casa_data['SalePrice'], kde=True, ax=ax)
|
| 80 |
-
ax.set_title("Distribuição do Preço de Venda")
|
| 81 |
-
st.pyplot(fig)
|
| 82 |
-
|
| 83 |
-
# Boxplots
|
| 84 |
-
st.markdown("### Boxplots das Variáveis Selecionadas")
|
| 85 |
-
variavel = st.selectbox("Escolha a variável categórica para comparar preços:",
|
| 86 |
-
["Neighborhood","Garage_Type","Fireplaces"])
|
| 87 |
-
|
| 88 |
-
fig2, ax2 = plt.subplots(figsize=(12,6))
|
| 89 |
-
sns.boxplot(x=variavel, y="SalePrice", data=casa_data, ax=ax2)
|
| 90 |
-
plt.xticks(rotation=90)
|
| 91 |
-
ax2.set_title(f"Preço de Venda por {variavel}")
|
| 92 |
-
st.pyplot(fig2)
|
| 93 |
-
|
| 94 |
-
# Scatter interativo (média de preço por bairro)
|
| 95 |
-
st.markdown("### Preço Médio de Venda por Bairro")
|
| 96 |
-
bairro_grouped = casa_data.groupby('Neighborhood').agg(
|
| 97 |
-
count=('SalePrice','size'),
|
| 98 |
-
mean_price=('SalePrice','mean')
|
| 99 |
-
).reset_index()
|
| 100 |
-
|
| 101 |
-
bairro_filtered = bairro_grouped[bairro_grouped['count'] >= 5]
|
| 102 |
-
fig3 = px.scatter(
|
| 103 |
-
bairro_filtered,
|
| 104 |
-
x='mean_price',
|
| 105 |
-
y='Neighborhood',
|
| 106 |
-
size='count',
|
| 107 |
-
color='Neighborhood',
|
| 108 |
-
title='Preço Médio de Venda vs Bairro (Ames, Iowa)',
|
| 109 |
-
labels={'mean_price': 'Preço Médio de Venda', 'Neighborhood':'Bairro'},
|
| 110 |
-
opacity=0.8
|
| 111 |
-
)
|
| 112 |
-
st.plotly_chart(fig3, use_container_width=True)
|
| 113 |
-
|
| 114 |
-
# -------------------------------------------------
|
| 115 |
-
# ANOVA
|
| 116 |
-
# -------------------------------------------------
|
| 117 |
-
st.markdown("### ANOVA para Neighborhood, Garage_Type e Fireplaces")
|
| 118 |
-
alpha = st.sidebar.slider("Nível de significância (α) - ANOVA AmesHousing",
|
| 119 |
-
0.01,0.10,0.05,0.01,key="alpha_ames")
|
| 120 |
-
|
| 121 |
-
modelos = {
|
| 122 |
-
"Neighborhood": ols('SalePrice ~ C(Neighborhood)', data=casa_data).fit(),
|
| 123 |
-
"Garage_Type": ols('SalePrice ~ C(Garage_Type)', data=casa_data).fit(),
|
| 124 |
-
"Fireplaces": ols('SalePrice ~ C(Fireplaces)', data=casa_data).fit()
|
| 125 |
-
}
|
| 126 |
-
|
| 127 |
-
for nome, modelo in modelos.items():
|
| 128 |
-
st.markdown(f"#### ANOVA - {nome}")
|
| 129 |
-
anova = sm.stats.anova_lm(modelo, typ=2)
|
| 130 |
-
st.dataframe(anova)
|
| 131 |
-
|
| 132 |
-
# -------------------------------------------------
|
| 133 |
-
# Validação dos Pressupostos
|
| 134 |
-
# -------------------------------------------------
|
| 135 |
-
st.markdown("### Validação dos Pressupostos da ANOVA")
|
| 136 |
-
|
| 137 |
-
st.markdown("#### Teste de Normalidade (Shapiro-Wilk)")
|
| 138 |
-
for nome, modelo in modelos.items():
|
| 139 |
-
residuos = modelo.resid
|
| 140 |
-
stat, p = shapiro(residuos.dropna())
|
| 141 |
-
st.write(f"{nome}: estatística={stat:.3f}, p={p:.3f} "
|
| 142 |
-
+ ("resíduos normais" if p >= alpha else "violação de normalidade"))
|
| 143 |
-
|
| 144 |
-
st.markdown("#### Teste de Homocedasticidade (Levene)")
|
| 145 |
-
for nome in ["Neighborhood","Garage_Type","Fireplaces"]:
|
| 146 |
-
grupos = [grupo["SalePrice"].dropna() for _, grupo in casa_data.groupby(nome)]
|
| 147 |
-
stat, p = levene(*grupos)
|
| 148 |
-
st.write(f"{nome}: estatística={stat:.3f}, p={p:.3f} "
|
| 149 |
-
+ ("variâncias iguais" if p >= alpha else "variâncias diferentes"))
|
| 150 |
-
|
| 151 |
-
# -------------------------------------------------
|
| 152 |
-
# Kruskal-Wallis
|
| 153 |
-
# -------------------------------------------------
|
| 154 |
-
st.markdown("### Teste não-paramétrico (Kruskal-Wallis)")
|
| 155 |
-
for nome in ["Neighborhood","Garage_Type","Fireplaces"]:
|
| 156 |
-
grupos = [grupo["SalePrice"].dropna() for _, grupo in casa_data.groupby(nome)]
|
| 157 |
-
stat, p = kruskal(*grupos)
|
| 158 |
-
st.write(f"{nome}: estatística={stat:.3f}, p={p:.3f} "
|
| 159 |
-
+ ("diferenças significativas" if p < alpha else "sem diferença significativa"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
import pandas as pd
|
| 3 |
import matplotlib.pyplot as plt
|
| 4 |
import seaborn as sns
|
| 5 |
import plotly.express as px
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
from sklearn.model_selection import train_test_split
|
| 8 |
+
|
| 9 |
+
st.set_page_config(page_title="Dashboard Ames Housing", layout="wide")
|
| 10 |
+
|
| 11 |
+
# -----------------------
|
| 12 |
+
# Carregando o CSV de forma robusta
|
| 13 |
+
# -----------------------
|
| 14 |
+
HERE = Path(__file__).resolve().parent
|
| 15 |
+
CANDIDATES = [
|
| 16 |
+
HERE.parent / "Dados" / "AmesHousing.csv",
|
| 17 |
+
HERE / "Dados" / "AmesHousing.csv",
|
| 18 |
+
Path("Dados") / "AmesHousing.csv",
|
| 19 |
+
]
|
| 20 |
+
csv_path = next((p for p in CANDIDATES if p.exists()), None)
|
| 21 |
+
if csv_path is None:
|
| 22 |
+
st.error("Arquivo 'Dados/AmesHousing.csv' não encontrado. Confirme o nome e a pasta.")
|
| 23 |
+
st.stop()
|
| 24 |
+
|
| 25 |
+
casa_data = pd.read_csv(csv_path)
|
| 26 |
+
casa_data.columns = casa_data.columns.str.strip().str.replace(" ", "_")
|
| 27 |
+
|
| 28 |
+
# -----------------------
|
| 29 |
+
# Sidebar: proporção treino/teste
|
| 30 |
+
# -----------------------
|
| 31 |
+
st.sidebar.header("Configurações")
|
| 32 |
+
prop_treino = st.sidebar.slider("Proporção de treino", 0.1, 0.9, 0.7)
|
| 33 |
+
|
| 34 |
+
train, test = train_test_split(casa_data, train_size=prop_treino, random_state=42)
|
| 35 |
+
|
| 36 |
+
# O usuário escolhe qual conjunto visualizar
|
| 37 |
+
dataset_opcao = st.sidebar.radio(
|
| 38 |
+
"Conjunto de dados a visualizar:",
|
| 39 |
+
["Treino", "Teste"],
|
| 40 |
+
index=0
|
| 41 |
)
|
| 42 |
|
| 43 |
+
if dataset_opcao == "Treino":
|
| 44 |
+
dados = train.copy()
|
| 45 |
+
else:
|
| 46 |
+
dados = test.copy()
|
| 47 |
+
|
| 48 |
+
# -----------------------
|
| 49 |
+
# Gráfico 1: Distribuição do Preço de Venda
|
| 50 |
+
# -----------------------
|
| 51 |
+
st.subheader("Distribuição do Preço de Venda")
|
| 52 |
+
fig, ax = plt.subplots()
|
| 53 |
+
sns.histplot(dados['SalePrice'], kde=True, ax=ax)
|
| 54 |
+
st.pyplot(fig)
|
| 55 |
+
|
| 56 |
+
# -----------------------
|
| 57 |
+
# Gráfico 2: Boxplot de Preço de Venda por Bairro
|
| 58 |
+
# -----------------------
|
| 59 |
+
st.subheader("Boxplot de Preço de Venda por Bairro")
|
| 60 |
+
fig2, ax2 = plt.subplots(figsize=(12, 6))
|
| 61 |
+
sns.boxplot(x="Neighborhood", y="SalePrice", data=dados, ax=ax2)
|
| 62 |
+
plt.xticks(rotation=90)
|
| 63 |
+
st.pyplot(fig2)
|
| 64 |
+
|
| 65 |
+
# -----------------------
|
| 66 |
+
# Gráfico 3: Dispersão Área vs Preço
|
| 67 |
+
# -----------------------
|
| 68 |
+
st.subheader("Dispersão: Área vs Preço de Venda")
|
| 69 |
+
fig3 = px.scatter(dados, x="Gr_Liv_Area", y="SalePrice",
|
| 70 |
+
color="Overall_Qual", hover_data=["Year_Built"])
|
| 71 |
+
st.plotly_chart(fig3, use_container_width=True)
|
| 72 |
+
|
| 73 |
+
# -----------------------
|
| 74 |
+
# Gráfico 4: Heatmap de Correlação
|
| 75 |
+
# -----------------------
|
| 76 |
+
st.subheader("Matriz de Correlação (variáveis numéricas)")
|
| 77 |
+
corr = dados.corr(numeric_only=True)
|
| 78 |
+
fig4, ax4 = plt.subplots(figsize=(10, 8))
|
| 79 |
+
sns.heatmap(corr, cmap="coolwarm", center=0, ax=ax4)
|
| 80 |
+
st.pyplot(fig4)
|
| 81 |
+
|
| 82 |
+
# -----------------------
|
| 83 |
+
# Gráfico 5: Preço médio por estilo de casa
|
| 84 |
+
# -----------------------
|
| 85 |
+
st.subheader("Preço médio por estilo de casa")
|
| 86 |
+
mean_price = dados.groupby("House_Style")["SalePrice"].mean().sort_values(ascending=False)
|
| 87 |
+
fig5, ax5 = plt.subplots()
|
| 88 |
+
mean_price.plot(kind="bar", ax=ax5)
|
| 89 |
+
st.pyplot(fig5)
|
| 90 |
+
|
| 91 |
+
st.success(f"Visualizando {dataset_opcao} ({dados.shape[0]} registros, proporção treino = {prop_treino:.2f})")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|