如何在Pandas DataFrame中无需指定行列提取目标子串及数字子串?
问题描述
我有多个Pandas DataFrame,需要提取的目标数据(比如project:后以45开头的4位数字、日期、物质名称)在不同DataFrame中的行列位置完全不固定。目前用df.iloc指定行列拆分的方法适配性极差,操作还繁琐,想找一种不用指定行列就能提取这些子串(尤其是数字子串)的实现方法。
以下是示例DataFrame:
df
{1: {0: 'sample', 1: 2}, 2: {0: 'project: 4568 date: 7 January 2023', 1: 4}, 3: {0: 'substance:water', 1: 6}}
df2
{1: {0: 'sample', 1: 2}, 2: {0: 'user ab', 1: 4}, 3: {0: 'project: 4568 date: 7 January 2023', 1: 6}, 4: {0: 'substance:water', 1: 3}}
df3
{1: {0: nan, 1: 'sample', 2: 2}, 2: {0: 'Monday', 1: 'user ab', 2: 4}, 3: {0: nan, 1: 'project: 4568 substance: water date: 7 January 2023', 2: 6}, 4: {0: nan, 1: 'plate 2', 2: 3}}
解决方案
核心思路是用正则表达式替代固定行列定位,通过匹配目标内容的格式规则提取数据,完全不需要指定行列位置。
方法1:全局文本提取(推荐)
把整个DataFrame转换成扁平的文本集合,一次性用正则匹配所有目标内容,效率最高:
import pandas as pd import re def extract_targets(df): # 将DataFrame所有元素转为字符串,过滤空值后拼接成全局文本 all_text = ' '.join(str(val) for val in df.stack().dropna()) # 提取project后45开头的4位数字 project_num = re.search(r'project:\s*(45\d{2})', all_text).group(1) # 提取日期(匹配"数字+月份+年份"格式) date = re.search(r'date:\s*(\d+\s+\w+\s+\d{4})', all_text).group(1) # 提取物质名称 substance = re.search(r'substance:\s*(\w+)', all_text).group(1) return { 'project_number': project_num, 'date': date, 'substance': substance } # 测试三个示例DataFrame for df_name, df in zip(['df', 'df2', 'df3'], [df, df2, df3]): result = extract_targets(df) print(f"{df_name}提取结果:") print(result)
方法2:遍历元素匹配
逐个检查DataFrame的每个元素,找到包含目标关键字的内容后提取,适合需要中途终止遍历的场景:
import pandas as pd import re def extract_targets_by_element(df): project_num = None date = None substance = None # 遍历所有列和行的元素 for col in df.columns: for val in df[col].dropna(): val_str = str(val) # 匹配project字段 p_match = re.search(r'project:\s*(45\d{2})', val_str) if p_match: project_num = p_match.group(1) # 匹配date字段 d_match = re.search(r'date:\s*(\d+\s+\w+\s+\d{4})', val_str) if d_match: date = d_match.group(1) # 匹配substance字段 s_match = re.search(r'substance:\s*(\w+)', val_str) if s_match: substance = s_match.group(1) # 三个目标全部找到后提前终止遍历 if project_num and date and substance: break if project_num and date and substance: break return { 'project_number': project_num, 'date': date, 'substance': substance } # 测试 for df_name, df in zip(['df', 'df2', 'df3'], [df, df2, df3]): result = extract_targets_by_element(df) print(f"{df_name}提取结果:") print(result)
关键注意事项
- 正则规则可以根据实际数据格式调整:比如物质名称包含空格时,把
\w+改成[\w\s]+;日期格式变化时,修改日期匹配的正则表达式即可。 df.stack()用于将二维DataFrame转为一维序列,简化全局遍历;dropna()过滤空值,避免无效内容干扰匹配。
内容的提问来源于Stack Exchange,提问作者Steve Johnson
相关产品推荐
相关产品推荐

