Data Science é a disciplina que extrai conhecimento e insights de dados — combinando estatística, programação e domínio do problema. Python se tornou a linguagem dominante nessa área por um motivo simples: seu ecossistema de bibliotecas é incomparável. NumPy, pandas, Matplotlib e Seaborn formam a base sobre a qual toda análise de dados em Python é construída. Neste artigo apresentamos esse ecossistema de forma sistemática e prática.
O Ecossistema de Data Science
Dados brutos
│
▼
┌─────────────┐ coleta e limpeza ┌──────────────┐
│ pandas │ ◄──────────────────── │ requests / │
│ (tabelas) │ │ scrapy / sql│
└──────┬──────┘ └──────────────┘
│ arrays numéricos
▼
┌─────────────┐ visualização ┌──────────────┐
│ NumPy │ ────────────────────► │ Matplotlib │
│ (vetores) │ │ Seaborn │
└──────┬──────┘ └──────────────┘
│ modelagem
▼
┌─────────────┐ avaliação ┌──────────────┐
│ scikit-learn│ ────────────────────► │ métricas / │
│ (ML) │ │ relatórios │
└─────────────┘ └──────────────┘
pip install numpy pandas matplotlib seaborn scipy jupyter
NumPy: Computação Numérica
NumPy é a fundação de todo o ecossistema científico Python — arrays multidimensionais com operações vetorizadas, muito mais rápidas que listas Python puras.
import numpy as np
# Criando arrays
a = np.array([1, 2, 3, 4, 5])
b = np.array([10, 20, 30, 40, 50])
print(a.dtype) # int64
print(a.shape) # (5,)
print(a.ndim) # 1
# Operações vetorizadas — sem loop explícito
print(a + b) # [11 22 33 44 55]
print(a * 2) # [ 2 4 6 8 10]
print(a ** 2) # [ 1 4 9 16 25]
print(np.sqrt(a)) # [1. 1.41 1.73 2. 2.24]
# Comparações vetorizadas
print(a > 3) # [False False False True True]
print(a[a > 3]) # [4 5] — indexação booleana
Arrays Multidimensionais
# Matriz 3x4
matriz = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
])
print(matriz.shape) # (3, 4)
print(matriz[1, 2]) # 7 — linha 1, coluna 2
print(matriz[:, 0]) # [1 5 9] — toda a coluna 0
print(matriz[0, :]) # [1 2 3 4] — toda a linha 0
print(matriz[1:, 2:]) # submatriz
# Criando arrays especiais
zeros = np.zeros((3, 4))
uns = np.ones((2, 5))
ident = np.eye(3) # matriz identidade
seq = np.arange(0, 20, 2) # [0 2 4 ... 18]
lin = np.linspace(0, 1, 5) # [0. 0.25 0.5 0.75 1.]
rand = np.random.rand(3, 3) # valores aleatórios 0-1
Álgebra Linear e Estatística
a = np.array([2, 4, 4, 4, 5, 5, 7, 9])
print(f"Média: {np.mean(a):.2f}") # 5.0
print(f"Mediana: {np.median(a):.2f}") # 4.5
print(f"Desvio: {np.std(a):.2f}") # 2.0
print(f"Variância: {np.var(a):.2f}") # 4.0
print(f"Mínimo: {np.min(a)}") # 2
print(f"Máximo: {np.max(a)}") # 9
print(f"Soma: {np.sum(a)}") # 40
print(f"Percentil 75: {np.percentile(a, 75)}") # 5.25
# Produto matricial
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(A @ B) # produto matricial
print(np.dot(A, B))
# Autovalores e autovetores
vals, vecs = np.linalg.eig(A)
print(vals)
# Resolução de sistema linear Ax = b
A = np.array([[2, 1], [1, 3]], dtype=float)
b = np.array([5, 10], dtype=float)
x = np.linalg.solve(A, b)
print(x) # solução do sistema
pandas: Análise de Dados Tabulares
pandas é o Excel do Python — mas infinitamente mais poderoso.
import pandas as pd
# Criando DataFrame
df = pd.DataFrame({
"nome": ["Ana", "Bruno", "Carla", "Diego", "Elena"],
"idade": [23, 35, 28, 42, 31],
"cidade": ["Recife", "SP", "RJ", "SP", "Recife"],
"salario": [4500.0, 8200.0, 6300.0, 12000.0, 5800.0],
"ativo": [True, True, False, True, True]
})
# Informações básicas
print(df.shape) # (5, 5)
print(df.dtypes) # tipos de cada coluna
print(df.describe()) # estatísticas descritivas
print(df.info()) # visão geral + memória usada
print(df.head(3)) # primeiras 3 linhas
print(df.tail(2)) # últimas 2 linhas
Seleção e Filtragem
# Selecionando colunas
print(df["nome"]) # Series
print(df[["nome", "salario"]]) # DataFrame
# loc — por rótulo
print(df.loc[0]) # linha 0
print(df.loc[1:3, ["nome", "idade"]]) # linhas 1-3, colunas específicas
# iloc — por posição inteira
print(df.iloc[0, 1]) # linha 0, coluna 1
print(df.iloc[:3, :2]) # primeiras 3 linhas, 2 colunas
# Filtrando
ativos = df[df["ativo"] == True]
sp = df[df["cidade"] == "SP"]
alto_sal = df[df["salario"] > 6000]
sp_ativo = df[(df["cidade"] == "SP") & (df["ativo"] == True)]
recife_ou_rj = df[df["cidade"].isin(["Recife", "RJ"])]
# query() — sintaxe SQL-like
resultado = df.query("salario > 5000 and ativo == True")
Transformações e Cálculos
# Novas colunas
df["bonus"] = df["salario"] * 0.1
df["faixa_etaria"] = pd.cut(
df["idade"],
bins=[0, 25, 35, 50, 100],
labels=["Jovem", "Adulto", "Meia-idade", "Sênior"]
)
# Aplicando funções
df["nome_upper"] = df["nome"].str.upper()
df["salario_k"] = df["salario"].apply(lambda x: f"R$ {x/1000:.1f}k")
# Operações sobre grupos
por_cidade = df.groupby("cidade").agg(
total_funcionarios=("nome", "count"),
salario_medio= ("salario", "mean"),
salario_total= ("salario", "sum"),
idade_media= ("idade", "mean")
).round(2)
print(por_cidade)
# Pivot table
pivot = df.pivot_table(
values="salario",
index="cidade",
columns="ativo",
aggfunc="mean"
)
print(pivot)
Limpeza de Dados
import numpy as np
# Dataset com problemas
df_sujo = pd.DataFrame({
"nome": ["Ana", "Bruno", None, "Diego", "Ana", "Elena"],
"idade": [23, 35, 28, None, 23, -5],
"salario": [4500, 8200, 6300, 12000, 4500, np.nan],
"email": ["ana@email.com", "bruno@email.com", "invalido",
"diego@email.com", "ana@email.com", "elena@email.com"]
})
print("=== Dados sujos ===")
print(df_sujo)
print(f"\nValores nulos:\n{df_sujo.isnull().sum()}")
print(f"\nDuplicatas: {df_sujo.duplicated().sum()}")
# 1. Removendo duplicatas
df_limpo = df_sujo.drop_duplicates()
# 2. Tratando valores nulos
df_limpo["nome"].fillna("Desconhecido", inplace=True)
df_limpo["salario"].fillna(df_limpo["salario"].median(), inplace=True)
df_limpo.dropna(subset=["idade"], inplace=True) # remove linhas sem idade
# 3. Corrigindo valores inválidos
df_limpo = df_limpo[df_limpo["idade"] > 0]
# 4. Validando e-mails
df_limpo["email_valido"] = df_limpo["email"].str.contains(
r"^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$",
regex=True
)
# 5. Normalizando tipos
df_limpo["idade"] = df_limpo["idade"].astype(int)
df_limpo["salario"] = df_limpo["salario"].astype(float)
print("\n=== Dados limpos ===")
print(df_limpo)
Matplotlib: Visualização Fundamental
import matplotlib.pyplot as plt
import numpy as np
# Configuração global
plt.rcParams.update({
"figure.figsize": (10, 6),
"axes.spines.top": False,
"axes.spines.right": False,
"font.family": "DejaVu Sans"
})
def graficos_basicos():
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
fig.suptitle("Tipos de Gráficos", fontsize=16, fontweight="bold")
# 1. Linha
x = np.linspace(0, 10, 100)
ax = axes[0, 0]
ax.plot(x, np.sin(x), label="sen(x)", color="#2E75B6")
ax.plot(x, np.cos(x), label="cos(x)", color="#C00000", linestyle="--")
ax.set_title("Gráfico de Linha")
ax.legend()
ax.grid(alpha=0.3)
# 2. Barras
categorias = ["Jan", "Fev", "Mar", "Abr", "Mai"]
valores = [42, 58, 71, 65, 83]
ax = axes[0, 1]
bars = ax.bar(categorias, valores, color="#2E75B6", alpha=0.8)
ax.bar_label(bars, padding=2)
ax.set_title("Gráfico de Barras")
# 3. Dispersão
np.random.seed(42)
x = np.random.randn(100)
y = 2 * x + np.random.randn(100)
ax = axes[0, 2]
ax.scatter(x, y, alpha=0.6, color="#2E75B6")
ax.set_title("Dispersão")
# 4. Histograma
dados = np.random.normal(170, 10, 500)
ax = axes[1, 0]
ax.hist(dados, bins=30, color="#2E75B6", alpha=0.8, edgecolor="white")
ax.set_title("Histograma")
ax.set_xlabel("Altura (cm)")
# 5. Pizza
labels = ["Aprovados", "Reprovados", "Recuperação"]
sizes = [65, 20, 15]
cores = ["#375623", "#C00000", "#F5A623"]
ax = axes[1, 1]
ax.pie(sizes, labels=labels, colors=cores, autopct="%1.1f%%", startangle=90)
ax.set_title("Pizza")
# 6. Box Plot
dados_box = [np.random.normal(loc, 1, 100) for loc in [2, 3, 5, 8]]
ax = axes[1, 2]
ax.boxplot(dados_box, labels=["A", "B", "C", "D"], patch_artist=True)
ax.set_title("Box Plot")
plt.tight_layout()
plt.savefig("graficos_basicos.png", dpi=150, bbox_inches="tight")
plt.show()
graficos_basicos()
Seaborn: Visualizações Estatísticas
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
# Dataset de exemplo
np.random.seed(42)
df_vis = pd.DataFrame({
"nota": np.random.normal(7.0, 1.5, 200).clip(0, 10),
"horas_estudo": np.random.uniform(1, 8, 200),
"turma": np.random.choice(["A", "B", "C"], 200),
"aprovado": lambda x: None
})
df_vis["aprovado"] = (df_vis["nota"] >= 6).map({True: "Sim", False: "Não"})
sns.set_theme(style="whitegrid", palette="muted")
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 1. Distribuição de notas
sns.histplot(
data=df_vis, x="nota", hue="aprovado",
multiple="stack", bins=20, ax=axes[0, 0]
)
axes[0, 0].set_title("Distribuição de Notas")
axes[0, 0].axvline(6, color="red", linestyle="--", label="Mínimo")
# 2. Boxplot por turma
sns.boxplot(
data=df_vis, x="turma", y="nota",
palette="Blues", ax=axes[0, 1]
)
axes[0, 1].set_title("Notas por Turma")
# 3. Scatter com regressão
sns.regplot(
data=df_vis,
x="horas_estudo", y="nota",
scatter_kws={"alpha": 0.4},
line_kws={"color": "red"},
ax=axes[1, 0]
)
axes[1, 0].set_title("Horas de Estudo vs Nota")
# 4. Heatmap de correlação
correlacao = df_vis[["nota", "horas_estudo"]].corr()
sns.heatmap(
correlacao,
annot=True, fmt=".2f",
cmap="Blues", center=0,
ax=axes[1, 1]
)
axes[1, 1].set_title("Correlação")
plt.suptitle("Análise de Desempenho Escolar", fontsize=16, fontweight="bold")
plt.tight_layout()
plt.savefig("analise_escolar.png", dpi=150, bbox_inches="tight")
plt.show()
Análise Exploratória Completa
def analise_exploratoria(df: pd.DataFrame, coluna_alvo: str):
"""EDA — Exploratory Data Analysis padronizada."""
print("=" * 50)
print("ANÁLISE EXPLORATÓRIA DE DADOS")
print("=" * 50)
# 1. Visão geral
print(f"\n📊 Dimensões: {df.shape[0]} linhas × {df.shape[1]} colunas")
print(f"\n📋 Tipos de dados:\n{df.dtypes}")
print(f"\n🔍 Valores nulos:\n{df.isnull().sum()}")
print(f"\n🔁 Duplicatas: {df.duplicated().sum()}")
# 2. Estatísticas da variável alvo
alvo = df[coluna_alvo]
print(f"\n📈 Estatísticas de '{coluna_alvo}':")
print(f" Média: {alvo.mean():.2f}")
print(f" Mediana: {alvo.median():.2f}")
print(f" Desvio: {alvo.std():.2f}")
print(f" Assimetria: {alvo.skew():.2f}")
print(f" Curtose: {alvo.kurtosis():.2f}")
# 3. Correlações com a variável alvo
numericas = df.select_dtypes(include=[np.number])
correlacoes = numericas.corr()[coluna_alvo].sort_values(ascending=False)
print(f"\n🔗 Correlações com '{coluna_alvo}':\n{correlacoes}")
# 4. Distribuição de categorias
categoricas = df.select_dtypes(include=["object", "category"])
for col in categoricas.columns:
print(f"\n📌 {col}:")
print(df[col].value_counts().head(5))
analise_exploratoria(df_vis, "nota")
SciPy: Estatística Avançada
from scipy import stats
# Teste t — comparar médias de dois grupos
turma_a = df_vis[df_vis["turma"] == "A"]["nota"]
turma_b = df_vis[df_vis["turma"] == "B"]["nota"]
t_stat, p_valor = stats.ttest_ind(turma_a, turma_b)
print(f"Teste t: t={t_stat:.3f}, p={p_valor:.3f}")
print(f"Diferença significativa: {'Sim' if p_valor < 0.05 else 'Não'}")
# Teste de normalidade
stat, p = stats.shapiro(turma_a)
print(f"\nShapiro-Wilk: stat={stat:.3f}, p={p:.3f}")
print(f"Distribuição normal: {'Sim' if p > 0.05 else 'Não'}")
# Intervalo de confiança
media = turma_a.mean()
ic = stats.t.interval(
confidence=0.95,
df=len(turma_a) - 1,
loc=media,
scale=stats.sem(turma_a)
)
print(f"\nIC 95%: [{ic[0]:.2f}, {ic[1]:.2f}]")
# Regressão linear
slope, intercept, r, p, se = stats.linregress(
df_vis["horas_estudo"], df_vis["nota"]
)
print(f"\nRegressão Linear:")
print(f" Inclinação: {slope:.3f}")
print(f" Intercepto: {intercept:.3f}")
print(f" R²: {r**2:.3f}")
Resumo
- NumPy fornece arrays multidimensionais com operações vetorizadas — base de todo o ecossistema científico
- pandas organiza dados em DataFrames com operações de seleção, transformação, agrupamento e limpeza
groupby().agg()resume dados por categoria de forma expressiva e eficiente- Limpeza de dados inclui tratar nulos, remover duplicatas e corrigir tipos e valores inválidos
- Matplotlib oferece controle total sobre gráficos; Seaborn adiciona visualizações estatísticas elegantes
- EDA — Exploratory Data Analysis — é sempre o primeiro passo antes de qualquer modelagem
- SciPy complementa NumPy com testes estatísticos, distribuições e regressões
Referências e Leituras Complementares
- NumPy — documentação oficial — https://numpy.org/doc/stable/
- pandas — documentação oficial — https://pandas.pydata.org/docs/
- Matplotlib — documentação oficial — https://matplotlib.org/stable/
- Seaborn — documentação oficial — https://seaborn.pydata.org/
- SciPy — documentação oficial — https://docs.scipy.org/doc/scipy/
- MCKINNEY, Wes. Python for Data Analysis. 3. ed. O'Reilly Media, 2022. — o livro definitivo sobre pandas, escrito pelo seu criador.
- VANDERPLAS, Jake. Python Data Science Handbook. O'Reilly Media, 2016. — guia completo do ecossistema científico Python, disponível gratuitamente em https://jakevdp.github.io/PythonDataScienceHandbook/
- GÉRON, Aurélien. Hands-On Machine Learning. 3. ed. O'Reilly Media, 2022. Cap. 2 — pipeline completo de Data Science do início ao fim.