Python para Data Science: NumPy, Pandas e Scikit-Learn em 2026

Domine os tres pilares do ecossistema Python para ciencia de dados: NumPy para computacao vetorizada, Pandas para manipulacao de dados e Scikit-Learn para machine learning com pipelines reproduziveis.

Ilustracao de codigo Python com NumPy, Pandas e Scikit-Learn para ciencia de dados

O ecossistema Python para ciencia de dados amadureceu a ponto de se tornar o padrao de fato na industria. NumPy, Pandas e Scikit-Learn formam uma triade que cobre o ciclo completo do trabalho com dados: da computacao numerica eficiente a entrega de modelos preditivos em producao. Compreender cada camada dessa pilha -- e como elas se encaixam -- e requisito indispensavel para qualquer profissional que lida com perguntas de entrevista em data science ou busca elevar a qualidade do proprio trabalho analitico.

Versoes utilizadas neste artigo

Todos os exemplos foram validados com Python 3.12, NumPy 2.1, Pandas 2.2 e Scikit-Learn 1.5. As APIs descritas aqui refletem o comportamento estaivel dessas versoes em 2026.

NumPy: A Base da Computacao Vetorizada

O NumPy e a fundacao sobre a qual toda a pilha de ciencia de dados Python e construida. Seu objeto central -- o ndarray -- armazena dados homogeneos em memoria contigua e delega operacoes a rotinas compiladas em C e Fortran. O resultado pratico e que lacos Python, notoriamente lentos para operacoes numericas massivas, tornam-se desnecessarios.

Arrays e Operacoes Elementares

O ponto de partida e a criacao de arrays e a aplicacao de aritmetica vetorizada:

python
# numpy_basics.py
import numpy as np

# Create arrays from different sources
prices = np.array([29.99, 49.99, 19.99, 99.99, 39.99])
quantities = np.arange(1, 6)  # [1, 2, 3, 4, 5]

# Vectorized arithmetic — no loops needed
revenue = prices * quantities
print(revenue)  # [29.99, 99.98, 59.97, 399.96, 199.95]

# Statistical aggregations
print(f"Total revenue: ${revenue.sum():.2f}")   # $789.85
print(f"Mean price: ${prices.mean():.2f}")       # $47.99
print(f"Std deviation: ${prices.std():.2f}")     # $27.64

# Boolean indexing — filter without loops
premium_mask = prices > 40
premium_items = prices[premium_mask]  # [49.99, 99.99]

O indexamento booleano merece atencao especial: em vez de iterar sobre elementos e aplicar condicionais, uma mascara binaria e gerada e aplicada em uma unica operacao vetorizada. Esse padrao e recorrente ao longo de toda a pilha de dados.

Broadcasting e Reshaping

O conceito de broadcasting permite que operacoes entre arrays de formas distintas sejam realizadas sem copias desnecessarias. O reshaping prepara tensores para consumo por modelos de machine learning, que frequentemente exigem entradas bidimensionais:

python
# numpy_reshape.py
import numpy as np

# Monthly sales data: 4 products x 3 months
sales = np.array([
    [120, 150, 130],  # Product A
    [200, 180, 220],  # Product B
    [90, 110, 95],    # Product C
    [300, 280, 310],  # Product D
])

# Column-wise mean (average per month)
monthly_avg = sales.mean(axis=0)  # [177.5, 180.0, 188.75]

# Row-wise sum (total per product)
product_totals = sales.sum(axis=1)  # [400, 600, 295, 890]

# Normalize each product relative to its own max
normalized = sales / sales.max(axis=1, keepdims=True)
# keepdims=True preserves the shape for broadcasting
print(normalized[0])  # [0.8, 1.0, 0.867] — Product A relative to its peak

# Reshape for Scikit-Learn (requires 2D input)
flat_sales = sales.flatten()  # 1D array of 12 values
reshaped = flat_sales.reshape(-1, 1)  # 12x1 column vector

O parametro keepdims=True e sutil mas essencial: sem ele, a divisao entre um array 2D e um array 1D produziria um resultado diferente do esperado. Dominar as regras de broadcasting evita uma categoria inteira de bugs silenciosos.

