Usuń niechciane części z łańcuchów w kolumnie
Szukam skutecznego sposobu na usunięcie niechcianych części z łańcuchów w kolumnie DataFrame.
Dane wyglądają następująco:
time result
1 09:00 +52A
2 10:00 +62B
3 11:00 +44a
4 12:00 +30b
5 13:00 -110a
Muszę przyciąć te dane do:
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
Próbowałem .str.lstrip('+-')
i .str.rstrip('aAbBcC')
, ale mam błąd:
TypeError: wrapper() takes exactly 1 argument (2 given)
Wszelkie wskazówki będą bardzo mile widziane!
9 answers
data['result'] = data['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC'))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-03 11:33:51
Jak usunąć niechciane części z napisów w kolumnie?
6 lat po opublikowaniu pierwotnego pytania, pandas ma teraz dużą liczbę" wektoryzowanych " funkcji ciągów, które mogą zwięźle wykonywać te operacje manipulacji ciągami.
Ta odpowiedź przeanalizuje niektóre z tych funkcji ciągów, zaproponuje szybsze alternatywy i przejdzie do porównania czasów na końcu.
.str.replace
Określ podłańcuch / wzorzec do dopasowania i podłańcuch do zastąpienia.
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
Jeśli potrzebujesz wyniku przekonwertowanego na liczbę całkowitą, możesz użyć Series.astype
,
df['result'] = df['result'].str.replace(r'\D', '').astype(int)
df.dtypes
time object
result int64
dtype: object
Jeśli nie chcesz modyfikować df
in-place, użyj DataFrame.assign
:
df2 = df.assign(result=df['result'].str.replace(r'\D', ''))
df
# Unchanged
.str.extract
Przydatne do wyodrębniania podłańcuchów, które chcesz zachować.
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
Z extract
, konieczne jest określenie co najmniej jednej grupy przechwytywania. expand=False
zwróci serię z przechwyconymi przedmiotami z pierwszej grupy przechwytywania.
.str.split
oraz .str.get
Dzielenie działa zakładając, że wszystkie Twoje ciągi podążają za tą spójną strukturą.
# 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
Nie zaleca się, jeśli szukasz ogólnego rozwiązania.
Jeśli jesteś zadowolony z zwięzłego i czytelnego
str
rozwiązania oparte na accessorze powyżej, można zatrzymać tutaj. Jednakże, jeśli jesteś zainteresowanych szybszymi, bardziej wydajnymi alternatywami, Czytaj dalej.
Optymalizacja: Składanie List
W pewnych okolicznościach, składanie list powinno być preferowane w stosunku do funkcji łańcuchowych pandas. Powodem jest to, że funkcje string są z natury trudne do wektoryzacji( w prawdziwym tego słowa znaczeniu), więc większość funkcji string i regex są tylko owijaczami wokół pętli z większym obciążeniem.
Moje zapiski, są dla-pętli w pandy naprawdę źle? Kiedy powinno mnie to obchodzić?, idzie bardziej szczegółowo.
Opcja str.replace
może być zapisana ponownie za pomocą 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
Przykład str.extract
może być napisany na nowo przy użyciu listy z 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
Jeśli istnieje możliwość Nan lub no-matching, musisz ponownie napisać powyższe, aby uwzględnić pewne sprawdzanie błędów. Robię to za pomocą funkcji.
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
Możemy również ponownie napisać odpowiedzi @ eumiro i @ MonkeyButter za pomocą listy skład:
df['result'] = [x.lstrip('+-').rstrip('aAbBcC') for x in df['result']]
I,
df['result'] = [x[1:-1] for x in df['result']]
Obowiązują te same zasady obsługi Nan itp.
Porównanie Wydajności
Wykresy generowane za pomocą perfplot . pełna lista kodów, w celach informacyjnych. odpowiednie funkcje są wymienione poniżej.
Niektóre z tych porównań są niesprawiedliwe, ponieważ wykorzystują strukturę danych OP, ale biorą z niej to, co chcesz. Należy pamiętać, że że każda funkcja rozumienia listy jest albo szybsza, albo porównywalna od jej równoważnego wariantu.
Funkcje
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']])
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-10 03:31:52
Użyłbym funkcji pandy replace, bardzo prostej i potężnej, ponieważ można użyć regex. Poniżej używam regex \d, aby usunąć wszelkie znaki niecyfrowe, ale oczywiście można uzyskać dość twórczy z regex.
data['result'].replace(regex=True,inplace=True,to_replace=r'\D',value=r'')
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-31 14:57:04
W konkretnym przypadku, gdy znasz liczbę pozycji, które chcesz usunąć z kolumny dataframe, możesz użyć indeksowania łańcuchowego wewnątrz funkcji lambda, aby pozbyć się tych części:
Ostatni znak:
data['result'] = data['result'].map(lambda x: str(x)[:-1])
Pierwsze dwa znaki:
data['result'] = data['result'].map(lambda x: str(x)[2:])
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-06 23:27:54
Jest tu błąd: obecnie nie można przekazać argumentów do str.lstrip
i str.rstrip
:
Http://github.com/pydata/pandas/issues/2411
EDIT: 2012-12-07 to działa teraz na gałęzi dev:
In [8]: df['result'].str.lstrip('+-').str.rstrip('aAbBcC')
Out[8]:
1 52
2 62
3 44
4 30
5 110
Name: result
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-07 16:31:06
Bardzo prostą metodą byłoby użycie metody extract
do wybrania wszystkich cyfr. Wystarczy podać Wyrażenie regularne '\d+'
, które wyciąga dowolną liczbę cyfr.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-22 05:58:39
Często używam zestawień list do tego typu zadań, ponieważ często są szybsze.
Mogą występować duże różnice w wydajności pomiędzy różnymi metodami wykonywania takich rzeczy (tj. modyfikowanie każdego elementu serii w ramce danych). Często zrozumienie listy może być najszybsze-zobacz kod wyścigu poniżej dla tego zadania:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-11 06:44:43
Załóżmy, że Twój DF ma również te Dodatkowe znaki pomiędzy liczbami.Ostatni wpis.
result time
0 +52A 09:00
1 +62B 10:00
2 +44a 11:00
3 +30b 12:00
4 -110a 13:00
5 3+b0 14:00
Możesz spróbować str.zastąp, aby usunąć znaki nie tylko od początku i końca, ale także od środka.
DF['result'] = DF['result'].str.replace('\+|a|b|\-|A|B', '')
Wyjście:
result time
0 52 09:00
1 62 10:00
2 44 11:00
3 30 12:00
4 110 13:00
5 30 14:00
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-15 04:24:22
Spróbuj użyć wyrażenia regularnego:
import re
data['result'] = data['result'].map(lambda x: re.sub('[-+A-Za-z]',x)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-11 07:08:13