8

我有一个软件项目的需求列表,它是从其前身的剩余部分组装而成的。每个需求都应映射到一个或多个类别。每个类别由一组关键字组成。我想要做的是找到一种算法,它会给我一个分数排名,每个需求可能属于哪个类别。结果将用作进一步分类需求的起点。

例如,假设我有以下要求:

系统应将存款应用到客户的指定账户。

和类别/关键字:

  1. 客户交易:存款、存款、客户、账户、账户
  2. 余额账户:账户、账户、借方、贷方
  3. 其他类别: foo, bar

我希望算法在第 1 类中得分最高,在第 2 类中得分较低,在第 3 类中完全不得分。评分机制与我几乎无关,但需要传达第 1 类比第 2 类更可能适用.

我是 NLP 的新手,所以我有点不知所措。我一直在阅读Python 中的自然语言处理,并希望应用其中的一些概念,但还没有看到任何适合的东西。我不认为简单的频率分布会起作用,因为我正在处理的文本非常小(一个句子。)

4

3 回答 3

6

您可能希望查看“相似性度量”或“距离度量”的类别(在数据挖掘术语中,这与“分类”不同。)

基本上,相似性度量是一种数学方法,您可以:

  1. 取两组数据(在你的情况下,单词)
  2. 做一些计算/方程/算法
  3. 结果是您有一些数字可以告诉您该数据有多“相似”。

使用相似性度量时,此数字是 0 到 1 之间的数字,其中“0”表示“完全不匹配”,“1”表示“相同”

因此,您实际上可以将您的句子视为一个向量——句子中的每个单词都代表该向量的一个元素。对于每个类别的关键字列表也是如此。

然后您可以做一些非常简单的事情:采用“余弦相似度”或“ Jaccard 索引”(取决于您如何构建数据。)

这两个指标的作用是它们采用两个向量(您的输入句子和您的“关键字”列表)并给您一个数字。如果您在所有类别中执行此操作,您可以对这些数字进行排名,以查看哪个匹配项具有最大的相似系数。

举个例子:

从你的问题:

客户交易:存款、存款、客户、账户、账户

所以你可以构造一个包含 5 个元素的向量:(1, 1, 1, 1, 1)。这意味着,对于“客户交易”关键字,您有 5 个单词,并且(这听起来很明显,但是)这些单词中的每一个都出现在您的搜索字符串中。和我在一起。

所以现在你拿你的句子:

系统应将存款应用到客户的指定账户。

这在“客户交易”集中有 2 个词:{deposits, account, customer}

(实际上,这说明了另一个细微差别:您实际上有“客户”。这是否等同于“客户”?)

您句子的向量可能是 (1, 0, 1, 1, 0)

这个向量中的 1 与第一个向量中的 1 的位置相同——因为这些词是相同的。

所以我们可以说:这些向量有多少次不同?让我们比较一下:

(1,1,1,1,1) (1,0,1,1,0)

嗯。它们有 3 次相同的“位”——在第 1、第 3 和第 4 位。它们仅相差 2 位。因此,假设当我们比较这两个向量时,我们的“距离”为 2。恭喜,我们刚刚计算了汉明距离!汉明距离越低,数据就越“相似”。

(“相似性”度量和“距离”度量之间的区别在于前者是标准化的——它给你一个介于 0 和 1 之间的值。距离是任意数字,所以它只给你一个相对值。)

无论如何,这可能不是进行自然语言处理的最佳方式,但就您的目的而言,它是最简单的,并且实际上可能非常适合您的应用程序,或者至少作为一个起点。

(PS:“分类”-正如您在标题中所说的那样-将回答“如果您接受我的句子,它最有可能属于哪个类别?”这与说“相似程度有多少?”有点不同我对第 1 类的判决比对第 2 类的判决?”这似乎是你所追求的。)

祝你好运!

于 2009-09-29T03:59:41.440 回答
2

问题的主要特点是:

  • 外部定义的分类标准(关键字列表)
  • 要分类的项目(来自需求文档的行)由相对较少数量的属性值组成,实际上只有一个维度:“关键字”。
  • 根据定义,没有反馈/校准(尽管建议其中一些可能是合适的)

这些特征带来了好消息和坏消息:实施应该相对直接,但分类过程的一致准确性水平可能难以实现。此外,少量的各种数量(可能的类别数量、项目中的最大/平均单词数等)应该给我们空间来选择可能是 CPU 和/或空间密集型的解决方案,如果需要的话。

