1

我正在开发一个基于 PHP 的购物应用程序。我有我知道代表相同产品的字符串列表。这些字符串可能包含完整的产品名称或其中的一部分(完整的产品名称通常是品牌 + 型号)。

我想知道执行此产品名称提取的最佳方法是什么。

例如,这里有一个代表相同产品的字符串列表:

  • Tkg BOUILLOIRE TKG - JK 1008 RWD
  • Tkg Jk 1008 Rwd
  • Tkg Kalorik - JK 1008 RWD - Bouilloire Électrique sans Fil 360°
  • TKG Bouilloire électrique sans fil 1,7 升 2000 瓦 Pois TKG Rouge et blanc
  • Tkg Kalorik - JK 1008 RWD - Bouilloire Électrique sans Fil 360°
  • Tkg JK 1008 RWD 肉汁

我希望提取产品名称“Tkg JK 1008 RWD”。请注意,字符串 4 仅包含部分信息。

当我计算所有字符串中的重复单词时,我尝试了一种方法;但从那里,很难走得更远。

你有什么线索吗?

干杯尼古拉斯

4

4 回答 4

2

在比较购物引擎工作过(虽然不是专门针对这个问题),我猜你描述的问题非常困难。我的建议是放弃并选择字符串中的“最佳”,而不是尝试合成或提取“该”产品名称(无论如何这是一个模糊的概念)。您用来尝试提取产品名称的大多数想法都会产生不一致和令人沮丧的结果。例如,仅查看您提供的示例,幼稚的算法可能会产生像“Jk 1008 Rwd”这样的神秘结果,或者像“Bouilloire Électrique”这样极其模糊的结果。即使是 Tomas 聪明而漂亮的结果也会在很多产品中失败,或者产生令人尴尬的不合语法的结果。

如果我处于您的位置,我可能会像这样对解决方案进行建模:计算标题中每个单词的 idf 权重(将您的所有产品或该类别中的所有产品视为文档空间)。然后将每个产品字符串转换为其 idf 权重向量,并计算该产品的所有权重向量的质心。找到最接近该质心的字符串,并将其称为“最佳”。使用该字符串作为产品名称。它并不完美,但在大多数情况下它可能运行良好。Lucene(或您正在使用的任何搜索数据库)中可能有一个插件或查询可以为您做很多事情。

在您提供的字符串列表中,此方法倾向于远离第四个不完整的字符串,因为它不包括高度加权的型号 1008(可能在电热水壶中不常见)。如果你有很多信息量少、不完整的产品名称,这可能是个问题。那么质心可能不会特别接近包含型号的名称。正如我所说,这是一个难题。

其他想法:

  1. Thomas 选择前 n 个最常用词的启发式方法可能比我想象的效果更好。或者,可能还有另一种启发式方法来检测它何时会运行不佳
  2. 寻找大多数字符串共有的长子字符串,并选择具有最高 IDF 权重和的子字符串。

进一步阅读:

特遣部队

质心

向量空间模型

于 2012-02-04T02:33:38.030 回答
2

您可以分析字符串重叠的程度(并生成出现在大多数字符串中的单词/子字符串列表),然后选择最相关的单词。

例如,如果单词出现在特定百分比的字符串中,您可以将它们识别为最有可能的产品名称候选者。(与您所做的类似,但添加了阈值 - 例如,您可以看到 5 个单词出现在 88% 的字符串中,而其他单词的百分比要低得多 - 然后选择前 5 个作为产品名称。这不是确切的恐怕需要手动调整。)这应该可以收集大部分信息,但永远不会完美。

此外,您可以有一个预定义的品牌列表并过滤掉这些词。我还将考虑单词的部分匹配,因为它们可能是手动数据输入的产物,并且总是可能存在拼写错误。您可以看到这是多么相关,如果您通过简单地丢弃它们获得足够强的“信号”,那么无需担心。

更进一步,您可以指定另一个过滤器来标记要手动管理的项目,但这可能非常耗时。

恐怕没有简单的答案。你所做的本质上是文本挖掘。我刚刚提出了一些可以帮助您开始的想法和起点。

假设您正在构建一些自动爬虫,试图将来自多个来源的日期放在一起,上述方法将起作用。如果您想让访问者能够搜索您的网站并为所有查询返回正确的产品页面,那么我建议您深入进行一些文本搜索(任何人都可以进行主要数据分析?)。或者只是使用一些现成的解决方案。

于 2012-02-03T18:33:01.130 回答
1

只是一些想法

<?php
// to lower case
$string = strtolower(
'Tkg BOUILLOIRE TKG - JK 10o8 RWD
Tkg Jk 10o8 Rwd
Tkg Kalorik - JK 10o8 RWD - Bouilloire Électrique sans Fil 360°
TKG Bouilloire électrique sans fil 1,7 litre 2000 watts Pois TKG Rouge et blanc
Tkg Kalorik - JK 10o8 RWD - Bouilloire Électrique sans Fil 360°
Tkg JK 10o8 RWD BOUILLOIRES'
);

// remove new lines and explode by spaces
$data = explode(' ', str_replace(array("\r\n", "\n", "\r"), ' ', $string));
// count most popular words
$count = array_count_values($data);
// sort 
arsort($count);
// get first 6 most popular words
$product = array_slice($count, 0, 6);
// print product
var_dump(implode(' ', array_keys($product)));
?>

输出是:

tkg rwd 1008 jk - bouilloire
于 2012-02-03T19:25:14.777 回答
0

第一次尝试实施你们带来的一些想法。

class ProductNameExtraction {

    private $brandName = NULL;
    private $categoryName = NULL;

    private $modelName = NULL;

    /**
      * @param $A Array of string discribing the same product
      */
    public function __construct($A, $brandName, $categoryName) {
        $this->brandName = $brandName;
        $this->categoryName = $categoryName;

        $res = array();     
        foreach ($A as $k => $title) {
            $res[] = $this->cleanTitle($title);
        }

        $this->modelName = $this->computeProductName($res);
    }

    public function getModelName() {
        return $this->modelName;
    }

    private function computeProductName($A) {
        $s = NULL;

        foreach ($A as $k => $title) {
            $s .= $title . ' ';
        }
        $s = trim($s);

        $data = explode(' ', $s);

        // count most popular words
        $count = array_count_values($data);

        // Remove brand & category names
        unset($count[$this->cleanTitle($this->brandName)]);
        unset($count[$this->cleanTitle($this->categoryName)]);

        $s = '';
        $totalnb = sizeof($A);          
        foreach ($count as $k => $val) {
            if ($val / $totalnb > 0.5) {
                $s .= $k . ' ';
            }
        }

        return $s;
    }

    private function cleanTitle($title) {
        // Remove extra spaces
        $title = trim($title);
        $title = preg_replace('/\s\s+/', ' ', $title);

        // Remove noise
        $title = str_replace(' - ', ' ', $title);
        $title = str_replace(array("\r\n", "\n", "\r"), ' ', $title);

        return strtoupper($title);
    }

}
于 2012-02-04T09:42:09.787 回答