匹配大熊猫数据框中的字符串(正则表达式?)以获取销售优惠

时间:2020-10-16 15:20:21

标签: python regex pandas

简介

我有一个pandas数据框,其中包含有关商品信息的各个列。我对使用包含字符串的列之一过滤数据框感兴趣,该字符串包含有关报价的信息。

我要识别两个主要类别:

  1. “所有商品最多x%折扣”-此处的关键是“最多”
  2. “所有商品均可享受x%的折扣”

在列中找到的示例字符串

  • [Random_String]最高可优惠x [Random_String]
  • [Random_String]凡是[Random_String]都可享受x%的折扣
  • [Random_String]最多可将foo降低y%,所有[Random_String]均可降低x%
  • [Random_String] foo的y%折扣,所有[Random_String]的折扣高达x%
  • [Random_String]所有内容均x%的折扣,foo [Random_String]中最高y%的折扣
  • [Random_String]最高可享受x%的折扣,foo [Random_String]可获得y%的折扣

我只对x%off感兴趣,并且该字符串是否包含最多x%,我对特定产品系列的y%不感兴趣。随机字符串可以是任何字母数字数据,但这只是我要过滤/分类的折扣。

预期产量

对于上面给出的示例字符串,我希望分类分为两类:使用“最多”或不使用“最多”。对于上面的每个字符串,都是这样(为了便于阅读,删除了random_string标记):

  • 所有内容最多可享受x%的折扣-“最多”组
  • 将所有商品减价x%-不在“最多”组中
  • foo最多可享受y%的折扣,一切都可享受x%的折扣-不在“ up up”组中
  • foo可获得y%的折扣,所有内容最多可获得x%的折扣-“最多”组
  • 所有商品均减价x%,foo最高减价y%-不在“最多”组中
  • 所有内容最多x%的折扣,foo最多y%的折扣-“最多”组

当前方法

我一直在尝试使用正则表达式使用以下内容过滤数据框

df[df['column'.str.match('regex_here')==True]

但是我对正则表达式非常陌生,正如评论中指出的那样,我弄错了一些基本原理。我现在有一个“最多”组:

df[df['column'.str.match('up to \d{1,2}% off', case=false)==True]

问题

我一直在努力找出不符合分类标准的方法,我已阅读Regular expression to match a line that doesn't contain a word,但是我正在努力使其适应我的目的。

所以我相信这里有3个子问题:

  1. 如何操作正则表达式以准确地对列中的“ x%off all”字符串进行分类
  2. 是否有一种简单的方法可以对我提供的四个额外字符串进行分类,或者每个字符串都需要单独的大小写?
  3. 正则表达式甚至是执行此操作的正确方法吗?在整个阅读过程中,我感到这可能不合适-但是这是我可以考虑的唯一方法,因此,对此表示感谢。

对于使用python和regex这样的东西,我还很陌生,所以请联系我们以了解是否不清楚。

2 个答案:

答案 0 :(得分:0)

您误解了r'[abcd]'作为正则表达式模式的工作方式。这些是可选的字母,与'abcd'

之一完全匹配

'[1-100]'相同,它匹配'1''1'(== '1')之间的所有字母或字母'0'。仍然只匹配一个字母。

您需要的是类似

的东西
r'up to \d{1,3}% off'       - to match "up to 74% off"
r'(?! up to )\d{1,3}% off'  - to match "777% off everything" with no 'up to' in front

要将0到100匹配为数字,可以使用r'(\d|[1-9]\d|100)'之类的东西来匹配一位数字(0-9),两位以1-9或100开头的数字。

http://regex101.com之类的在线正则表达式测试器是一个基于演示数据开始开发正则表达式的好地方,如果您不确定该怎么做-它们会将模式转换为普通语言,以使其更易于理解。


您可以基于r'up to \d{1,3} off everything'对数据进行分区:

import pandas as pd

data = ["[Random_String] up to 40% off everything [Random_String]",
        "[Random_String] 41% off everything [Random_String]",
        "[Random_String] up to 99% off foo, 42% off everything [Random_String]",
        "[Random_String] y% off foo, up to 43% off everything [Random_String]",
        "[Random_String] 44% off everything, up to 99% off foo [Random_String]",
        "[Random_String] up to 45% off everything, 99% off foo [Random_String]",
        "some data that has neither in it",]

df = pd.DataFrame({"column":data})
df['up to'] = df['column'].str.match(r'.*(up to \d{1,3}% off) everything.*', case=False)

print(df.to_csv(sep='\t'))

输出:

    column                                                                  up to
0   [Random_String] up to 40% off everything [Random_String]                True
1   [Random_String] 41% off everything [Random_String]                      False
2   [Random_String] up to 99% off foo, 42% off everything [Random_String]   False
3   [Random_String] y% off foo, up to 43% off everything [Random_String]    True
4   [Random_String] 44% off everything, up to 99% off foo [Random_String]   False
5   [Random_String] up to 45% off everything, 99% off foo [Random_String]   True
6   some data that has neither in it                                        False

答案 1 :(得分:-1)

我认为您应该使用()-括号进行尝试。而且您不需要在开头和结尾使用“。*”,因为您无需在模式之前使用“ ^”或在结尾使用“ $”。

编辑:

我希望我现在能理解你。

我的代码:

import re
text = "[Random_String] up to 99% off foo, 50% off everything [Random_String]"
result = re.findall(r"(up to )?(\d{1,2})% off", text)
print(result) # output: [('up to ', '99'), ('', '50')]
print(result[0]) # output: ('up to ', '99') 
print(result[0][1]) # output: 99