本文目录导读:

- 基础准备
- 使用
str.extract()提取单个字段 - 使用
str.extractall()提取多个匹配 - 使用
str.contains()进行条件筛选 - 使用
str.replace()进行替换操作 - 实战案例:数据分析清洗
- 高级应用:多条件正则匹配
- 批量处理和数据验证
- 使用命名捕获组
- 性能优化技巧
我来详细介绍如何使用Pandas进行数据正则提取,包含多个实用案例。
基础准备
import pandas as pd
import re
# 创建示例数据
data = {
'text': [
'联系方式:138-1234-5678,邮箱:user1@example.com',
'电话:010-87654321,邮箱:test@email.com',
'手机:159-1234-5678,QQ:123456789',
'地址:北京市朝阳区XXX路,电话:13900000000'
]
}
df = pd.DataFrame(data)
print("原始数据:")
print(df)
使用 str.extract() 提取单个字段
# 提取手机号(11位数字)
df['phone'] = df['text'].str.extract(r'(\d{3}-\d{4}-\d{4})')
print("提取手机号:")
print(df[['text', 'phone']].head())
使用 str.extractall() 提取多个匹配
# 提取所有数字信息
patterns = {
'phone': r'(\d{3}-\d{4}-\d{4})',
'email': r'([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})',
'qq': r'(\d{5,10})'
}
# 提取所有匹配
df_extracted = df['text'].str.extractall('|'.join([f'(?P<{k}>{v})' for k, v in patterns.items()]))
print("所有提取结果:")
print(df_extracted)
使用 str.contains() 进行条件筛选
# 筛选包含邮箱的行
has_email = df['text'].str.contains(r'@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', na=False)
print("包含邮箱的记录:")
print(df[has_email])
使用 str.replace() 进行替换操作
# 隐藏手机号中间4位
df['masked_phone'] = df['text'].str.replace(
r'(\d{3})-(\d{4})-(\d{4})',
r'\1-****-\3',
regex=True
)
print("隐藏手机号:")
print(df[['text', 'masked_phone']].head())
实战案例:数据分析清洗
# 创建更复杂的数据集
data_complex = {
'user_info': [
'张三|13812345678|beijing|25岁|男',
'李四|13901234567|shanghai|30岁|女',
'王五|15811223344|广东深圳|28岁|男',
'赵六|无|unknown|22岁|女'
],
'order_id': ['ORD2023001', 'ORD2023002', 'ORD2023003', 'ORD2023004']
}
df_complex = pd.DataFrame(data_complex)
# 提取姓名、手机号、城市
pattern = r'^(.*?)\|(.*?)\|(.*?)\|'
df_complex[['name', 'phone', 'city']] = df_complex['user_info'].str.extract(pattern)
print("提取后的数据:")
print(df_complex[['order_id', 'name', 'phone', 'city']].head())
高级应用:多条件正则匹配
# 处理不同格式的电话号码
phone_data = {
'contact': [
'手机:138-1234-5678',
'电话:010-87654321',
'座机:0755-88886666',
'国际:+86 13812345678'
]
}
df_phone = pd.DataFrame(phone_data)
# 提取不同格式的电话号码
def extract_phone(text):
patterns = [
r'(\d{3}-\d{4}-\d{4})', # 手机号格式
r'(\d{3,4}-\d{7,8})', # 座机格式
r'(\+\d{1,3}\s?\d{10,11})' # 国际格式
]
for pattern in patterns:
match = re.search(pattern, text)
if match:
return match.group(1)
return None
df_phone['extracted_phone'] = df_phone['contact'].apply(extract_phone)
print("电话号码提取结果:")
print(df_phone)
批量处理和数据验证
# 数据验证函数
def validate_email(email):
"""验证邮箱格式"""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return bool(re.match(pattern, str(email)))
def validate_phone(phone):
"""验证手机号格式"""
pattern = r'^\d{3}-\d{4}-\d{4}$'
return bool(re.match(pattern, str(phone)))
# 创建验证列
df['email_valid'] = df['text'].str.extract(r'([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})')[0].apply(
lambda x: validate_email(x) if pd.notna(x) else False
)
print("邮箱验证结果:")
print(df[['text', 'email_valid']].head())
使用命名捕获组
# 提取结构化信息
s = pd.Series([
"李明,30岁,北京",
"张华,25岁,上海",
"王芳,28岁,广州"
])
# 使用命名捕获组
df_names = s.str.extract(r'(?P<name>\w+),(?P<age>\d+)岁,(?P<city>\w+)')
print("命名捕获组提取结果:")
print(df_names)
性能优化技巧
import time
# 大数据集模拟
big_data = pd.DataFrame({
'text': ['测试数据' + str(i) + ',电话:138-1234-5678' for i in range(10000)]
})
# 方法1:使用向量化操作
start = time.time()
result1 = big_data['text'].str.extract(r'(\d{3}-\d{4}-\d{4})')
print(f"向量化操作耗时:{time.time() - start:.3f}秒")
# 方法2:使用apply方法
start = time.time()
result2 = big_data['text'].apply(lambda x: re.search(r'(\d{3}-\d{4}-\d{4})', x).group(1) if re.search(r'(\d{3}-\d{4}-\d{4})', x) else None)
print(f"apply方法耗时:{time.time() - start:.3f}秒")
使用Pandas进行正则提取的主要优势:
- 向量化操作:比循环处理快很多
- 链式调用:
str.extract(),str.contains()等可以组合使用 - 灵活性强:支持复杂的正则表达式
- 易于数据清洗:方便处理缺失值和异常数据
常见应用场景:
- 数据清洗(提取电话号码、邮箱、身份证号等)
- 文本分类(基于关键词或模式)
- 数据验证(格式检查)
- 信息抽取(从非结构化文本中提取结构化数据)
记住在使用正则时要注意:
- 使用原始字符串(
r'')避免转义问题 - 考虑边界情况和异常值
- 大数据集时优先使用向量化操作