Agentes de resumo estatístico
Análise de distribuições, correlações e detecção de valores atípicos em relatórios gerados por agentes.
Agentes de resumo estatístico é uma aula grátis de AI Agents no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Agents, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Agents inclui 4 aulas no total.
Por que os resumos estatísticos são importantes
Dados brutos raramente são úteis por si só. Um agente de análise de dados se torna realmente valioso quando consegue calcular automaticamente resumos estatísticos e traduzir números em conclusões em linguagem simples.
Esta lição aborda as principais operações estatísticas: describe, correlação, detecção de valores atípicos, identificação de distribuições e geração automatizada de conclusões.
df.describe(): o ponto de partida
df.describe() calcula contagem, mean, std, min, quartis e max para todas as colunas numéricas em uma única chamada. Essa é a primeira etapa padrão de qualquer análise exploratória de dados.
import pandas as pd
df = pd.read_csv('sales_data.csv')
# Basic numeric summary
print(df.describe())
# Also describe categorical columns
print(df.describe(include='object'))
# Custom percentiles
print(df.describe(percentiles=[0.05, 0.25, 0.5, 0.75, 0.95]))
# Convert to clean dict for agent use
def get_numeric_summary(df):
desc = df.describe().round(2)
return {
col: desc[col].to_dict()
for col in desc.columns
}Matriz de correlação
A matriz de correlação mostra relações lineares par a par entre todas as colunas numéricas. Os valores variam de -1 (fortemente negativa) a +1 (fortemente positiva). Valores próximos de 0 indicam ausência de relação linear.
import pandas as pd
import numpy as np
def compute_correlation_matrix(df):
numeric = df.select_dtypes(include='number')
corr = numeric.corr().round(3)
return corr.to_dict()
def find_strong_correlations(df, threshold=0.7):
numeric = df.select_dtypes(include='number')
corr = numeric.corr()
strong = []
cols = corr.columns
for i in range(len(cols)):
for j in range(i + 1, len(cols)): # upper triangle only
val = corr.iloc[i, j]
if abs(val) >= threshold:
strong.append({
'col_a': cols[i],
'col_b': cols[j],
'correlation': round(val, 3),
'direction': 'positive' if val > 0 else 'negative'
})
return sorted(strong, key=lambda x: abs(x['correlation']), reverse=True)Detecção de valores atípicos: método IQR
O método do intervalo interquartil (IQR) identifica valores atípicos como valores mais de 1.5x acima do IQR em relação a Q3 ou abaixo de Q1. Ele é resistente a valores extremos — ao contrário da pontuação z, funciona bem mesmo quando há valores atípicos nos dados.
import pandas as pd
def detect_outliers_iqr(df, columns=None, multiplier=1.5):
numeric = df.select_dtypes(include='number')
if columns:
numeric = numeric[columns]
outlier_report = {}
for col in numeric.columns:
q1 = numeric[col].quantile(0.25)
q3 = numeric[col].quantile(0.75)
iqr = q3 - q1
lower = q1 - multiplier * iqr
upper = q3 + multiplier * iqr
outliers = numeric[(numeric[col] < lower) | (numeric[col] > upper)][col]
outlier_report[col] = {
'q1': round(q1, 3),
'q3': round(q3, 3),
'iqr': round(iqr, 3),
'lower_bound': round(lower, 3),
'upper_bound': round(upper, 3),
'outlier_count': len(outliers),
'outlier_pct': round(len(outliers) / len(df) * 100, 1),
'outlier_values': outliers.tolist()[:10] # first 10
}
return outlier_reportIdentificação do tipo de distribuição
Identificar o tipo de distribuição (normal, assimétrica, bimodal ou uniforme) ajuda o agente a escolher os testes estatísticos adequados e a descrever os dados com precisão.
Use assimetria e kurtosis como heurísticas rápidas antes de executar testes formais.
import pandas as pd
from scipy import stats
def identify_distribution(series):
'''Classify distribution type using skewness, kurtosis, and normality test.'''
clean = series.dropna()
if len(clean) < 8:
return {'type': 'insufficient_data'}
skewness = clean.skew()
kurtosis = clean.kurtosis()
# Shapiro-Wilk normality test (reliable up to ~5000 samples)
sample = clean.sample(min(500, len(clean)), random_state=42)
_, p_value = stats.shapiro(sample)
distribution = 'normal' if p_value > 0.05 else 'non-normal'
if abs(skewness) < 0.5 and p_value > 0.05:
dist_type = 'normal'
elif skewness > 1.0:
dist_type = 'right-skewed (long right tail)'
elif skewness < -1.0:
dist_type = 'left-skewed (long left tail)'
elif abs(skewness) < 0.5 and kurtosis < -1:
dist_type = 'uniform-like'
else:
dist_type = 'approximately normal'
return {
'type': dist_type,
'skewness': round(skewness, 3),
'kurtosis': round(kurtosis, 3),
'normality_pvalue': round(p_value, 4),
'is_normal': p_value > 0.05
}Testes de normalidade
Há vários testes formais de normalidade disponíveis. Shapiro-Wilk é melhor para amostras pequenas; D'Agostino-Pearson, para conjuntos de dados maiores. O limiar do valor-p costuma ser 0,05 — rejeite a normalidade se p < 0,05.
from scipy import stats
import numpy as np
def test_normality(series, alpha=0.05):
clean = series.dropna().values
n = len(clean)
results = {}
# Shapiro-Wilk (best for n < 5000)
if n <= 5000:
stat, p = stats.shapiro(clean)
results['shapiro_wilk'] = {
'statistic': round(stat, 4),
'p_value': round(p, 4),
'is_normal': p > alpha
}
# D'Agostino-Pearson (n >= 20)
if n >= 20:
stat, p = stats.normaltest(clean)
results['dagostino_pearson'] = {
'statistic': round(stat, 4),
'p_value': round(p, 4),
'is_normal': p > alpha
}
# Kolmogorov-Smirnov
mean, std = np.mean(clean), np.std(clean)
stat, p = stats.kstest(clean, 'norm', args=(mean, std))
results['kolmogorov_smirnov'] = {
'statistic': round(stat, 4),
'p_value': round(p, 4),
'is_normal': p > alpha
}
return resultsPerfil estatístico completo
Combine todas as análises estatísticas em uma única função full_profile() que retorna um resumo estatístico abrangente para cada coluna numérica de uma tabela de dados.
def full_statistical_profile(df):
numeric = df.select_dtypes(include='number')
profiles = {}
for col in numeric.columns:
series = numeric[col].dropna()
profile = {
'count': len(series),
'null_count': df[col].isnull().sum(),
'mean': round(series.mean(), 4),
'median': round(series.median(), 4),
'std': round(series.std(), 4),
'min': round(series.min(), 4),
'max': round(series.max(), 4),
'range': round(series.max() - series.min(), 4),
'q1': round(series.quantile(0.25), 4),
'q3': round(series.quantile(0.75), 4)
}
profile['distribution'] = identify_distribution(series)
outliers = detect_outliers_iqr(df, columns=[col])
profile['outliers'] = outliers.get(col, {})
profiles[col] = profile
return {
'profiles': profiles,
'correlations': find_strong_correlations(df),
'shape': {'rows': len(df), 'columns': len(df.columns)}
}Geração automatizada de conclusões
Passe o perfil estatístico ao LLM e peça que gere conclusões em linguagem simples. O modelo identifica padrões, sinaliza anomalias e destaca descobertas relevantes para usuários de negócio.
import json
INSIGHT_PROMPT = '''You are a data analyst. Generate 3-5 key insights from this statistical summary.
Dataset: {dataset_name}
Statistical profile:
{profile_json}
For each insight:
- Be specific (use actual numbers)
- Focus on business relevance
- Flag any data quality concerns (high null counts, extreme outliers)
- Note unexpected patterns
Format as bullet points.'''
def generate_insights(df, dataset_name='dataset'):
profile = full_statistical_profile(df)
profile_text = json.dumps(profile, indent=2, default=str)[:3000]
return llm_call(INSIGHT_PROMPT.format(
dataset_name=dataset_name,
profile_json=profile_text
))
# Example output:
# - Revenue column has 3.2% outliers; max value ($48,500) is 12x the median ($3,900)
# - Customer age follows a right-skewed distribution (skewness: 1.4) with most users under 35
# - Strong positive correlation (r=0.87) between session_count and lifetime_valueDetecção de tendências em séries temporais
Para dados de séries temporais, detecte a tendência geral (crescente, decrescente ou estável) usando regressão linear. Isso permite que os agentes afirmem "A receita está crescendo a US$ 2.400 por mês."
import numpy as np
from scipy import stats
def detect_trend(values):
if len(values) < 3:
return {'trend': 'insufficient_data'}
x = np.arange(len(values))
y = np.array(values, dtype=float)
slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)
if p_value > 0.05:
trend = 'flat (no significant trend)'
elif slope > 0:
trend = 'increasing'
else:
trend = 'decreasing'
return {
'trend': trend,
'slope_per_period': round(slope, 4),
'r_squared': round(r_value ** 2, 4),
'p_value': round(p_value, 4),
'significant': p_value < 0.05
}
# Example: monthly revenue trend
monthly_revenue = [10000, 11200, 10800, 12500, 13100, 14200, 15000]
print(detect_trend(monthly_revenue))
# {'trend': 'increasing', 'slope_per_period': 834.2, 'r_squared': 0.95, ...}Estatísticas comparativas
Muitas vezes, a conclusão mais útil é comparar grupos: "O valor médio dos pedidos do Segmento A é 40% maior que o do Segmento B." Use testes t ou Mann-Whitney para comparar grupos.
from scipy import stats
import pandas as pd
def compare_groups(df, group_column, value_column):
groups = df.groupby(group_column)[value_column].apply(list)
group_names = list(groups.index)
comparison = []
for i, g1 in enumerate(group_names):
for j, g2 in enumerate(group_names):
if j <= i:
continue
a, b = groups[g1], groups[g2]
mean_a = pd.Series(a).mean()
mean_b = pd.Series(b).mean()
# Mann-Whitney U (non-parametric, no normality assumption)
stat, p = stats.mannwhitneyu(a, b, alternative='two-sided')
pct_diff = (mean_a - mean_b) / mean_b * 100 if mean_b != 0 else 0
comparison.append({
'group_a': g1, 'group_b': g2,
'mean_a': round(mean_a, 2),
'mean_b': round(mean_b, 2),
'pct_difference': round(pct_diff, 1),
'p_value': round(p, 4),
'significant': p < 0.05
})
return comparisonAnálise de valores ausentes
Antes de calcular qualquer estatística, analise os valores ausentes. Taxas elevadas de valores nulos em uma coluna invalidam as estatísticas calculadas a partir dela. Relate contagens de valores nulos, percentuais e padrões (os valores nulos são aleatórios ou sistemáticos?).
import pandas as pd
import numpy as np
def analyze_missing_values(df):
total_rows = len(df)
missing_report = {}
for col in df.columns:
null_count = df[col].isnull().sum()
if null_count == 0:
continue
null_pct = null_count / total_rows * 100
# Check if nulls correlate with another column (systematic pattern)
pattern = 'random'
if null_pct > 5:
for other_col in df.select_dtypes(include='object').columns:
if other_col == col:
continue
null_rates = df.groupby(other_col)[col].apply(
lambda x: x.isnull().mean()
)
if null_rates.max() - null_rates.min() > 0.3: # 30% difference
pattern = f'correlated_with_{other_col}'
break
missing_report[col] = {
'null_count': int(null_count),
'null_pct': round(null_pct, 1),
'severity': 'high' if null_pct > 20 else 'medium' if null_pct > 5 else 'low',
'pattern': pattern
}
return missing_reportVerificação de conhecimentos
Por que o método IQR é preferível ao da pontuação z para detectar valores atípicos em aplicações de agentes?
Recapitulação: agentes de resumos estatísticos
Os agentes de resumos estatísticos combinam: df.describe() para obter estatísticas básicas, matrizes de correlação para descobrir relações, detecção de valores atípicos pelo IQR (resistente a valores extremos), identificação de distribuições por meio de assimetria e testes de normalidade e detecção de tendências por meio de regressão linear.
Passe o perfil estatístico ao LLM para gerar conclusões automaticamente — traduzindo números em descobertas de negócio em linguagem simples. Estatísticas comparativas (comparações entre grupos com testes de significância) destacam as conclusões mais acionáveis.
Perguntas Frequentes
A aula “Agentes de resumo estatístico” é grátis?
Sim — o texto completo de “Agentes de resumo estatístico” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Agents, atualize para CoddyKit PRO. O curso de AI Agents inclui 4 aulas no total.
O que vou aprender em “Agentes de resumo estatístico”?
Análise de distribuições, correlações e detecção de valores atípicos em relatórios gerados por agentes. Você pratica AI Agents com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar AI Agents?
Nenhuma experiência prévia é necessária. AI Agents no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.
Quanto tempo leva a aula “Agentes de resumo estatístico”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de AI Agents?
Sim. Cada aula de AI Agents inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Padrão de interpretador de código para análise de dados
- Ferramentas de agentes orientadas por Pandas
- Geração automatizada de gráficos e visualizações
- Agentes de resumo estatístico