# 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. - Published: 2026-04-07 - Updated: 2026-04-07 - Author: Anthony Fillion-Maillet - Tags: data-science, python, numpy, pandas, scikit-learn, machine-learning, tutorial - Reading time: 10 min --- 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](/technologies/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](/technologies/data-science/interview-questions/feature-engineering). ## 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](/technologies/data-science/interview-questions/ml-supervised-classification). > **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. ### Validacao Cruzada e Grid Search 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](/blog/data-science/machine-learning-algorithms-explained) 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. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pt/blog/data-science/python-data-science-numpy-pandas-scikit-learn-2026