Mô tả bài toán
Cho Series chứa chuỗi ngày tháng:
0 2010-03-12 1 2011-3-1 2 2020-10-10 3 11-2-2
Yêu cầu: Lọc chỉ các chuỗi đúng định dạng YYYY-MM-DD (4 chữ số năm, 2 chữ số tháng, 2 chữ số ngày, phân cách bằng dấu gạch ngang). Kết quả: index 0 và 2.
Giải pháp 1: Regex kiểm tra định dạng (cách gốc)
Regex: r'\d{4}\W\d{2}\W\d{2}' - 4 số, phân cách không phải chữ/số, 2 số, phân cách, 2 số.
import pandas as pd
import re
l = ['2010-03-12','2011-3-1','2020-10-10','11-2-2']
data = pd.Series(l)
# Cách 1: Vòng lặp
print("Cách 1 - Vòng lặp:")
for idx, val in data.items():
if re.match(r"\d{4}\W\d{2}\W\d{2}", val):
print(idx, val)
# Cách 2: Filter + isin
result = pd.Series(filter(lambda x: re.match(r"\d{4}\W\d{2}\W\d{2}", x), data))
print("\nCách 2 - Filter:")
print(data[data.isin(result)])
Giải pháp 2: Vector hóa str.match (khuyên dùng)
import pandas as pd
data = pd.Series(['2010-03-12','2011-3-1','2020-10-10','11-2-2'])
# str.match mặc định anchor ở đầu (^)
mask = data.str.match(r'\d{4}-\d{2}-\d{2}')
result = data[mask]
print("Vector hóa str.match:")
print(result)
Giải pháp 3: Chuyển đổi datetime (kiểm tra tính hợp lệ thực tế)
Regex chỉ kiểm tra định dạng, không kiểm tra ngày 31/02 có tồn tại không. Dùng to_datetime với errors='coerce'.
import pandas as pd
data = pd.Series(['2010-03-12','2011-3-1','2020-10-10','11-2-2', '2023-02-30'])
# Chuyển đổi, lỗi thành NaT
parsed = pd.to_datetime(data, format='%Y-%m-%d', errors='coerce')
print("Parsed datetime:")
print(parsed)
# Lọc những cái không phải NaT
valid = data[parsed.notna()]
print("\nNgày hợp lệ (thực tế):")
print(valid)
Đầu ra so sánh
--- Regex (chỉ định dạng) --- 0 2010-03-12 2 2020-10-10 dtype: object --- to_datetime (kiểm tra thực tế) --- 0 2010-03-12 2 2020-10-10 dtype: object # '2011-3-1' sai định dạng (tháng/ngày 1 chữ số) # '2023-02-30' đúng định dạng nhưng ngày không tồn tại -> bị loại
Khuyên dùng: pd.to_datetime(..., errors='coerce') vừa kiểm tra định dạng vừa kiểm tra tính hợp lệ của ngày tháng.