---
title: "Pandas: O que É e Como Funciona | Python Brasil"
url: "https://python.dev.br/glossario/pandas/"
markdown_url: "https://python.dev.br/glossario/pandas.MD"
description: "Pandas é a biblioteca Python para análise de dados. Aprenda DataFrame, Series, groupby, merge, tratamento de dados faltantes e muito mais."
date: "2025-03-22"
author: ""
---

# Pandas: O que É e Como Funciona | Python Brasil

Pandas é a biblioteca Python para análise de dados. Aprenda DataFrame, Series, groupby, merge, tratamento de dados faltantes e muito mais.


## O que é Pandas?

O **Pandas** é a biblioteca mais popular do Python para **análise e manipulação de dados**. Criada por Wes McKinney em 2008, ela oferece estruturas de dados poderosas e ferramentas para trabalhar com dados tabulares de forma rápida e intuitiva.

O nome vem de "Panel Data", um termo de econometria para conjuntos de dados multidimensionais. Hoje, o Pandas é indispensável para qualquer cientista de dados, analista ou engenheiro que trabalha com Python.

## Series: a estrutura unidimensional

A `Series` é o bloco fundamental do Pandas: um array unidimensional com rótulos (índice) em cada elemento.

```python
import pandas as pd
import numpy as np

# Criando Series de diferentes formas
s1 = pd.Series([10, 20, 30, 40])           # Indice automático (0, 1, 2, 3)
s2 = pd.Series([10, 20, 30], index=['a', 'b', 'c'])  # Indice personalizado
s3 = pd.Series({'jan': 100, 'fev': 200, 'mar': 150}) # A partir de dicionário

# Operações em Series
print(s2 * 2)         # Multiplica todos os valores por 2
print(s2[s2 > 15])    # Filtragem booleana
print(s2.mean())      # Média: 20.0
print(s2.describe())  # Estatísticas descritivas

# Alinhamento automático por índice
a = pd.Series({'x': 1, 'y': 2, 'z': 3})
b = pd.Series({'x': 10, 'y': 20, 'w': 30})
print(a + b)
# w     NaN
# x    11.0
# y    22.0
# z     NaN
# 'z' e 'w' não têm par, resultam em NaN
```

## Criando DataFrames de diferentes fontes

```python
import pandas as pd

# A partir de dicionário (forma mais comum)
df_dict = pd.DataFrame({
    'nome': ['Ana', 'Bruno', 'Carla'],
    'idade': [28, 34, 25],
    'salario': [8500.0, 12000.0, 7200.0]
})

# A partir de lista de dicionários
registros = [
    {'produto': 'Notebook', 'preco': 3500, 'estoque': 10},
    {'produto': 'Mouse', 'preco': 80, 'estoque': 150},
    {'produto': 'Teclado', 'preco': 200, 'estoque': 75},
]
df_lista = pd.DataFrame(registros)

# Lendo arquivos externos
# df_csv   = pd.read_csv('dados.csv', encoding='utf-8', sep=';')
# df_excel = pd.read_excel('planilha.xlsx', sheet_name='Vendas')
# df_json  = pd.read_json('dados.json')
# df_sql   = pd.read_sql('SELECT * FROM clientes', conexao)

# Inspecionando o DataFrame
print(df_dict.head(3))     # Primeiras 3 linhas
print(df_dict.tail(2))     # Últimas 2 linhas
print(df_dict.info())      # Tipos de dados e valores não-nulos
print(df_dict.describe())  # Estatísticas descritivas das colunas numéricas
print(df_dict.shape)       # (3, 3) - linhas e colunas
print(df_dict.dtypes)      # Tipo de cada coluna
```

## Indexação: loc, iloc, at e iat

O Pandas oferece quatro formas principais de indexar dados, cada uma com seu propósito:

