r - pandas 中的向量化按列正则表达式匹配

标签 r regex pandas dplyr vectorization

第一部分

假设我有一个如下所示的数据集 df:

x   | y     
----|--------
foo | 1.foo-ya
bar | 2.bar-ga
baz | 3.ha-baz
qux | None

我想过滤 y 恰好在中间包含 x 的行(既不开始也不结束,即匹配模式 '^.+\w+.+$',命中第 1 行和第 2 行),不包括 None/NaN:

x   | y
----|-----
foo | 1.foo-ya
bar | 2.bar-ga

这是典型的成对字符比较,在 SQL 中很容易实现:

select x, y from df where y like concat('^.+', x, '.+%');

或在 R 中:

library(dplyr)
library(stringr)
library(glue)
df %>% filter(str_detect(y, glue('^.+{x}.+$')))

但是由于我不是pandas方面的专家,pandas中似乎没有类似的简单的“矢量化”正则表达式匹配方法?我应用了 lambda 方法:

import pandas as pd
import re
df.loc[df.apply(lambda row: bool(re.search(
                '^.+' + row.x + '.+$', row.y)) 
       if row.x and row.y else False, axis=1), :]

pandas 中有没有更优雅的方法来完成它?

第二部分

此外,我想提取第一部分中生成的匹配记录中的前导数字(1, 2, ...):

x   | y        |  z
----|----------|---
foo | 1.foo-ya |  1
bar | 2.bar-ga |  2

在 R 中,我可以进行直接的管道处理:

df %>%
  filter(str_detect(y, glue('^.+{x}.+$'))) %>%
  mutate(z=str_replace(y, glue('^(\\d+)\\.{x}.+$'), '\\1') %>%
           as.numeric)

但是在 pandas 中,我只知道 lambda 方法。还有比它“更好”的方法吗?

a = df.loc[df.apply(lambda row: bool(
                re.search('^.+' + row.x + '.+$', row.y))
                if row.x and row.y else False, axis=1), 
       ['x', 'y']]
a['z'] = a.apply(lambda row: re.sub(
       r'^(\d+)\.' + row.x + '.+$', r'\1', row.y), axis=1).astype('int')
a

顺便说一句,分配方法无法工作。

df.loc[df.apply(lambda row: bool(re.search(
                '^.+' + row.x + '.+$', row.y))
                if row.x and row.y else False, axis=1), 
       ['x', 'y']].assign(z=lambda row: re.sub(
                r'^(\d+)\.' + row.x + '.+$', r'\1', row.y))

谢谢!

最佳答案

pandas 字符串操作建立在 python 的 string 和 re 模块之上。尝试一下,看看它是否是您想要的:

import re

#find out if values in column x are in column y
#according to the pattern u wrote in the question
pattern = [re.match(fr'^.+{a}.+$',b)
           for a,b 
           in zip(df.x.str.strip(),
                  df.y.str.strip())
          ]

match = [ent.group() if ent is not None else np.nan for ent in pattern]

#extract values for digit immediately preceding val in col x    
ext = [re.search(fr'\d(?=\.{a})', b) for a,b  in 
       zip(df.x.str.strip(),
           df.y.str.strip())]

extract = [ent.group() if ent is not None else np.nan for ent in ext]

df['match'], df['extract'] = match, extract

     x     y        match   extract
1   foo 1.foo-ya    1.foo-ya    1
2   bar 2.bar-ga    2.bar-ga    2
3   baz 3.ha-baz      NaN      NaN
4   qux    None       NaN      NaN

关于r - pandas 中的向量化按列正则表达式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61436313/

相关文章:

python - 为什么 pandas reindex() 不就地运行?

r - 如何将 4 对图组合在一个图中?

r - geom_smooth() 有哪些可用方法?

regex - 如何编写排除而不是匹配的正则表达式,例如,不包括(this | string)?

regex - 为什么要实现不同的正则表达式引擎(例如 PCRE)作为编译指示?

ruby-on-rails - Ruby .scan 方法使用正则表达式返回空

r - install.package期间出错: cannot read unreleased workspace version 3 written by experimental R 3. 5.0

r - 根据r中的列名从列表中提取数据框

python - 使用 psycopg2 复制到带有 ARRAY INT 列的表

python-polars 通过分隔符将字符串列拆分为多列