Текстовые столбцы: нормализация и разбор через .str
Содержание курса
Нормализация текста: .str.lower, .str.strip, .str.replace
Самая частая причина, по которой одинаковые значения не совпадают при сравнении — это лишние пробелы и разный регистр. Строки 'Alice', ' alice ' и 'ALICE' для Python разные, хотя по смыслу одно и то же. Три метода закрывают этот класс проблем.
.str.strip() убирает пробельные символы с обоих концов строки — пробелы, табуляции, переносы строк. Если нужно чистить только одну сторону, есть .str.lstrip() (левый конец) и .str.rstrip() (правый).
.str.lower() приводит все символы к нижнему регистру. Для верхнего — .str.upper(), для заглавной первой буквы — .str.capitalize().
.str.replace(pat, repl) заменяет вхождения pat на repl. В pandas 2.x параметр regex=False по умолчанию, то есть pat трактуется буквально.
На практике эти три метода почти всегда идут цепочкой:
import pandas as pd
df = pd.DataFrame({
'name': [' Alice Smith ', ' BOB jones', 'carol BROWN ']
})
df['name_clean'] = df['name'].str.strip().str.lower()
print(df['name_clean'].tolist())
# ['alice smith', 'bob jones', 'carol brown']
Сначала снимаем пробелы по краям, потом приводим к нижнему регистру. Порядок здесь не критичен для этих двух методов, но привычка ставить strip первым полезна: тогда последующие операции работают с уже чистым текстом.
Для замены, например, дефисов на подчёркивания:
df['name_underscored'] = df['name_clean'].str.replace(' ', '_', regex=False)
print(df['name_underscored'].tolist())
# ['alice_smith', 'bob_jones', 'carol_brown']
Ловушка с regex в .str.replace и .str.contains. Здесь легко ошибиться, потому что у двух методов разные дефолты.
В .str.replace — regex=False по умолчанию. Это значит, что строка '.' будет искаться буквально как точка, а не как «любой символ» из регулярных выражений. Если вы хотите использовать паттерн вроде r'\s+', нужно явно написать regex=True.
В .str.contains — наоборот, regex=True по умолчанию. Паттерн '.' там найдёт что угодно, потому что точка в регулярных выражениях означает любой символ.
Антипример:
s = pd.Series(['3.14', '314', 'abc'])
# Хотим найти строки с буквальной точкой:
print(s.str.contains('.')) # regex=True по умолчанию — найдёт всё!
# 0 True
# 1 True
# 2 True
print(s.str.contains('.', regex=False)) # правильно — только '3.14'
# 0 True
# 1 False
# 2 False
Правило простое: для буквального поиска в .str.contains всегда передавайте regex=False. Для .str.replace с простой подстрокой regex=False уже стоит по умолчанию и менять его не нужно.
Каждый вызов возвращает новый Series — исходный столбец не затрагивается. Если результат нужен в таблице, присваивайте явно: df['col'] = df['col'].str.strip().
