正则表达式在多个模式之前找到一个数字序列,放入一个新列(Python,Pandas)
Posted
技术标签:
【中文标题】正则表达式在多个模式之前找到一个数字序列,放入一个新列(Python,Pandas)【英文标题】:Regular expression to find a sequence of numbers before multiple patterns, into a new column (Python, Pandas) 【发布时间】:2021-01-17 20:39:45 【问题描述】:这是我的样本数据:
import pandas as pd
import re
cars = pd.DataFrame('Engine Information': 0: 'Honda 2.4L 4 cylinder 190 hp 162 ft-lbs',
1: 'Aston Martin 4.7L 8 cylinder 420 hp 346 ft-lbs',
2: 'Dodge 5.7L 8 Cylinder 390hp 407 ft-lbs',
3: 'MINI 1.6L 4 Cylinder 118 hp 114 ft-lbs',
4: 'Ford 5.0L 8 Cylinder 360hp 380 ft-lbs FFV',
5: 'GMC 6.0L 8 Cylinder 352 hp 382 ft-lbs',
'HP': 0: None, 1: None, 2: None, 3: None, 4: None, 5: None)
这是我的想要的输出:
我创建了一个名为“HP”的新列,我想从原始列(“引擎信息”)中提取马力数据
这是我尝试执行此操作的代码:
cars['HP'] = cars['Engine Information'].apply(lambda x: re.match(r'\\d+(?=\\shp|hp)', str(x)))
这个想法是我想用正则表达式匹配模式:'在'hp'或'hp'之前出现的数字序列。这是因为某些单元格在数字和“hp”之间没有“空格”,如我的示例所示。
我确定正则表达式是正确的,因为我已经在 R 中成功完成了类似的过程。但是,我尝试了诸如 str.extract
、re.findall
、re.search
、re.match
之类的函数。返回错误或“无”值(如示例中所示)。所以在这里我有点失落。
谢谢!
【问题讨论】:
为什么“s”前面有两个“\”? \d+(?=\\shp|hp)。删除一个时,它会正确匹配所有 hp 值:regex101.com/r/Aeh0LX/1r'\\d+(?=\\shp|hp)'
==> r'\d+(?=\shp|hp)'
或 '\\d+(?=\\shp|hp)'
尝试了这两种解决方案,仍然在我的表中返回“无”值。
【参考方案1】:
你可以使用str.extract
:
cars['HP'] = cars['Engine Information'].str.extract(r'(\d+)\s*hp\b', flags=re.I)
详情
(\d+)\s*hp\b
- 匹配并捕获到第 1 组一个或多个数字,然后仅匹配 0 个或多个空格 (\s*
) 和 hp
(由于 flags=re.I
不区分大小写)作为一个完整的单词(因为 @ 987654329@ 标记一个单词边界)
str.extract
仅在模式中有捕获组时才返回捕获的值,因此 hp
和空格不是结果的一部分。
Python 演示结果:
>>> cars
Engine Information HP
0 Honda 2.4L 4 cylinder 190 hp 162 ft-lbs 190
1 Aston Martin 4.7L 8 cylinder 420 hp 346 ft-lbs 420
2 Dodge 5.7L 8 Cylinder 390hp 407 ft-lbs 390
3 MINI 1.6L 4 Cylinder 118 hp 114 ft-lbs 118
4 Ford 5.0L 8 Cylinder 360hp 380 ft-lbs FFV 360
5 GMC 6.0L 8 Cylinder 352 hp 382 ft-lbs 352
【讨论】:
另见this Python demo online。 起初这返回了我:TypeError: extract() got an unexpected keyword argument 'expand'
,但是我删除了“提取”参数并且它运行良好。
@k3b 奇怪,请参阅文档:“expand
: bool, default True If True,每个捕获组返回一列 DataFrame。如果为 False,如果有一个捕获组,则返回 Series/Index;如果有多个捕获组,则返回 DataFrame。"【参考方案2】:
有几个问题:
re.match
只查看字符串的开头,如果您的模式可能出现在任何地方,请使用 re.search
如果您使用原始字符串,请不要转义,即'\\d hp'
或r'\d hp'
- 原始字符串可以帮助您避免转义
返回匹配组。您只是搜索但不产生找到的组。 re.search(rex, string)
为您提供一个复杂对象(匹配对象),您可以从中提取所有组,例如re.search(rex, string)[0]
您必须将访问封装在一个单独的函数中,因为您必须在访问组之前检查是否有任何匹配项。如果您不这样做,异常可能会在中间停止应用过程
应用速度慢;使用 pandas 矢量化函数,例如提取:cars['Engine Information'].str.extract(r'(\d+) ?hp')
你的方法应该适用于这个:
def match_horsepower(s):
m = re.search(r'(\d+) ?hp', s)
return int(m[1]) if m else None
cars['HP'] = cars['Engine Information'].apply(match_horsepower)
【讨论】:
【参考方案3】:这将在 hp 之前获得数值,不带或带(单个或多个)空格。
r'\d+(?=\s+hp|hp)'
您可以在此处验证正则表达式:https://regex101.com/r/pXySxm/1
【讨论】:
感谢您的回答,但我仍然收到“无”值返回。以上是关于正则表达式在多个模式之前找到一个数字序列,放入一个新列(Python,Pandas)的主要内容,如果未能解决你的问题,请参考以下文章