Pandas: Operações com Strings

Última atualização: 2026-08-26

Os textos em dados do mundo real nunca são limpos — espaços extras, capitalização inconsistente, caracteres especiais, formatos misturados. O acessador .str do Pandas traz vetorização para operações com strings: limpe uma coluna inteira de texto em uma única linha de código, até 100 vezes mais rápido que um laço em Python. Esta seção aborda os métodos de string mais comumente usados e mostra como construir pipelines de limpeza encadeados.

⚠️ Nota: O código abaixo requer um ambiente Python local para ser executado.

1. What You Will Learn


2. Limpeza de Entrada do Usuário de Carol

(1) O Problema: Entradas de Usuário Vêm em Todos os Formatos

Os dados do usuário que Carol coletou estão uma bagunça:

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['  alice  ', 'BOB', 'Charlie!', '  carol  ', 'DaVid123'],
    'email': ['alice@EXAMPLE.com', 'bob@company.ORG', 'charlie@uni.edu',
              'CAROL@example.COM', 'david@test.net'],
    'phone': ['555-0100', '(555) 0200', '555.0300', '+1-555-0400', '5550500']
})
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.

(2) A Solução: Limpeza Encadeada com .str

▶ Exemplo: Limpeza de Texto Encadeada (Dificuldade ⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['  alice  ', 'BOB', 'Charlie!', '  carol  ', 'DaVid123'],
    'email': ['alice@EXAMPLE.com', 'bob@company.ORG', 'charlie@uni.edu',
              'CAROL@example.COM', 'david@test.net']
})

# Encadeia métodos .str: strip → replace → title
df['name_clean'] = (df['name']
    .str.strip()
    .str.replace(r'[^a-zA-Z ]', '', regex=True)
    .str.title()
)
print(df[['name', 'name_clean']])
#          name name_clean
# 0    alice        Alice
# 1         BOB        Bob
# 2   Charlie!    Charlie
# 3     carol        Carol
# 4   DaVid123       David

# Coloca o domínio do email em minúsculas
df['email_clean'] = df['email'].str.lower()
print(df['email_clean'])
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.

3. O Acessador .str

(1) .str vs Python str

Característica Python str Pandas .str
Opera em Uma única string Uma coluna inteira (vetorizado)
Tratamento de NaN Gera um erro Ignora automaticamente (retorna NaN)
Encadeamento Não suportado ✅ Chamadas consecutivas
Desempenho Loop → lento Vetorizado → rápido

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado — instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.

: Métodos Básicos do .str (Dificuldade ⭐)

PYTHON
import pandas as pd

s = pd.Series(['Hello World', 'pandas', 'DATA SCIENCE', None, 'python'])

# Conversão de caixa
print(s.str.lower())    # hello world, pandas, data science, NaN, python
print(s.str.upper())    # HELLO WORLD, PANDAS, DATA SCIENCE, NaN, PYTHON
print(s.str.title())    # Hello World, Pandas, Data Science, NaN, Python
print(s.str.capitalize())  # Hello world, Pandas, Data science, NaN, Python

# Espaços em branco
s2 = pd.Series(['  hello  ', '\tworld\n', '  pandas  '])
print(s2.str.strip())    # hello, world, pandas
print(s2.str.lstrip())   # hello  , world\n, pandas  
print(s2.str.rstrip())   #   hello, \tworld,   pandas

# Comprimento
print(s.str.len())       # 11, 6, 12, NaN, 6
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado — instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.

4. replace / contains / match

