Удалить ненужные части из строк в столбце

Я ищу эффективный способ удаления ненужных деталей из строк в столбце DataFrame.

Данные выглядят следующим образом:

    time    result
1    09:00   +52A
2    10:00   +62B
3    11:00   +44a
4    12:00   +30b
5    13:00   -110a

Мне нужно обрезать эти данные:

    time    result
1    09:00   52
2    10:00   62
3    11:00   44
4    12:00   30
5    13:00   110

Я пробовал .str.lstrip('+-') и. str.rstrip('aAbBcC'), но получил ошибку:

TypeError: wrapper() takes exactly 1 argument (2 given)

Любые указатели будут очень благодарны!

Ответ 1

data['result'] = data['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC'))

Ответ 2

Я бы использовал функцию замены pandas, очень простую и мощную, так как вы можете использовать регулярное выражение. Ниже я использую regex\D для удаления любых символов, отличных от цифр, но, очевидно, вы можете получить довольно творческий подход с регулярным выражением.

data['result'].replace(regex=True,inplace=True,to_replace=r'\D',value=r'')

Ответ 3

В конкретном случае, когда вы знаете количество позиций, которые хотите удалить из столбца dataframe, вы можете использовать индексирование строк внутри лямбда-функции, чтобы избавиться от этих частей:

Последний символ:

data['result'] = data['result'].map(lambda x: str(x)[:-1])

Первые два символа:

data['result'] = data['result'].map(lambda x: str(x)[2:])

Ответ 4

Здесь есть ошибка: в настоящее время нельзя передать аргументы str.lstrip и str.rstrip:

http://github.com/pydata/pandas/issues/2411

EDIT: 2012-12-07 это работает теперь в ветке dev:

In [8]: df['result'].str.lstrip('+-').str.rstrip('aAbBcC')
Out[8]: 
1     52
2     62
3     44
4     30
5    110
Name: result

Ответ 5

Как удалить ненужные части из строк в столбце?

Спустя 6 лет после того, как оригинальный вопрос был опубликован, у pandas теперь есть большое количество "векторизованных" строковых функций, которые могут кратко выполнять эти операции манипуляции со строками.

В этом ответе будут рассмотрены некоторые из этих строковых функций, предложены более быстрые альтернативы и проведено сравнение по времени в конце.


.str.replace

Укажите подстроку/шаблон для сопоставления и подстроку для замены.

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

.str.extract

Полезно для извлечения подстроки, которую вы хотите сохранить.

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 вернет Серию с захваченными предметами из первой группы захвата.


.str.split и .str.get

Разделение работает, если все ваши строки следуют этой последовательной структуре.

# 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 доступа str приведенными выше, вы можете остановиться здесь. Однако, если вас интересуют более быстрые и производительные альтернативы, продолжайте читать.


Оптимизация: список понимания

В некоторых обстоятельствах, списки должны быть предпочтительнее строковых функций панд. Причина в том, что строковые функции по своей природе трудно векторизовать (в истинном смысле этого слова), поэтому большинство строковых и регулярных выражений являются только обертками вокруг циклов с большими накладными расходами.

Моя статья, Для петель с пандами - Когда мне это нужно? подробнее.

Опция 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 и т.д.


Сравнение производительности

enter image description here

Графики созданы с использованием перфплота. Полный список кодов, для вашей справки. Соответствующие функции перечислены ниже.

Некоторые из этих сравнений несправедливы, потому что они используют в своих интересах структуру данных OP, но берут из этого, что вы будете. Следует отметить, что каждая функция понимания списка является либо более быстрой, либо сопоставимой, чем ее эквивалентный вариант панд.

функции

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']])

Ответ 6

Очень простой метод - использовать метод extract для выбора всех цифр. Просто предоставьте ему регулярное выражение '\d+' которое извлекает любое количество цифр.

df['result'] = df.result.str.extract(r'(\d+)', expand=True).astype(int)
df

    time  result
1  09:00      52
2  10:00      62
3  11:00      44
4  12:00      30
5  13:00     110

Ответ 7

Я часто использую списки для этих задач, потому что они часто бывают быстрее.

Могут быть большие различия в производительности между различными методами для выполнения подобных действий (т.е. Изменение каждого элемента серии в пределах DataFrame). Часто понимание списка может быть самым быстрым - смотрите код гонки ниже для этой задачи:

import pandas as pd
#Map
data = pd.DataFrame({'time':['09:00','10:00','11:00','12:00','13:00'], 'result':['+52A','+62B','+44a','+30b','-110a']})
%timeit data['result'] = data['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC'))
10000 loops, best of 3: 187 µs per loop
#List comprehension
data = pd.DataFrame({'time':['09:00','10:00','11:00','12:00','13:00'], 'result':['+52A','+62B','+44a','+30b','-110a']})
%timeit data['result'] = [x.lstrip('+-').rstrip('aAbBcC') for x in data['result']]
10000 loops, best of 3: 117 µs per loop
#.str
data = pd.DataFrame({'time':['09:00','10:00','11:00','12:00','13:00'], 'result':['+52A','+62B','+44a','+30b','-110a']})
%timeit data['result'] = data['result'].str.lstrip('+-').str.rstrip('aAbBcC')
1000 loops, best of 3: 336 µs per loop

Ответ 8

=RIGHT(LEFT(O13,(LEN(O13)-1)),LEN(LEFT(O13,(LEN(O13)-1))-1))

Поместите это право из столбца результата и получите результат.