Как удалить ненужные части из строк в столбце?
Через 6 лет после того, как был опубликован исходный вопрос, у pandas теперь есть большое количество «векторизованных» строковых функций, которые могут кратко выполнять эти операции манипулирования строками.
В этом ответе будут рассмотрены некоторые из этих строковых функций, предложены более быстрые альтернативы и в конце будет проведено сравнение таймингов.
Укажите подстроку / шаблон для сопоставления и подстроку для замены.
pd.__version__
# '0.24.1'
df
time result
1 09:00 +52A
2 10:00 +62B
3 11:00 +44a
4 12:00 +30b
5 13:00 -110a
df['result'] = df['result'].str.replace(r'\D', '')
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
Если вам нужно преобразовать результат в целое число, вы можете использовать Series.astype
,
df['result'] = df['result'].str.replace(r'\D', '').astype(int)
df.dtypes
time object
result int64
dtype: object
Если вы не хотите изменять df
на месте, используйте DataFrame.assign
:
df2 = df.assign(result=df['result'].str.replace(r'\D', ''))
df
# Unchanged
Полезно для извлечения подстрок, которые вы хотите сохранить.
df['result'] = df['result'].str.extract(r'(\d+)', expand=False)
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
С extract
необходимо указать хотя бы одну группу захвата. expand=False
вернет серию с захваченными элементами из первой группы захвата.
Разделение работает при условии, что все ваши строки следуют этой согласованной структуре.
# df['result'] = df['result'].str.split(r'\D').str[1]
df['result'] = df['result'].str.split(r'\D').str.get(1)
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
Не рекомендую, если вы ищете общее решение.
Если вас устраивают лаконичные и удобочитаемые str
решения на основе аксессуаров, описанные выше, вы можете здесь остановиться. Однако, если вас интересуют более быстрые и производительные альтернативы, продолжайте читать.
Оптимизация: составление списков
В некоторых случаях понимание списка должно быть предпочтительнее строковых функций pandas. Причина в том, что строковые функции по своей природе трудно векторизовать (в истинном смысле этого слова), поэтому большинство строковых и регулярных функций являются только оболочками вокруг циклов с большими накладными расходами.
Моя рецензия, действительно ли циклы for в пандах плохи? Когда мне нужно заботиться? , более подробно.
str.replace
Опция может быть переписана с использованиемre.sub
import re
# Pre-compile your regex pattern for more performance.
p = re.compile(r'\D')
df['result'] = [p.sub('', x) for x in df['result']]
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
str.extract
Пример может быть переписан с использованием списка понимание с re.search
,
p = re.compile(r'\d+')
df['result'] = [p.search(x)[0] for x in df['result']]
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
Если возможны NaN или несоответствия, вам нужно будет переписать приведенное выше, чтобы включить проверку ошибок. Я делаю это с помощью функции.
def try_extract(pattern, string):
try:
m = pattern.search(string)
return m.group(0)
except (TypeError, ValueError, AttributeError):
return np.nan
p = re.compile(r'\d+')
df['result'] = [try_extract(p, x) for x in df['result']]
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
Мы также можем переписать ответы @ eumiro и @ MonkeyButter, используя списки:
df['result'] = [x.lstrip('+-').rstrip('aAbBcC') for x in df['result']]
И,
df['result'] = [x[1:-1] for x in df['result']]
Применяются те же правила для обработки NaN и т. Д.
Сравнение производительности
Графики, созданные с помощью perfplot . Полный список кодов для справки. Соответствующие функции перечислены ниже.
Некоторые из этих сравнений несправедливы, потому что они используют структуру данных OP, но извлекайте из нее все, что хотите. Следует отметить, что каждая функция понимания списка либо быстрее, либо сравнима, чем ее эквивалентный вариант pandas.
функции
def eumiro(df):
return df.assign(
result=df['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC')))
def coder375(df):
return df.assign(
result=df['result'].replace(r'\D', r'', regex=True))
def monkeybutter(df):
return df.assign(result=df['result'].map(lambda x: x[1:-1]))
def wes(df):
return df.assign(result=df['result'].str.lstrip('+-').str.rstrip('aAbBcC'))
def cs1(df):
return df.assign(result=df['result'].str.replace(r'\D', ''))
def cs2_ted(df):
# `str.extract` based solution, similar to @Ted Petrou's. so timing together.
return df.assign(result=df['result'].str.extract(r'(\d+)', expand=False))
def cs1_listcomp(df):
return df.assign(result=[p1.sub('', x) for x in df['result']])
def cs2_listcomp(df):
return df.assign(result=[p2.search(x)[0] for x in df['result']])
def cs_eumiro_listcomp(df):
return df.assign(
result=[x.lstrip('+-').rstrip('aAbBcC') for x in df['result']])
def cs_mb_listcomp(df):
return df.assign(result=[x[1:-1] for x in df['result']])