Bir sütundaki dizelerden istenmeyen parçaları nasıl kaldırırım?
Orijinal sorunun gönderilmesinden 6 yıl sonra, pandalar artık bu dizgi işleme işlemlerini kısa ve öz bir şekilde gerçekleştirebilen çok sayıda "vektörleştirilmiş" dizgi işlevine sahiptir.
Bu cevap, bu dizi işlevlerinden bazılarını keşfedecek, daha hızlı alternatifler önerecek ve sonunda bir zamanlama karşılaştırmasına girecektir.
Eşleşecek alt dizeyi / deseni ve bununla değiştirilecek alt dizeyi belirtin.
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
Sonucun bir tam sayıya dönüştürülmesine ihtiyacınız varsa, şunu kullanabilirsiniz Series.astype
:
df['result'] = df['result'].str.replace(r'\D', '').astype(int)
df.dtypes
time object
result int64
dtype: object
Yerinde değiştirmek istemiyorsanız df
, şunu kullanın DataFrame.assign
:
df2 = df.assign(result=df['result'].str.replace(r'\D', ''))
df
# Unchanged
Saklamak istediğiniz alt dizeleri çıkarmak için kullanışlıdır.
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
İle extract
en az bir yakalama grubu belirtmek gerekir. expand=False
ilk yakalama grubundan yakalanan öğelerle bir Seri döndürecektir.
Bölme, tüm dizelerinizin bu tutarlı yapıyı izlediğini varsayarak çalışır.
# 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
Genel bir çözüm arıyorsanız tavsiye etmeyin.
str
Yukarıdaki özlü ve okunabilir erişimci tabanlı çözümlerden memnunsanız, burada durabilirsiniz. Ancak, daha hızlı, daha performanslı alternatiflerle ilgileniyorsanız okumaya devam edin.
Optimize Etme: Anlaşmaları Listeleme
Bazı durumlarda, liste anlamaları pandaların dizgi işlevlerine tercih edilmelidir. Bunun nedeni, dize işlevlerinin doğal olarak vektörleştirilmesinin zor olmasıdır (kelimenin gerçek anlamıyla), bu nedenle çoğu dize ve düzenli ifade işlevi yalnızca daha fazla ek yüke sahip döngülerin etrafına sarılır.
Benim yazma-up, for-döngüler pandalar gerçekten kötü mü? Ne zaman umursamalıyım? , daha fazla ayrıntıya giriyor.
str.replace
Seçeneği kullanılarak yeniden yazılabilirre.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
İçeren bir liste kavrayışa yazılı yeniden örnek olabilir 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'ler veya eşleşmeyenler bir olasılıksa, bazı hata kontrollerini dahil etmek için yukarıdakileri yeniden yazmanız gerekecektir. Bunu bir işlev kullanarak yapıyorum.
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
Ayrıca @ eumiro'nun ve @ MonkeyButter'ın yanıtlarını liste anlamalarını kullanarak yeniden yazabiliriz:
df['result'] = [x.lstrip('+-').rstrip('aAbBcC') for x in df['result']]
Ve,
df['result'] = [x[1:-1] for x in df['result']]
NaN'leri vb. İşlemek için aynı kurallar geçerlidir.
Performans karşılaştırması
Performans grafiği kullanılarak oluşturulan grafikler . Referans için tam kod listesi. İlgili işlevler aşağıda listelenmiştir.
Bu karşılaştırmalardan bazıları haksızdır çünkü OP verilerinin yapısından yararlanırlar, ancak ondan ne isterseniz onu alırlar. Unutulmaması gereken bir nokta, her liste anlama işlevinin eşdeğer pandalar varyantından daha hızlı veya karşılaştırılabilir olmasıdır.
Fonksiyonlar
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']])