Работа с текстовыми колонками в Pandas: символьные данные и их преобразование
Основные подходы к обработке строк в Pandas
Наиболее эффективный способ
Как быстро применить строковую операцию ко всем элементам столбца?
Для векторизованной обработки строк используется аксессор .str. Он предоставляет методы, подобные строковым методам Python, но работающие с Series.
import pandas as pd
df = pd.DataFrame({'text': ['Hello', 'WORLD', 'pYTHON', None]})
df['lower'] = df['text'].str.lower()
print(df)обработка больших данных python (обработка больших данных в python)
text lower 0 Hello hello 1 WORLD world 2 pYTHON python 3 None None
очистка данных python (очистка данных в python)
Метод .str.lower() автоматически обрабатывает пропущенные значения (NaN) без ошибок. Доступны также .str.upper(), .str.title(), .str.capitalize() и другие.
Типичная ошибка:
Попытка вызвать .str на столбце, содержащем нестроковые типы (например, числа), приведет к ошибке AttributeError: 'Series' object has no attribute 'str'. Перед использованием рекомендуется убедиться, что тип данных столбца - object или string. Для преобразования можно выполнить df['col'] = df['col'].astype(str).
Как применить кастомную функцию к каждой строке?
Если нужной операции нет среди методов .str, можно использовать .apply().
def custom_clean(s):
if s is None:
return s
return s.replace(' ', '_').upper()
df['cleaned'] = df['text'].apply(custom_clean)
print(df)
Python подготовка данных (подготовка данных в python)
text lower cleaned 0 Hello hello HELLO 1 WORLD world WORLD 2 pYTHON python PYTHON 3 None None None
работа с dataframe python (работа с dataframe в python)
Важно: .apply() медленнее векторизованных методов и может вызвать исключение при работе с NaN, если функция их не обрабатывает. В примере выше проверка if s is None предотвращает ошибку.
Как извлечь часть строки по шаблону с помощью регулярных выражений?
Метод .str.extract() позволяет извлечь подстроки, соответствующие регулярному выражению.
df = pd.DataFrame({'email': ['user@example.com', 'admin@site.org', 'bad-email']})
df[['username','domain']] = df['email'].str.extract(r'([^@]+)@([^@]+)')
print(df)Python работа с большими данными (работа с большими данными в python)
email username domain 0 user@example.com user example.com 1 admin@site.org admin site.org 2 bad-email NaN NaN
структурированные данные python (структурированные данные в python)
Если шаблон не найден, подставляется NaN. Для нескольких совпадений подойдёт .str.extractall().
Когда стоит использовать list comprehension вместо apply?
Для простых преобразований list comprehension может работать быстрее .apply().
df['upper_lc'] = [x.upper() if x is not None else None for x in df['text']]
print(df)генерация данных python (генерация данных в python)
text lower cleaned upper_lc 0 Hello hello HELLO HELLO 1 WORLD world WORLD WORLD 2 pYTHON python PYTHON PYTHON 3 None None None None
Python код символа (код символа в python)
Недостаток: list comprehension не интегрируется с индексами DataFrame и не поддерживает автоматическую обработку NaN. При работе с большими данными векторизованные методы .str все же предпочтительнее.
Как обработать целый столбец с помощью строковых методов numpy?
Векторизованные строковые методы numpy можно применить через np.vectorize, но такой подход обычно медленнее .str и редко используется.
Проблема: NaN в строковых операциях
При использовании .str NaN остаются NaN без ошибок. Однако в .apply() необходима явная проверка. Решение: использовать pd.notna() или проверять if pd.isna(x).
def safe_upper(x):
if pd.isna(x):
return x
return x.upper()
df['upper_safe'] = df['text'].apply(safe_upper)В качестве альтернативы можно удалить или заполнить пропуски перед обработкой.
Расширенные примеры обработки строк в Pandas
Разделение строк на части и создание новых строк
Метод .str.split() возвращает списки, а .str.explode() превращает их в отдельные строки.
df = pd.DataFrame({'tags': ['a,b,c', 'd,e', 'f']})
df_exp = df['tags'].str.split(',').explode()
print(df_exp)0 a 0 b 0 c 1 d 1 e 2 f dtype: object
Применение: нормализация тегов, создание long format.
Объединение строк столбца с разделителем
.str.cat() объединяет строки столбца в одну строку с разделителем.
df = pd.DataFrame({'word': ['Python', 'Pandas', 'Data']})
combined = df['word'].str.cat(sep=' - ')
print(combined)Python - Pandas - Data
Также можно объединить два столбца поэлементно: df['col1'].str.cat(df['col2'], sep=' ').
Поиск всех вхождений шаблона в строке
.str.findall() возвращает список всех совпадений.
df = pd.DataFrame({'text': ['apple 123', 'banana 456', 'cherry']})
df['numbers'] = df['text'].str.findall(r'\d+')
print(df)text numbers 0 apple 123 [123] 1 banana 456 [456] 2 cherry []
Если нужны просто индексы первого вхождения, используется .str.find().
Удаление лишних пробелов и заполнение пробелами до заданной длины
.str.strip() удаляет пробелы, .str.pad() добавляет пробелы до ширины.
df = pd.DataFrame({'code': [' abc ', 'def', ' ghi ']})
df['stripped'] = df['code'].str.strip()
df['padded'] = df['code'].str.pad(10, side='left', fillchar=' ')
print(df)code stripped padded 0 abc abc abc 1 def def def 2 ghi ghi ghi
Следует помнить: .str.strip() работает только с пробельными символами; для других символов применяется .str.strip(символы).
Извлечение данных с помощью именованных групп в регулярных выражениях
.str.extract() поддерживает именованные группы, что удобно для именования столбцов.
df = pd.DataFrame({'log': ['2024-01-01 INFO message', '2024-01-02 ERROR fatal']})
df_ext = df['log'].str.extract(r'(?P\d{4}-\d{2}-\d{2})\s+(?P\w+)\s+(?P.+)')
print(df_ext) date level msg 0 2024-01-01 INFO message 1 2024-01-02 ERROR fatal
Удаление символов с помощью translate
.str.translate() эффективен для замены набора символов по таблице.
import string
table = str.maketrans('', '', string.punctuation)
df = pd.DataFrame({'text': ['Hello! How are you?', 'Python: powerful.']})
df['clean'] = df['text'].str.translate(table)
print(df)text clean 0 Hello! How are you? Hello How are you 1 Python: powerful. Python powerful
Таблицы можно создавать и для замены символов, а не только удаления.
Нормализация юникодных строк (например, приведение к одному виду)
.str.normalize() преобразует Unicode строки в заданную форму (NFC, NFD и т.д.).
df = pd.DataFrame({'text': ['café', 'cafe\u0301']}) # два представления 'café'
df['norm'] = df['text'].str.normalize('NFC')
print(df['norm'].iloc[0] == df['norm'].iloc[1])True
Полезно при сравнении строк, полученных из разных источников.
Проверка строки на соответствие шаблону с помощью str.match и str.fullmatch
.str.match() ищет совпадение с начала строки, .str.fullmatch() требует совпадение всей строки.
df = pd.DataFrame({'id': ['A123', 'B456', 'C78']})
df['match_A'] = df['id'].str.match(r'A\d+')
df['full_alpha'] = df['id'].str.fullmatch(r'[A-Z]\d+')
print(df)id match_A full_alpha 0 A123 True True 1 B456 False True 2 C78 False False
Отличие от .str.contains(): .match() не требует специальных обозначений, проверяет с начала.
Сложная логика с комбинацией методов
Часто требуется несколько преобразований последовательно: lower, удалить знаки, split, взять первый элемент.
df = pd.DataFrame({'raw': [' Python! ', ' Data Science? ', ' Machine- Learning ']})
df['processed'] = (df['raw']
.str.strip()
.str.lower()
.str.replace('[!?\-]', '', regex=True)
.str.split('\s+') # разбиваем по пробелам
.str[0] # первое слово
)
print(df)raw processed 0 Python! python 1 Data Science? data 2 Machine- Learning machine
Такая цепочка читается легко и выполняется быстро благодаря векторизации.
Примечание: при большом количестве операций с регулярными выражениями производительность может снизиться, но для большинства задач этого достаточно.