```python
import pandas as pd

df = pd.DataFrame({
    'nome': ['Ana', 'Bruno', 'Carla', 'Diego'],
    'idade': [28, 34, 25, 31],
    'cidade': ['SP', 'RJ', 'PR', 'MG'],
    'salario': [8500, 12000, 7200, 9800]
}, index=['a', 'b', 'c', 'd'])

# loc: indexação por RÓTULO (label-based)
print(df.loc['a'])                     # Linha com rótulo 'a'
print(df.loc['a', 'nome'])             # Valor específico: 'Ana'
print(df.loc['a':'c', 'nome':'idade']) # Intervalo de rótulos
print(df.loc[df['idade'] > 30])        # Filtragem booleana com loc

# iloc: indexação por POSIÇÃO (position-based)
print(df.iloc[0])          # Primeira linha (posição 0)
print(df.iloc[0, 1])       # Linha 0, coluna 1 → 28
print(df.iloc[1:3, 0:2])   # Linhas 1-2, colunas 0-1

# at e iat: acesso ESCALAR (mais rápido para valores únicos)
print(df.at['a', 'nome'])    # 'Ana'   - por rótulo
print(df.iat[0, 0])          # 'Ana'   - por posição

# Adicionando e removendo colunas
df['bonus'] = df['salario'] * 0.1              # Nova coluna calculada
df.drop(columns=['bonus'], inplace=True)       # Remove coluna
df_sem_linha = df.drop(index=['a'])            # Remove linha
```

## GroupBy com múltiplas agregações

```python
import pandas as pd
import numpy as np

dados = pd.DataFrame({
    'departamento': ['TI', 'TI', 'RH', 'RH', 'TI', 'RH'],
    'cargo': ['Jr', 'Sr', 'Jr', 'Sr', 'Pl', 'Pl'],
    'salario': [4000, 9000, 3500, 7000, 6500, 5500],
    'anos_empresa': [1, 5, 2, 8, 3, 4]
})

# Agregação simples
media_dept = dados.groupby('departamento')['salario'].mean()

# Múltiplas agregações com agg
resumo = dados.groupby('departamento').agg(
    salario_medio=('salario', 'mean'),
    salario_maximo=('salario', 'max'),
    salario_minimo=('salario', 'min'),
    total_funcionarios=('salario', 'count'),
    media_anos=('anos_empresa', 'mean')
)
print(resumo)

# Agrupamento por múltiplas colunas
por_dept_cargo = dados.groupby(['departamento', 'cargo'])['salario'].mean()

# transform: mantém o mesmo tamanho do DataFrame original
dados['media_dept'] = dados.groupby('departamento')['salario'].transform('mean')
dados['acima_media'] = dados['salario'] > dados['media_dept']
print(dados)
```

## Merge, Join e Concat

```python
import pandas as pd

clientes = pd.DataFrame({
    'id': [1, 2, 3, 4],
    'nome': ['Ana', 'Bruno', 'Carla', 'Diego']
})

pedidos = pd.DataFrame({
    'pedido_id': [101, 102, 103, 104],
    'cliente_id': [1, 2, 1, 5],     # cliente 5 não existe em clientes
    'valor': [150.0, 89.0, 220.0, 75.0]
})

# INNER JOIN: apenas registros com correspondência em ambos os lados
inner = pd.merge(clientes, pedidos,
                 left_on='id', right_on='cliente_id', how='inner')

# LEFT JOIN: todos os clientes, mesmo sem pedidos
left = pd.merge(clientes, pedidos,
                left_on='id', right_on='cliente_id', how='left')

# OUTER JOIN: todos os registros de ambas as tabelas
outer = pd.merge(clientes, pedidos,
                 left_on='id', right_on='cliente_id', how='outer')

print(f"Inner: {len(inner)} linhas")  # 3 linhas
print(f"Left:  {len(left)} linhas")   # 4 linhas (todos os clientes)

# concat: empilhar DataFrames
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})
empilhado = pd.concat([df1, df2], ignore_index=True)      # Empilha linhas
lado_a_lado = pd.concat([df1, df2], axis=1)                # Lado a lado
```

## Tratamento de dados faltantes

```python
import pandas as pd
import numpy as np

df = pd.DataFrame({
    'A': [1, np.nan, 3, np.nan, 5],
    'B': [np.nan, 2, 3, 4, 5],
    'C': [1, 2, np.nan, 4, 5]
})

# Detectando valores faltantes
print(df.isnull().sum())          # Contagem de NaN por coluna
print(df.isnull().sum().sum())    # Total de NaN no DataFrame
print(df.notna().all())           # Colunas sem nenhum NaN

# dropna: removendo linhas ou colunas com NaN
df_sem_nan = df.dropna()                    # Remove qualquer linha com NaN
df_limpo = df.dropna(thresh=2)             # Mantém linhas com ao menos 2 valores válidos
df_cols = df.dropna(axis=1)               # Remove colunas com NaN

# fillna: preenchendo valores faltantes
df_zero = df.fillna(0)                      # Substitui por zero
df_media = df.fillna(df.mean())             # Substitui pela média da coluna
df_forward = df.fillna(method='ffill')      # Propaga o último valor válido
df_backward = df.fillna(method='bfill')     # Propaga o próximo valor válido

# interpolate: interpolação entre valores
df_interp = df.interpolate(method='linear') # Interpolação linear entre vizinhos

# Combinando estratégias por coluna
df['A'] = df['A'].fillna(df['A'].median())
df['B'] = df['B'].interpolate()
df['C'] = df['C'].fillna('desconhecido')
```