Eixos no NumPy

axis=0 opera ao longo das linhas (produz um resultado por coluna) e axis=1 opera ao longo das colunas (produz um resultado por linha). A confusao entre os dois e uma das fontes mais comuns de erros em codigo cientifico.

Pandas: Do Dado Bruto ao Dataset Pronto para Modelagem

Enquanto o NumPy opera sobre arrays homogeneos, o Pandas lida com dados tabulares heterogeneos -- a realidade cotidiana de quem trabalha com CSV, bancos relacionais ou APIs. O DataFrame combina a expressividade de uma planilha com a potencia de uma linguagem de programacao completa.

Limpeza Reproduzivel com Method Chaining

Dados reais chegam sujos: valores ausentes, outliers, duplicatas, tipos incorretos. A abordagem com method chaining -- encadeamento de metodos em um unico bloco -- garante que cada etapa da limpeza seja explicita e auditavel:

python
# pandas_cleaning.py
import pandas as pd
import numpy as np

# Load and inspect raw data
df = pd.read_csv("candidates.csv")
print(df.shape)       # (1500, 8)
print(df.dtypes)      # Check column types
print(df.isna().sum()) # Count missing values per column

# Clean in a reproducible chain
df_clean = (
    df
    .dropna(subset=["salary", "experience_years"])      # Drop rows missing critical fields
    .assign(
        salary=lambda x: x["salary"].clip(lower=20000, upper=500000),  # Cap outliers
        experience_years=lambda x: x["experience_years"].astype(int),
        hired_date=lambda x: pd.to_datetime(x["hired_date"], errors="coerce"),
    )
    .drop_duplicates(subset=["email"])                  # Remove duplicate candidates
    .query("experience_years >= 0")                     # Filter invalid entries
    .reset_index(drop=True)
)

print(f"Cleaned: {len(df)} -> {len(df_clean)} rows")

O metodo .assign() e preferivel a atribuicao direta (df['col'] = ...) dentro de uma chain porque retorna uma copia modificada sem alterar o DataFrame original. Isso preserva a rastreabilidade das transformacoes e facilita testes unitarios sobre cada etapa.

GroupBy e Engenharia de Features

Agregacoes por grupo sao o pao e manteiga da analise exploratoria e da criacao de features. O Pandas oferece uma interface expressiva para construir estatisticas agregadas e enriquece-las com informacoes contextuais:

python
# pandas_groupby.py
import pandas as pd

# Aggregate candidate stats by department
dept_stats = (
    df_clean
    .groupby("department")
    .agg(
        avg_salary=("salary", "mean"),
        median_experience=("experience_years", "median"),
        headcount=("email", "count"),
        max_salary=("salary", "max"),
    )
    .sort_values("avg_salary", ascending=False)
)
print(dept_stats.head())

# Create features for ML: encode categorical + add aggregated stats
df_features = (
    df_clean
    .assign(
        # Ratio of individual salary to department average
        salary_ratio=lambda x: x["salary"] / x.groupby("department")["salary"].transform("mean"),
        # Time since hire in days
        tenure_days=lambda x: (pd.Timestamp.now() - x["hired_date"]).dt.days,
        # Binary encoding
        is_senior=lambda x: (x["experience_years"] >= 5).astype(int),
    )
)

O metodo .transform() e particularmente poderoso: diferente de .agg(), que reduz o grupo a uma linha, ele devolve um Series do mesmo tamanho do DataFrame original -- ideal para calcular estatisticas relativas como o salary_ratio acima. Esse tipo de feature contextual e justamente o que se discute em perguntas de entrevista sobre feature engineering.

Pronto para mandar bem nas entrevistas de Data Science & ML?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

Scikit-Learn: Pipelines de Machine Learning em Producao

O Scikit-Learn consolidou uma API unificada -- fit, transform, predict -- que cobre desde pre-processamento ate modelos de gradient boosting. Sua proposta mais valiosa, porem, vai alem dos algoritmos: a abstracao de Pipeline garante que todo o fluxo de transformacao e predicao seja tratado como um unico objeto, eliminando uma das causas mais comuns de data leakage.

