#7 - Trabalhando com Texto e Dados Categóricos no Pandas

Como manipular texto com o acessor .str do Pandas e usar dados categóricos com astype('category') para economizar memória.

#7 - Trabalhando com Texto e Dados Categóricos no Pandas

Até aqui a série tratou principalmente de números — médias, somas, correlações. Mas boa parte dos dados do mundo real é texto: nomes, categorias, descrições, códigos. Neste post você vai ver como o Pandas trata colunas de texto através do acessor .str, e como representar valores que se repetem bastante (como categorias) de um jeito mais eficiente, com o tipo category.

O acessor .str

Colunas de texto num DataFrame são armazenadas como object (ou string, em versões mais recentes do Pandas). Pra aplicar métodos de string a uma coluna inteira de uma vez — sem escrever um loop — o Pandas oferece o acessor .str, que dá acesso a praticamente todos os métodos de string do Python, aplicados elemento a elemento.

import pandas as pd

dados = {
    "nome": ["  Ana Silva", "bruno costa", "CARLA MENDES  ", "Diego Alves"],
    "email": ["[email protected]", "[email protected]", "[email protected]", "[email protected]"]
}

df = pd.DataFrame(dados)

Exemplo 1 - maiúsculas, minúsculas e espaços

df["nome_limpo"] = df["nome"].str.strip().str.title()
print(df["nome_limpo"])

A saída é:

0       Ana Silva
1     Bruno Costa
2    Carla Mendes
3     Diego Alves
Name: nome_limpo, dtype: object

.strip() remove espaços em branco do início e do fim de cada valor, e .title() deixa a primeira letra de cada palavra maiúscula — os métodos encadeiam normalmente, já que cada um devolve uma nova Series de texto.

Exemplo 2 - padronizando e-mails

df["email"] = df["email"].str.lower()
print(df["email"])
0      ana@empresa.com
1    bruno@empresa.com
2    carla@empresa.com
3    diego@empresa.com
Name: email, dtype: object

Exemplo 3 - contando caracteres com len()

print(df["nome_limpo"].str.len())
0     9
1    11
2    12
3    11
Name: nome_limpo, dtype: int64

Exemplo 4 - verificando conteúdo com contains()

.str.contains() devolve uma máscara booleana, útil pra filtrar linhas — o mesmo tipo de máscara que você já viu no post sobre seleção e filtragem:

tem_costa = df["nome_limpo"].str.contains("Costa")
print(df[tem_costa])
          nome         email    nome_limpo
1  bruno costa  bruno@empresa.com  Bruno Costa

Exemplo 5 - substituindo texto com replace()

dominio_novo = df["email"].str.replace("empresa.com", "novaempresa.com")
print(dominio_novo)
0      ana@novaempresa.com
1    bruno@novaempresa.com
2    carla@novaempresa.com
3    diego@novaempresa.com
Name: email, dtype: object

Exemplo 6 - dividindo texto com split()

.str.split() quebra cada valor em uma lista, usando o separador informado (por padrão, espaço em branco):

partes = df["nome_limpo"].str.split(" ")
print(partes)
0       [Ana, Silva]
1     [Bruno, Costa]
2    [Carla, Mendes]
3     [Diego, Alves]
Name: nome_limpo, dtype: object

Passando expand=True, cada parte vira uma coluna própria, em vez de ficar dentro de uma lista:

df[["primeiro_nome", "sobrenome"]] = df["nome_limpo"].str.split(" ", expand=True)
print(df[["primeiro_nome", "sobrenome"]])
  primeiro_nome sobrenome
0           Ana     Silva
1         Bruno     Costa
2         Carla    Mendes
3         Diego     Alves

Nota: todos os métodos de .str ignoram valores NaN automaticamente, sem gerar erro — uma célula vazia numa coluna de texto continua NaN depois de qualquer operação .str, em vez de quebrar o processamento das demais linhas.

Dados categóricos

Algumas colunas de texto não representam um valor livre, mas uma de um conjunto pequeno e fixo de categorias — status de um pedido ("pendente", "enviado", "entregue"), tamanho de uma peça de roupa ("P", "M", "G"), avaliação ("ruim", "médio", "bom", "ótimo"). Pra esse tipo de coluna, o Pandas tem um tipo dedicado: category.

Exemplo 7 - convertendo uma coluna pra category

dados_pedidos = {
    "pedido": [1, 2, 3, 4, 5],
    "status": ["enviado", "pendente", "entregue", "enviado", "entregue"]
}

df_pedidos = pd.DataFrame(dados_pedidos)
df_pedidos["status"] = df_pedidos["status"].astype("category")

print(df_pedidos["status"])
print(df_pedidos.dtypes)

A saída é:

0     enviado
1    pendente
2    entregue
3     enviado
4    entregue
Name: status, dtype: category
Categories (3, object): ['entregue', 'enviado', 'pendente']

pedido       int64
status     category
dtype: object

Por baixo dos panos, o Pandas passa a guardar só um código numérico por linha (referenciando uma lista fixa de categorias), em vez do texto repetido em cada célula — o que economiza bastante memória em colunas com poucos valores distintos e muitas linhas.

Exemplo 8 - impondo uma ordem lógica

Por padrão, as categorias não têm uma ordem — mas casos como “tamanho” ou “avaliação” têm uma ordem natural que faz sentido preservar. Isso é feito com CategoricalDtype:

from pandas.api.types import CategoricalDtype

ordem_tamanhos = CategoricalDtype(categories=["P", "M", "G", "GG"], ordered=True)

df_produtos = pd.DataFrame({"produto": ["Camisa", "Calça", "Jaqueta"], "tamanho": ["M", "GG", "P"]})
df_produtos["tamanho"] = df_produtos["tamanho"].astype(ordem_tamanhos)

print(df_produtos.sort_values("tamanho"))
   produto tamanho
2  Jaqueta       P
0   Camisa       M
1    Calça      GG

Com ordered=True, o .sort_values() ordena pela sequência lógica definida em categories (P < M < G < GG), em vez da ordem alfabética que você teria com uma coluna de texto comum (onde "GG" viria antes de "M" e "P").

Exemplo 9 - comparando categorias ordenadas

Categorias ordenadas também aceitam operadores de comparação diretamente:

print(df_produtos["tamanho"] > "M")
0    False
1     True
2    False
Name: tamanho, dtype: bool

A comparação segue a ordem lógica definida (P < M < G < GG), não a ordem alfabética — é por isso que "GG" (índice 1) é considerado maior que "M".

Com o .str e o tipo category no repertório, você já consegue tratar tanto texto livre quanto categorias com ordem própria. No próximo — e último post desta leva — o assunto é datas: como o Pandas representa datas e séries temporais, e como usá-las como índice de um DataFrame.

Fonte adaptada: Pandas - Working with Text Data, Pandas - Categorical Data, Pandas - Ordering and Sorting Categorical Data