然而,即使这个许可证变得“花哨”,我建议从(并保持接近)一个简单的算法开始,并在此基础上进行一些补充和考虑,同时保持警惕永远存在的称为过度拟合的危险.

基本算法 (概念性,即此时不关注性能技巧)

   参数 =
     CatKWs = 字符串列表的数组/散列。该列表包含可能的
              关键字,用于给定的类别。
         用法:CatKWs[CustTx] = ('deposits', 'deposit', 'customer' ...)
     NbCats = 预定义类别的整数
   变量:
      CatAccu = 一个数组/数值散列,每个数值有一个条目
                可能的类别。用法:CatAccu[3] = 4(如果是数组)或
                 CatAccu['CustTx'] += 1(散列)
      TotalKwOccurences = 统计关键字匹配的总数(counts
       多个预定义类别中找到一个单词时)

    伪代码:(用于对一个输入项进行分类)
       1. 对于 x in 1 到 NbCats
            CatAccu[x] = 0 // 重置累加器
       2.对Item中的每个单词W
             对于 1 到 NbCats 中的每个 x
                 如果在 CatKWs[x] 中找到 W
                      TotalKwOccurences++
                      CatAccu[x]++
       3. 对于 1 中的每个 x 到 NbCats
             CatAccu[x] = CatAccu[x] / TotalKwOccurences // 计算评分
       4. 按值对 CatAccu 进行排序
       5.返回(CategoryID, rating)的有序列表
              对于给定阈值的所有相应 CatAccu[x] 值。

简单但合理:我们偏爱匹配最多的类别,但我们除以匹配的总数,作为在找到许多单词时降低置信度的一种方式。请注意,此划分不会影响给定项目的类别选择的相对排名,但在比较不同项目的评分时可能很重要。

现在,我想到了几个简单的改进:(我会认真考虑前两个,并考虑其他的;决定每一个都与项目的范围、数据的统计概况被分类和其他因素......)

  • 我们应该规范化从输入项中读取的关键字和/或以能够容忍拼写错误的方式匹配它们。由于我们可以使用的单词很少,因此我们需要确保不会因为愚蠢的拼写错误而丢失重要的单词。
  • 我们应该更加重视在 CatKW 中出现频率较低的单词。例如,单词“Account”应该小于单词“foo”或“credit”
  • 我们可以(但也许这不会有用甚至没有帮助)对具有较少 [非噪音] 词的项目的评级给予更多的权重。
  • 我们还可以考虑基于 digrams(两个连续的单词),因为对于自然语言(并且需求文档不是很自然 :-))单词接近度通常是比单词本身更强的指标。
  • 我们可以为分配给前面(或什至在前瞻逻辑中)项目的类别添加一点重要性。项目可能会出现在相关系列中,我们可以从这种规律中受益。

此外,除了评分本身的计算之外,我们还应该考虑:

  • 一些用于评估算法结果本身的指标(待定)
  • 一些逻辑来收集与指定类别相关的单词列表并最终对这些进行统计。这可以允许识别代表一个类别且最初未在 CatKW 中列出的单词。

指标的问题,应该尽早考虑,但这也需要输入项的参考集:排序的“训练集”,即使我们正在处理预定义的字典类别关键字(通常使用训练集来确定这个类别关键字列表以及权重因子)。当然,这样的参考/训练集应该既具有统计意义又具有统计代表性[整个集合]。

总结一下:坚持简单的方法,无论如何上下文不会留下非常花哨的空间。考虑引入一种测量特定算法(或给定算法中的特定参数)效率的方法,但要注意这些指标可能存在缺陷,并提示您针对给定集合专门解决其他项目(过度拟合) )。

于 2009-09-29T04:21:20.087 回答
0

我也面临着同样的问题,即仅基于关键字创建分类器。我有一个类关键字映射器文件,其中包含类变量和特定类中出现的关键字列表。我提出了以下算法,它工作得非常好。

# predictor algorithm
for docs in readContent:
    for x in range(len(docKywrdmppr)):
        catAccum[x]=0
    for i in range(len(docKywrdmppr)):
        for word in removeStopWords(docs):
            if word.casefold() in removeStopWords(docKywrdmppr['Keywords'][i].casefold()):
                print(word)
                catAccum[i]=catAccum[i]+counter
    print(catAccum)
    ind=catAccum.index(max(catAccum))
    print(ind)
    predictedDoc.append(docKywrdmppr['Document Type'][ind])
于 2019-03-14T11:24:16.670 回答