Pipeline com ColumnTransformer

Dados tabulares reais contem colunas numericas e categoricas que exigem transformacoes distintas. O ColumnTransformer resolve isso de forma elegante:

python
# sklearn_pipeline.py
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import classification_report
import pandas as pd

# Define column groups
numeric_features = ["salary", "experience_years", "salary_ratio", "tenure_days"]
categorical_features = ["department", "role_level"]
target = "promoted"

# Split before any preprocessing
X = df_features[numeric_features + categorical_features]
y = df_features[target]
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# Build the preprocessing + model pipeline
preprocessor = ColumnTransformer(
    transformers=[
        ("num", StandardScaler(), numeric_features),           # Scale numeric columns
        ("cat", OneHotEncoder(handle_unknown="ignore"), categorical_features),  # Encode categories
    ]
)

pipeline = Pipeline([
    ("preprocessor", preprocessor),
    ("classifier", GradientBoostingClassifier(
        n_estimators=200,
        learning_rate=0.1,
        max_depth=4,
        random_state=42,
    )),
])

# Train and evaluate
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
print(classification_report(y_test, y_pred))

A ordem das operacoes importa: o train_test_split acontece antes de qualquer transformacao. Se o StandardScaler fosse ajustado sobre todo o dataset antes do split, estatisticas do conjunto de teste contaminariam o treinamento -- um vazamento de dados classico que infla artificialmente metricas de validacao. Esse e um dos topicos mais cobrados em tarefas de aprendizado supervisionado.

Data Leakage: o inimigo silencioso

Jamais ajuste transformadores (scalers, encoders, imputadores) sobre dados que incluam o conjunto de teste. Use sempre pipeline.fit(X_train, y_train) e nunca aplique .fit_transform() no dataset completo antes do split.

Uma unica divisao treino/teste e insuficiente para estimar a performance real de um modelo. A validacao cruzada estratificada produz estimativas mais robustas, enquanto o GridSearchCV automatiza a busca por hiperparametros otimos:

python
# sklearn_tuning.py
from sklearn.model_selection import cross_val_score, GridSearchCV
import numpy as np

# 5-fold cross-validation on the full pipeline
scores = cross_val_score(pipeline, X_train, y_train, cv=5, scoring="f1")
print(f"F1 scores: {scores}")
print(f"Mean F1: {scores.mean():.3f} (+/- {scores.std() * 2:.3f})")

# Grid search over hyperparameters
param_grid = {
    "classifier__n_estimators": [100, 200, 300],
    "classifier__max_depth": [3, 4, 5],
    "classifier__learning_rate": [0.05, 0.1, 0.2],
}

grid_search = GridSearchCV(
    pipeline,
    param_grid,
    cv=5,
    scoring="f1",
    n_jobs=-1,      # Use all CPU cores
    verbose=1,
)

grid_search.fit(X_train, y_train)
print(f"Best params: {grid_search.best_params_}")
print(f"Best F1: {grid_search.best_score_:.3f}")

# Evaluate the best model on held-out test set
best_model = grid_search.best_estimator_
print(classification_report(y_test, best_model.predict(X_test)))

A notacao de duplo sublinhado (classifier__n_estimators) e a sintaxe do Scikit-Learn para referenciar parametros de etapas internas de um pipeline. O n_jobs=-1 instrui o framework a usar todos os nucleos disponiveis, acelerando significativamente a busca em grades grandes. Com 27 combinacoes e 5 folds, sao 135 modelos treinados -- paralelizacao aqui nao e opcional.

Exportacao e Carregamento do Modelo

Um modelo treinado so agrega valor quando pode ser implantado. O joblib serializa o pipeline completo -- preprocessador e classificador juntos -- em um unico arquivo binario:

python
# sklearn_export.py
import joblib
from pathlib import Path

