【问题标题】:How to classify/categorize strings according to regular expression rules in Python如何根据 Python 中的正则表达式规则对字符串进行分类/分类
【发布时间】:2012-03-26 07:10:44
【问题描述】:

我正在用 Python 编写一个 ETL 脚本,它获取 CSV 文件中的数据、验证和清理数据以及根据一些规则对每一行进行分类或分类,最后将其加载到 postgresql 数据库中。

数据看起来像这样(简化):

ColA, ColB, 时间戳, 时间戳, Journaltext, AmountA, AmountB

每一行都是一笔金融交易。 我想做的是根据一些规则对交易进行分类或分类。 规则基本上是与 Journaltext 列中的文本匹配的正则表达式。

所以我想做的是这样的:

交易 = [] 对于行中的行: t = 交易(类别=分类(row.journaltext)) 交易.追加(t)

我不确定如何有效地编写classify()函数。

这是分类规则的工作原理:

  • 有许多类别(可以添加更多类别,以后还会添加)
  • 每个类别都有一组子字符串或正则表达式,如果交易的 Journaltext 匹配此表达式或包含此子字符串,则此交易属于此类别。
  • 一笔交易只能属于一个类别
  • 如果一个类别 FOO 具有子字符串 'foo' 和 'Foo',而另一个类别 BAR 具有子字符串 'football',则必须将 Journaltext='food' 的交易放入类别 FOO,因为它只匹配 FOO ,但 Journaltext='footballs' 的交易必须放在 BAR 类别中。我认为这意味着我必须优先考虑每个类别或类似的类别。
  • 如果事务与任何表达式都不匹配,则它要么在类别中为 None,要么将被放入名为“UNKNOWN”或类似的占位符类别中。这无关紧要。

好的。那么我该如何在Python中表示这些类别和对应的规则呢?

非常感谢您的意见。即使您无法提供完整的解决方案。任何能提示我正确方向的东西都会很棒。谢谢。

【问题讨论】:

  • 您的输入有多大(类别数量、每个类别的术语、交易数量和文本的平均大小)?

标签: python regex data-warehouse etl classification


【解决方案1】:

没有任何多余的绒毛:

categories = [
  ('cat1', ['foo']),
  ('cat2', ['football']),
  ('cat3', ['abc', 'aba', 'bca'])
]

def classify(text):
  for category, matches in categories:
    if any(match in text for match in matches):
      return category
  return None

在 Python 中,您可以使用 in 运算符来测试字符串的子集。您可以添加一些类似isinstance(match, str) 的内容来检查您使用的是简单字符串还是正则表达式对象。它的高级程度取决于您。

【讨论】:

  • 这看起来很优雅,但是,如果类别有多个子字符串,它似乎不起作用。怎么做?比如说,cat3 有子字符串:'aba'、'abe' 和 'bca'
  • @ervingsb - 看看这些调整 - 它们允许每个类别有多个匹配项。优先级取决于您将内容放入主categories 列表的顺序。
  • @ervingsb:如果您已经使用正则表达式,您还可以调整它们以使用交替 (abc|abe|bca),这可以简化代码并且可能会带来更好的性能(取决于正则表达式的实现)。
  • 另外,dict 在这里的语法可能会少一些,同时提供相同的功能。
  • @NiklasB。 - 我选择列表而不是字典主要是因为它直接解决了优先级概念。使用dict,您实际上需要使用ordereddict,或者有一些其他分配优先级的容器,因为当您调用myDict.items() 时,您没有保证迭代顺序。
【解决方案2】:

在伪 python 中这个解决方案怎么样:

def classify(journaltext):
    prio_list = ["FOO", "BAR", "UPS", ...] # "..." is a placeholder: you have to give the full list here.
    # dictionary: 
    # - key is the name of the category, must match the name in the above prio_list
    # - value is the regex that identifies the category
    matchers = {"FOO": "the regex for FOO", "BAR": "the regex for BAR", "UPS":"...", ...}
    for category in prio_list:
        if re.match(matchers[category], journaltext):
            return category
    return "UNKOWN" # or you can "return None"

特点:

  • 这有一个prio_list,它是降序排列的所有类别。
  • 它尝试按照列表的顺序进行匹配。
  • 它与 matchers 字典中的正则表达式匹配。所以类别名称可以是任意的。
  • 函数返回类别名称
  • 如果没有匹配项,那么您将获得占位符类别名称。

您甚至可以从配置文件中读取优先类别列表和正则表达式,但这留给读者作为练习......

【讨论】:

  • 如何为 FOO 类别支持多个子字符串/正则表达式?我不能在字典中放置多个 'foo' 键。
  • 您可以将多个子字符串放在一个正则表达式中:“(foo|bar)”匹配包含“foo”或“bar”的字符串。并且正则表达式不能区分大小写,请参阅docs.python.org/howto/regex.html 了解 python 正则表达式操作方法。
猜你喜欢
  • 1970-01-01
  • 2012-06-14
  • 1970-01-01
  • 2015-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多