Часть I
Предположим, у меня есть набор данных 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? Я применил лямбда-подход:
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 какие-нибудь более изящные методы для достижения этой цели?
Часть II
Более того, я хочу извлечь ведущие числа (1, 2, ...) в сопоставленных записях, приведенных в части I:
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 я знаю только о лямбда-приближении. Есть ли "лучшие" подходы, чем он?
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
Кстати, assign
метод не работает.
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))
Спасибо!