首页 > 解决方案 > 查找特定单元格满足特定正则表达式的数据框行

问题描述

假设我有 Pandas 数据框:

data_df:

color          shape          number

green 5        triangle       3
green 1056     rectangle      2
blue           square         1
blue           circle         5
blue           square         4

我还有其他带有这些过滤器参数的数据框:

filter_df:

color          shape          number

green .*       ANY            ANY
blue           square         1

过滤后的结果应该是:

filtered_data_df:

color          shape          number

blue           circle         5
blue           square         4

我的错误方法是为颜色、形状和数字创建正则表达式,这样:

color_regex = 'green .*|blue'
shape_regex = '.*|square'  # I would replace ANY with '.*'
number_regex = '.*|1'

之后我会简单地使用:

filtered_data_df = data_df.drop(
           data_df[data_df['color'].str.match(color_regex , case=False)].index &
           data_df[data_df['shape'].str.match(shape_regex , case=False)].index &
           data_df[data_df['number'].astype(str).str.match(number_regex, case=False)].index,
           axis=0)

但当然,因为我在 shape_regex 和 number_regex 中都有“。*”,所以所有内容都会被过滤掉,我希望所有内容都被过滤掉,只针对绿色和蓝色,只针对蓝色/正方形/1 的组合。

我可能会写一些东西,但这会涉及某种 FOR 循环,与 Pandas 一起工作,我假设我可以跳过使用。

在我的真实案例中,data_dt 最多可以有 5000 行,而 filter_dt 可以有大约 100 行(3 列)的过滤参数组合,并且具有进一步增长的恒定潜力(逐行)。

我的问题是,如何以某种有效的 Pandas 方式处理这种过滤?

标签: python-3.xregexpandas

解决方案


IIUC 你可以使用列表理解。我应该注意到那df是你的data_dfdf1是你的filter_df

# replace any with .*
df1 = df1.replace('ANY', '.*')
# zip your columns
z = zip(df1['color'], df1['shape'], df1['number'])

# list comprehension with logic and str.contains
l = [~((df['color'].str.contains(c)) &\
       (df['shape'].str.contains(s)) & \
       (df['number'].astype(str).str.contains(n))).values for c,s,n in z]

# numpy.equal to see where the true values overlap then use boolean indexing
df[np.equal(*l)]

  color   shape  number
3  blue  circle       5
4  blue  square       4

这是样本数据

s = """color,shape,number
green 5,triangle,3
green 1056,rectangle,2
blue,square,1
blue,circle,5
blue,square,4"""

s1 = """color,shape,number
green .*,ANY,ANY
blue,square,1"""

df = pd.read_csv(StringIO(s))
df1 = pd.read_csv(StringIO(s1))

推荐阅读