## Apply, Map e Replace

```python
import pandas as pd

df = pd.DataFrame({
    'nome': ['ana silva', 'BRUNO COSTA', 'Carla Souza'],
    'salario': [8500, 12000, 7200],
    'nota': [7.5, 9.2, 6.8]
})

# apply: aplica uma função a linhas ou colunas
df['nome_formatado'] = df['nome'].apply(str.title)
df['salario_com_bonus'] = df['salario'].apply(lambda x: x * 1.1 if x < 10000 else x)

# apply em linhas inteiras (axis=1)
def classificar_nota(row):
    if row['nota'] >= 7:
        return 'Aprovado'
    return 'Reprovado'

df['status'] = df.apply(classificar_nota, axis=1)

# map: substitui valores em uma Series (útil para mapeamentos)
mapa_nivel = {8500: 'Junior', 12000: 'Senior', 7200: 'Junior'}
df['nivel'] = df['salario'].map(mapa_nivel)

# replace: substitui valores específicos
df['status'] = df['status'].replace({'Aprovado': 1, 'Reprovado': 0})

print(df)
```

## Pandas vs SQL: comparação de operações

| SQL | Pandas |
|-----|--------|
| `SELECT col FROM tb WHERE col > 5` | `df.loc[df['col'] > 5, 'col']` |
| `GROUP BY col HAVING COUNT(*) > 2` | `df.groupby('col').filter(lambda x: len(x) > 2)` |
| `ORDER BY col DESC` | `df.sort_values('col', ascending=False)` |
| `JOIN` | `pd.merge(df1, df2, on='col')` |
| `LIMIT 10` | `df.head(10)` |

## Dicas de performance

```python
import pandas as pd
import numpy as np

# 1. Use dtype 'category' para colunas com poucos valores únicos
df = pd.DataFrame({'status': ['ativo', 'inativo', 'ativo'] * 10000})
df['status'] = df['status'].astype('category')  # Reduz memória drasticamente

# 2. query() é mais legível e às vezes mais rápido que filtragem booleana
df_filtrado = df.query("status == 'ativo'")

# 3. Evite loops - use vetorização
# RUIM:
# for i, row in df.iterrows():
#     df.at[i, 'nova_col'] = row['valor'] * 2

# BOM:
df['nova_col'] = df['valor'] * 2  # Se 'valor' existir

# 4. Especifique dtypes ao ler CSV para reduzir uso de memória
# df = pd.read_csv('dados.csv', dtype={'id': 'int32', 'status': 'category'})
```

## Quando usar Pandas

Use Pandas quando precisar explorar e analisar dados tabulares interativamente, ler e escrever dados em formatos como CSV, Excel ou SQL, realizar operacoes de limpeza e transformacao de dados, ou preparar dados para modelos de machine learning. Para grandes volumes de dados que nao cabem na memoria RAM, considere alternativas como Polars, Dask ou PySpark.

## Termos Relacionados

- [NumPy](/glossario/numpy/) - Base numérica usada pelo Pandas
- [Jupyter Notebook](/glossario/jupyter-notebook/) - Ambiente interativo para análise
- [Machine Learning](/glossario/machine-learning/) - Aprendizado de máquina com Python

> **Análise de dados além do Python**: <a href="https://rustlang.com.br/blog/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', {source: 'python.dev.br', target: 'rustlang.com.br', content: 'glossario-pandas'})">Rust é a base do Polars</a>, alternativa de alta performance ao Pandas, e <a href="https://golang.com.br/blog/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', {source: 'python.dev.br', target: 'golang.com.br', content: 'glossario-pandas'})">Go oferece ferramentas para pipelines de dados</a> em larga escala.
