大熊猫里的`re.sub()`

时间:2018-01-19 19:19:18

标签: python regex pandas

说我有:

s = 'white male, 2 white females'

并希望"扩展"这个:

'white male, white female, white female'

更完整的案例清单如下:

  • '两名西班牙裔男性,两名西班牙裔女性'
    • - > '西班牙裔男性,西班牙裔男性,西班牙裔女性,西班牙裔女性'
  • ' 2名黑人男性,白人男性'
    • - > '黑人男性,黑人男性,白人男性'

好像我很接近:

import re

# Do I need boundaries here?
mult = re.compile('two|2 (?P<race>[a-z]+) (?P<gender>(?:fe)?male)s')

# This works:
s = 'white male, 2 white females'
mult.sub(r'\g<race> \g<gender>, \g<race> \g<gender>', s)
# 'white male, white female, white female'

# This fails:
s = 'two hispanic males, 2 hispanic females'
mult.sub(r'\g<race> \g<gender>, \g<race> \g<gender>', s)
# ' ,  , hispanic males, hispanic female, hispanic female,'

在第二种情况下是什么造成了绊倒?

奖金问题:是否有大熊猫的方法&#39;直接实现此功能的系列而不是使用Series.apply()?很抱歉修改我的问题并浪费任何人在这里的时间。

例如,在:

s = pd.Series(
    ['white male',
     'white male, white female',
     'hispanic male, 2 hispanic females',
     'black male, 2 white females'])

是否有比以下更快的路线:

s.apply(lambda x: mult.sub(..., x))

3 个答案:

答案 0 :(得分:3)

关于你的&#34;奖金&#34;问题,您可以使用pandas.Series.str.replace,它是pandas.Series.str methods的一部分,与正则表达式一起使用:

In [10]: import re

In [11]: import pandas as pd

In [12]: s = pd.Series(
    ...:     ['white male',
    ...:      'white male, white female',
    ...:      'hispanic male, 2 hispanic females',
    ...:      'black male, 2 white females'])

In [13]: mult = re.compile('two|2 (?P<race>[a-z]+) (?P<gender>(?:fe)?male)s')
    ...:

In [14]: s.str.replace(mult, r'\g<race> \g<gender>, \g<race> \g<gender>')
Out[14]:
0                                         white male
1                           white male, white female
2    hispanic male, hispanic female, hispanic female
3             black male, white female, white female
dtype: object

这些方法是否明显快于我不知道的.apply。我怀疑你永远不会用object dtypes快速工作。

注意,如果发现this issue这些方法的速度很慢。我想直到他们认为写出一个Cythonized实现是值得的,那么你可能不会有太多希望。

答案 1 :(得分:1)

IIUC,如果你想要匹配,你需要在two|2 (two|2)附近放置一下。

import re

mult = re.compile('(two|2) (?P<race>[a-z]+) (?P<gender>(?:fe)?male)s')
s = 'two hispanic males, 2 hispanic females'
mult.sub(r'\g<race> \g<gender>, \g<race> \g<gender>', s)
# 'hispanic male, hispanic male, hispanic female, hispanic female'

答案 2 :(得分:1)

关于你的正则表达式本身,我将使用下面的一个更通用和优化的。

In [14]: mult = re.compile('(?:two|2) ([^,]+)')

In [15]: s = 'two hispanic males, 2 hispanic females'

In [16]: mult.sub(lambda x: x.group(1) + ' ' + x.group(1), s)
Out[16]: 'hispanic males hispanic males, hispanic females hispanic females'

但是关于性能以及使用列表理解将正则表达式应用于Pandas Series是最好的方法:

In [29]: s = pd.Series(                                     
    ['white male',
     'white male, white female',
     'hispanic male, 2 hispanic females',
     'black male, 2 white females'])

In [30]: %timeit s.str.replace('(?:two|2) (?P<race>[a-z]+) (?P<gender>(?:fe)?male)s', r'\g<race> \g<gender>, \g<race> \g<gender>')
1000 loops, best of 3: 205 µs per loop

In [31]: %timeit s.apply(lambda x: mult.sub(lambda x: x.group(1) + ' ' + x.group(1), x))
10000 loops, best of 3: 148 µs per loop

In [32]: %timeit [mult.sub(lambda x: x.group(1) + ' ' + x.group(1), i) for i in s]
100000 loops, best of 3: 14.6 µs per loop