# Save the complete pipeline (preprocessor + model)
model_dir = Path("models")
model_dir.mkdir(exist_ok=True)
joblib.dump(best_model, model_dir / "promotion_model_v1.joblib")

# Load and predict in a different process
loaded_model = joblib.load(model_dir / "promotion_model_v1.joblib")
new_data = pd.DataFrame({
    "salary": [75000],
    "experience_years": [4],
    "salary_ratio": [1.05],
    "tenure_days": [730],
    "department": ["Engineering"],
    "role_level": ["Mid"],
})

prediction = loaded_model.predict(new_data)
probability = loaded_model.predict_proba(new_data)[:, 1]
print(f"Promoted: {bool(prediction[0])}, Confidence: {probability[0]:.2%}")

Carregar o pipeline serializado e aplica-lo a novos dados requer exatamente as mesmas colunas usadas no treinamento, na mesma ordem. Como o ColumnTransformer armazena essa informacao internamente, nao ha necessidade de replicar a logica de pre-processamento no servico de inferencia -- o objeto carregado e autossuficiente.

Versionamento de modelos

Adote uma convencao de nomenclatura que inclua versao e data (promotion_model_v1_20260407.joblib). Em ambientes de producao, ferramentas como MLflow ou DVC oferecem rastreamento mais robusto de experimentos e artefatos.

Como as Tres Camadas se Integram

A elegancia desse ecossistema esta na forma como as camadas se comunicam. O NumPy fornece a representacao numerica fundamental; o Pandas constroi sobre ela uma interface orientada a dados tabulares; o Scikit-Learn consome DataFrames do Pandas diretamente (desde a versao 1.0, com suporte nativo a feature_names_in_). O fluxo tipico de um projeto segue esta sequencia:

  • Ingestao e inspecao: pd.read_csv(), df.dtypes, df.describe(), df.isna().sum()
  • Limpeza: method chaining com .dropna(), .assign(), .query()
  • Analise exploratoria: .groupby().agg(), .corr(), visualizacoes com Matplotlib/Seaborn
  • Engenharia de features: .transform(), operacoes vetorizadas NumPy, codificacao manual
  • Modelagem: Pipeline + ColumnTransformer + estimador Scikit-Learn
  • Avaliacao: cross_val_score, classification_report, matrizes de confusao
  • Implantacao: joblib.dump() para serializacao, API REST ou batch job para inferencia

Cada etapa dessa lista corresponde a habilidades concretas que sao avaliadas em processos seletivos. Quem domina o fluxo completo -- nao apenas snippets isolados -- se posiciona de forma diferenciada. Para aprofundar o estudo dos algoritmos por tras dos modelos, as perguntas de entrevista sobre machine learning oferecem um complemento direto ao conhecimento pratico deste tutorial.

Conclusao

NumPy, Pandas e Scikit-Learn nao sao tres ferramentas independentes: sao camadas de uma pilha coesa que transforma dados brutos em decisoes automatizadas. Os pontos centrais a consolidar:

  • NumPy elimina lacos Python com vetorizacao, broadcasting e indexamento booleano -- o alicerce de toda operacao numerica eficiente
  • Pandas oferece method chaining para limpeza reproduzivel, GroupBy para analise agregada e .transform() para features contextuais
  • Scikit-Learn impoe disciplina com a abstracao de Pipeline, prevenindo data leakage e encapsulando pre-processamento e modelo em um unico objeto implantavel
  • O split treino/teste deve ocorrer antes de qualquer ajuste de transformadores
  • GridSearchCV com n_jobs=-1 e validacao cruzada estratificada sao o padrao para selecao de hiperparametros
  • joblib serializa o pipeline completo, tornando a inferencia autossuficiente sem replicacao de logica

A proficiencia nessa pilha e verificavel e mensuravel: pipelines que nao vazam dados, codigo que produz os mesmos resultados em qualquer maquina e modelos que chegam a producao de forma rastreavel.

Comece a praticar!

Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.

Tags

#data-science
#python
#numpy
#pandas
#scikit-learn
#machine-learning
#tutorial

Compartilhar

Artigos relacionados