我正在开发一个基于PHP的购物应用程序。我有我知道的字符串列表代表相同的产品。这些字符串可能包含完整的产品名称或部分产品名称(完整的产品名称通常是品牌+型号)。
我想知道执行产品名称提取的最佳方法是什么。
例如,这里是表示同一产品的字符串列表:
我希望提取产品名称“Tkg JK 1008 RWD”。请注意,字符串4仅包含部分信息。
当我计算所有字符串中重复的单词时,我尝试过一种方法;但从那里开始,很难走得更远。
你有什么线索吗?
干杯 尼古拉斯
答案 0 :(得分:2)
您可以分析字符串重叠的数量(并生成大多数字符串中显示的单词/子字符串列表),然后选择最相关的单词。
例如,如果单词出现在字符串的特定百分比中,则可以将它们标识为产品名称的最可能候选对象。 (所以类似于你所做的但增加了阈值 - 例如你可以看到88%的字符串中出现5个单词而其他字符串的百分比低得多 - 然后选择前5个作为产品名称。这不是确切的我担心,需要手动调整。)这应该允许收集大部分信息,但永远不会是完美的。
此外,您可以拥有预定义的品牌列表并过滤掉这些字词。我还会考虑单词的部分匹配,因为它们可能是手动数据输入的产物,并且总是存在拼写错误。你可以看出这是多么相关,如果你通过简单地丢弃它们来获得足够强大的“信号”,那么就不用担心了。
更进一步,您可以指定另一个过滤器来标记手动管理的项目,但这可能非常耗时。
恐怕没有简单的答案。你正在做的主要是文本挖掘。我刚刚提出了一些可以帮助你开始的想法和起点。
如果您正在构建一些自动爬虫尝试将来自多个来源的日期放在一起,则上述方法可行。如果您希望访问者能够搜索您的网站并返回所有查询的正确产品页面,那么我建议您进行一些文本搜索(主要数据分析是谁?)。或者只是使用一些现成的解决方案。
答案 1 :(得分:2)
在比较购物引擎工作(虽然没有特别针对这个问题),我猜你所描述的问题非常困难。我的建议是放弃并选择“最好”的字符串,而不是试图合成或提取“产品名称”(无论如何这是一个模糊的概念)。您用来尝试提取产品名称的大多数想法都会产生不一致且令人沮丧的结果。例如,只看你给出的例子,天真的算法可能会产生像“Jk 1008 Rwd”这样的神秘结果,或者像“BouilloireÉlectrique”那样极其模糊的东西。甚至托马斯的聪明和漂亮的效果也会因很多产品而失败,或产生令人尴尬的不合理的结果。我想到的许多想法都倾向于删除像“BouilloireÉlectrique”这样的类别词,这对于用户体验和SEO来说是次优的。
如果我在你的位置,我可能会像这样建模解决方案:计算标题中每个单词的idf权重(查看所有产品或此类别中的所有产品作为文档空间)。然后将每个产品字符串转换为其idf权重向量,并计算产品的所有权重向量的质心。找到最接近该质心的字符串,并将其称为“最佳”。使用该字符串作为产品名称。它并不完美,但在大多数情况下它可能会很好用。 Lucene(或您正在使用的任何搜索数据库)中可能有一个插件或查询,可以为您做很多这样的事情。
在您提供的字符串列表中,此方法将倾向于远离第四个不完整的字符串,因为它不包括高加权型号1008(可能在电水壶中不常见)。如果你有很多低信息,不完整的产品名称,这可能是一个问题。然后质心可能不会特别接近包含型号的名称。正如我所说,这是一个难题。
其他想法:
进一步阅读:
答案 2 :(得分: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
答案 3 :(得分: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);
}
}