【问题标题】:`re.sub()` in pandas大熊猫中的`re.sub()`
【发布时间】:2018-06-29 02:34:52
【问题描述】:

说我有:

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,'

在第二种情况下造成绊倒的原因是什么?

额外问题:熊猫系列有没有直接实现这个功能的方法而不是使用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))

【问题讨论】:

  • Pandas 确实提供了一堆向量化的字符串函数。我的正则表达式不是最好的,因此将您的问题中的所有内容转换为它们的功能有点复杂。但是,阅读他们的文档可能会让您接近解决问题:pandas.pydata.org/pandas-docs/stable/text.html
  • 是的,我很熟悉——认为它可以通过 .str.replace() @DataSwede 实现

标签: python regex pandas


【解决方案1】:

关于您的“奖励”问题,您可以使用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 实现是否值得之前,您可能不会抱太大希望。

【讨论】:

    【解决方案2】:

    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'
    

    【讨论】:

    • 谢谢——刚刚也意识到了这一点。否则,您将捕获强制性的“tw”,然后是“o”或“2”
    • @BradSolomon 没问题。
    【解决方案3】:

    关于您的正则表达式本身,我会使用以下更通用和优化的。

    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
    

    【讨论】:

    • 这里是否需要(?:two|2) 中的非捕获组,因为您没有使用(?P&lt;...&gt;) 明确命名组?换句话说,这就是为什么这个答案需要非捕获符号,而不是@Tai's?
    • @BradSolomon 是的,因为我们不需要他们。
    【解决方案4】:

    最简单的方法:

    import pandas as pd
    
    lst = ['Geeks', 'For', 'Geeks', 'is', 'portal', 'for', 'Geeks']
    lst2 = [11, 22, 33, 44, 55, 66, 77]
    
    df = pd.DataFrame(list(zip(lst, lst2)), columns =['Name', 'val'])
    
    # \1 $1 \g<1>
    df.replace(regex=r'(\w)(?P<ewe>\w)', value='\g<1>_\g<ewe>=')
    
    ## Output
               Name  val
    0     G_e=e_k=s   11
    1         F_o=r   22
    2     G_e=e_k=s   33
    3          i_s=   44
    4  p_o=r_t=a_l=   55
    5         f_o=r   66
    6     G_e=e_k=s   77
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-14
      • 2014-08-18
      • 1970-01-01
      • 2015-10-12
      • 2021-06-21
      • 1970-01-01
      • 2014-10-04
      • 2021-10-22
      相关资源
      最近更新 更多