Bagaimana cara menghapus bagian yang tidak diinginkan dari string di kolom?
6 tahun setelah pertanyaan asli dikirimkan, panda sekarang memiliki sejumlah fungsi string "vectorised" yang dapat melakukan operasi manipulasi string ini secara ringkas.
Jawaban ini akan mengeksplorasi beberapa fungsi string ini, menyarankan alternatif yang lebih cepat, dan masuk ke perbandingan timing di bagian akhir.
Tentukan substring / pola yang cocok, dan substring untuk menggantinya.
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
Jika Anda membutuhkan hasil yang dikonversi ke integer, Anda dapat menggunakan Series.astype
,
df['result'] = df['result'].str.replace(r'\D', '').astype(int)
df.dtypes
time object
result int64
dtype: object
Jika Anda tidak ingin memodifikasi df
di tempat, gunakan DataFrame.assign
:
df2 = df.assign(result=df['result'].str.replace(r'\D', ''))
df
# Unchanged
Berguna untuk mengekstraksi substring yang ingin Anda pertahankan.
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
Dengan extract
, perlu menentukan setidaknya satu grup tangkap. expand=False
akan mengembalikan Seri dengan item yang diambil dari grup tangkapan pertama.
Pekerjaan pemisahan dengan asumsi semua string Anda mengikuti struktur yang konsisten ini.
# 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
Jangan rekomendasikan jika Anda mencari solusi umum.
Jika Anda puas dengan str
solusi berbasis accessor yang ringkas dan mudah dibaca , Anda bisa berhenti di sini. Namun, jika Anda tertarik pada alternatif yang lebih cepat dan lebih berkinerja, teruslah membaca.
Mengoptimalkan: Daftar Pemahaman
Dalam beberapa keadaan, pemahaman daftar harus lebih disukai daripada fungsi string panda. Alasannya adalah karena fungsi string secara inheren sulit untuk di-vektorisasi (dalam arti sebenarnya dari kata itu), sehingga sebagian besar fungsi string dan regex hanya membungkus loop dengan lebih banyak overhead.
Tulisan saya, Apakah for-loop di panda benar-benar buruk? Kapan saya harus peduli? , masuk ke detail yang lebih besar.
The str.replace
pilihan dapat ditulis ulang menggunakanre.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
The str.extract
contoh dapat ditulis ulang menggunakan pemahaman daftar dengan 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
Jika NaN atau tidak-cocok adalah suatu kemungkinan, Anda harus menulis ulang di atas untuk memasukkan beberapa pengecekan kesalahan. Saya melakukan ini menggunakan fungsi.
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
Kami juga dapat menulis ulang jawaban @ eumiro dan @ MonkeyButter menggunakan daftar pemahaman:
df['result'] = [x.lstrip('+-').rstrip('aAbBcC') for x in df['result']]
Dan,
df['result'] = [x[1:-1] for x in df['result']]
Aturan yang sama untuk menangani NaN, dll, berlaku.
Perbandingan Kinerja
Grafik yang dihasilkan menggunakan perfplot . Daftar kode lengkap, untuk referensi Anda. Fungsi yang relevan tercantum di bawah ini.
Beberapa perbandingan ini tidak adil karena mereka mengambil keuntungan dari struktur data OP, tetapi ambil darinya apa yang Anda mau. Satu hal yang perlu diperhatikan adalah bahwa setiap fungsi pemahaman daftar lebih cepat atau sebanding dengan varian pandanya.
Fungsi
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']])