(1) replace

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente local do Python (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e siga junto. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

: Substituição de String com replace (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

s = pd.Series(['price: $100', 'price: $200', 'cost: €50'])

# Simple replacement
print(s.str.replace('$', 'USD'))
# price: USD100, price: USD200, cost: €50

# Regex replacement
print(s.str.replace(r'[\$€]', '', regex=True))
# price: 100, price: 200, cost: 50

# Replace multiple patterns
phones = pd.Series(['555-0100', '(555) 0200', '555.0300'])
clean = phones.str.replace(r'[^0-9]', '', regex=True)
print(clean)  # 5550100, 5550200, 5550300
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente local do Python (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e siga junto. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

(2) contains / startswith / endswith

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente local do Python (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e siga junto. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

: Filtragem de Strings por Condição (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['Alice Johnson', 'Bob Smith', 'Charlie Brown', 'Carol White'],
    'email': ['alice@example.com', 'bob@company.org', 'charlie@uni.edu', 'carol@test.net']
})

# Contains substring
has_com = df[df['email'].str.contains('.com')]
print(has_com['name'])  # Alice Johnson

# Startswith / endswith
starts_with_a = df[df['name'].str.startswith('A')]
print(starts_with_a)

edu_email = df[df['email'].str.endswith('.edu')]
print(edu_email['name'])  # Charlie Brown

# Regex contains — find org or edu domains
org_or_edu = df[df['email'].str.contains(r'\.(org|edu)$', regex=True)]
print(org_or_edu[['name', 'email']])
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente local do Python (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e siga junto. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

(3) contains vs match

Método Posição de correspondência Regex
contains Qualquer lugar na string
match Do início
startswith Do início ❌ (apenas string simples)
endswith Do final ❌ (apenas string simples)

5. divisão / extração

(1) divisão

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

: Dividindo Strings com split (Dificuldade ⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['Alice Johnson', 'Bob Smith', 'Charlie Brown'],
    'email': ['alice@example.com', 'bob@company.org', 'charlie@uni.edu']
})

# Dividir em lista
print(df['name'].str.split(' '))
# 0    [Alice, Johnson]
# 1    [Bob, Smith]
# 2    [Charlie, Brown]

# Dividir em colunas separadas
name_split = df['name'].str.split(' ', expand=True)
print(name_split)
#         0        1
# 0   Alice  Johnson
# 1     Bob    Smith
# 2 Charlie    Brown

# Dividir e manter apenas a primeira parte
df['first_name'] = df['name'].str.split(' ').str[0]
print(df['first_name'])

# Dividir e-mail para obter o domínio
df['domain'] = df['email'].str.split('@').str[1]
print(df['domain'])
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

(2) extração com Regex

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

: Extraindo Padrões com extract (Dificuldade ⭐⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'contact': [
        'Alice <alice@example.com>',
        'Bob <bob@company.org>',
        'Charlie (555-0100)',
        'Carol <carol@test.net>'
    ]
})

# Extrair e-mail com grupo regex
df['email'] = df['contact'].str.extract(r'<(.+?)>')
print(df[['contact', 'email']])
#                   contact             email
# 0  Alice <alice@example.com>  alice@example.com
# 1      Bob <bob@company.org>    bob@company.org
# 2     Charlie (555-0100)                NaN
# 3    Carol <carol@test.net>    carol@test.net

# Extrair múltiplos grupos
df2 = pd.DataFrame({
    'email': ['alice@example.com', 'bob@company.org']
})
parts = df2['email'].str.extract(r'(.+?)@(.+)')
print(parts)
#        0             1
# 0  alice  example.com
# 1    bob   company.org

# Extrair todas as correspondências
colors = pd.Series(['red,blue,green', 'yellow,pink'])
print(colors.str.extractall(r'(\w+)'))
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

6. Outros Métodos Comuns

(1) Referência Rápida

Método Finalidade Exemplo
len() Comprimento da string s.str.len()
count() Número de ocorrências de substring s.str.count('a')
find() Posição da substring s.str.find('bc')
isdigit() Todos dígitos? s.str.isdigit()
isalpha() Todas letras? s.str.isalpha()
join() Juntar com separador s.str.join(',')
pad() Preencher para largura fixa s.str.pad(10, fillchar='0')
repeat() Repetir string s.str.repeat(3)
slice() Fatiar s.str.slice(0, 5)

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.

: pad/slice/zfill (Dificuldade ⭐)

PYTHON
import pandas as pd

ids = pd.Series(['1', '23', '456', '7890'])

# Preencher com zeros até 4 dígitos
print(ids.str.zfill(4))
# 0    0001
# 1    0023
# 2    0456
# 3    7890

# Fatiar os primeiros 2 caracteres
codes = pd.Series(['US-001', 'UK-002', 'JP-003'])
print(codes.str.slice(0, 2))  # US, UK, JP
print(codes.str[:2])           # igual, sintaxe de slice do Python
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem pandas pré-instalado — instale localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeramente dependendo da sua versão do pandas.

7. Exemplo Completo: Pipeline de Limpeza de Texto de Dados de Usuário

(5) ▶ Fluxo de Trabalho de Limpeza de Texto

100%
graph TB
    A[Texto Bruto] --> B[strip: remover espaços em branco]
    B --> C[lower / upper: normalizar caso]
    C --> D[replace: remover caracteres especiais]
    D --> E[split / extract: extrair informações]
    E --> F[title: formatar saída]
    F --> G[Texto Limpo]
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado — instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado — instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

: Limpeza de Texto Completa (Dificuldade ⭐⭐⭐)

PYTHON
import pandas as pd

# ============================================
# Exemplo abrangente: Pipeline de limpeza
# de texto para dados de usuário
# ============================================

# 1. Dados de usuário brutos e desorganizados
df = pd.DataFrame({
    'raw_name': ['  ALICE johnson  ', 'bob   SMITH', '  CHARLIE! brown  ', 'CAROL white123'],
    'raw_email': ['ALICE@Example.COM', 'bob@company.ORG', 'charlie@uni.EDU', 'CAROL@TEST.NET'],
    'raw_phone': ['555-0100', '(555) 0200', '555.0300 ext 42', '+1-555-0400'],
    'raw_zip': ['0123', '12345', '  90210  ', '10001-2345']
})

# 2. Limpeza de nome: strip → remover caracteres especiais → título
df['name'] = (df['raw_name']
    .str.strip()
    .str.replace(r'[^a-zA-Z\s]', '', regex=True)
    .str.replace(r'\s+', ' ', regex=True)  # colapsar múltiplos espaços
    .str.title()
)

# 3. Limpeza de email: caixa baixa
df['email'] = df['raw_email'].str.lower()

# 4. Limpeza de telefone: manter apenas dígitos
df['phone_digits'] = df['raw_phone'].str.replace(r'[^0-9]', '', regex=True)
df['phone_formatted'] = df['phone_digits'].str.slice(0, 3) + '-' + df['phone_digits'].str.slice(3, 7)

# 5. CEP: extrair código de 5 dígitos
df['zip5'] = df['raw_zip'].str.strip().str.extract(r'(\d{5})')

# 6. Domínio do email
df['domain'] = df['email'].str.split('@').str[1]

# 7. Exibir resultados limpos
print("=== Dados Limpos ===")
print(df[['name', 'email', 'phone_formatted', 'zip5', 'domain']])
TEXT 📖 Somente leitura
> **Saída:** Execute isso em um ambiente Python local (pandas 2.x). O servidor Piston não tem o pandas pré-instalado — instale-o localmente (`pip install pandas`) e acompanhe. Os valores reais podem variar ligeiramente dependendo da sua versão do pandas.

❓ Perguntas Frequentes

P: Qual é a diferença entre .str e o str do Python? R: Os métodos str do Python operam em uma única string, enquanto o acessador .str opera em uma coluna inteira (vectorizado). O acessador .str automaticamente ignora valores NaN (retornando NaN), enquanto o str do Python lança um erro em valores NaN. O acessador .str suporta encadeamento de métodos (s.str.strip().str.lower()), o que o str do Python não faz. Em termos de desempenho, .str é 10-100x mais rápido que loops.

P: Como os valores NaN são tratados? R: Os métodos .str automaticamente ignoram NaN — se a entrada for NaN, a saída é NaN. Não é necessário verificar manualmente a presença de valores ausentes. Esta é uma das razões pelas quais .str é mais conveniente do que usar apply + str do Python. Note que contains/match retornam False (não NaN) para valores NaN, então leve isso em consideração ao filtrar.

P: O que extract retorna? R: extract retorna um DataFrame — uma colura por grupo regex. Um único grupo resulta em um DataFrame de 1 coluna; múltiplos grupos resultam em múltiplas colunas. extractall retorna todas as correspondências (com um MultiIndex). Nota: linhas sem correspondência retornam NaN. Se precisar de uma Series, use .str.extract(...)[0].

P: Qual é a diferença entre contains e match? R: contains corresponde a qualquer lugar na string (ex: 'abc' contains 'b' → True). match corresponde apenas a partir do início da string (ex: 'abc' match 'b' → False). startswith/endswith são comparações de string simples (sem suporte a regex). Use contains/match quando precisar de regex, e startswith/endswith para verificações de texto simples.

P: Quais são os benefícios de StringDtype? R: Por padrão, colunas de string usam o dtype objeto (objetos Python), onde cada valor é uma instância de str separada. StringDtype (df['col'].astype('string')) é um tipo de string dedicado do Pandas que usa pd.NA para valores ausentes, é mais eficiente em memória e fornece um comportamento .str mais consistente. O Pandas 2.x recomenda StringDtype em vez de objeto para dados de string.

P: Qual é a diferença entre str.replace e df.replace? R: str.replace opera apenas em colunas de string, suporta regex (regex=True), e substitui elemento por elemento. df.replace opera em todo o DataFrame, pode substituir valores de qualquer tipo, e também suporta regex. Para substituição de string, prefira str.replace (semântica mais clara); para substituição entre colunas, use df.replace.

P: Como extrair dígitos de um número de telefone? R: Use s.str.replace(r'[^0-9]', '', regex=True) para remover todos os caracteres não numéricos. Alternativamente, use extract: s.str.extract(r'(\d{3})[-.)\s]*(\d{3})[-.)\s]*(\d{4})') para capturar o código de área, prefixo e número da linha separadamente. Expressões regulares são a ferramenta principal para extração de texto.


📖 Resumo


📝 Exercícios

  1. Básico (Dificuldade ⭐): Crie uma Series de nomes com espaços extras e capitalização inconsistente. Limpe-a com .str.strip().str.title(), depois conte quantos nomes limpos começam com 'A'.
  2. Intermediário (Dificuldade ⭐⭐): Crie uma Series de números de telefone em formatos mistos. Use replace + regex para extrair apenas os dígitos, depois formate-os para 10 caracteres com zfill.
  3. Desafio (Dificuldade ⭐⭐⭐): Simule dados de registro de usuário (nome/email/telefone/CEP todos com problemas de formatação). Construa um pipeline de limpeza encadeado de 5 etapas — um método .str por etapa — e exiba a tabela final limpa.

← Previous: Reshaping and Pivoting · Next: Date and Time →

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%