2012-02-03 77 views
1

我正在研究一個基於PHP的購物應用程序。我有我知道代表相同產品的字符串列表。這些字符串可能包含完整的產品名稱或其中的一部分(完整的產品名稱通常是品牌+型號)。如何從一組字符串中提取產品名稱? (php)

我不知道什麼是執行此產品名稱提取的最佳方法。

例如,這裏代表同一產品的字符串列表:

  • TKG BOUILLOIRE TKG - JK 1008 RWD
  • TKG JK 1008 RWD
  • TKG KALORIK - JK 1008 RWD - Bouilloire ELECTRIQUE SANS費爾360°
  • TKG Bouilloire ELECTRIQUE SANS FIL 1,7-升2000瓦特的POI TKG胭脂等相思
  • TKG KALORIK - JK 1008 RWD - Bouilloire ELECTRIQUE SANS費爾360°
  • TKG JK 1008 RWD BOUILLOIRES

我希望提取的產品名爲 「TKG JK 1008 RWD」。請注意,字符串4只包含部分信息。

我試過一種方法,當我計算所有字符串中的重複單詞;但從那裏,很難走得更遠。

你有什麼線索嗎?

乾杯 薩科

+0

嗨,根據提供的信息,這看起來像一個銷售網站。你可以說得更詳細點嗎?你可以改變html輸出嗎?它被用作下拉菜單嗎? – 2012-02-03 18:32:43

+1

如果你已經知道你需要提取什麼,那麼不要費力提取它。如果你不知道你需要提取什麼,那麼你需要描述你想提取的***模式***,否則沒有人可以回答你的問題。 – FtDRbwLXw6 2012-02-03 18:33:33

+1

在我看來,這聽起來像你有某個地方的設計問題。強制使用獨特的產品編號,以避免混淆購買什麼和訂購。使用唯一的產品編號開始或結束上述每個字符串。 – phpmeh 2012-02-03 18:34:37

回答

2

你可以分析字符串多少重疊(併產生出現在大部分字/字符串列表),然後選擇最相關的詞。

例如,如果單詞出現在一定比例的字符串中,則可以將它們標識爲產品名稱的最可能候選對象。 (與您所做的相似,但添加了閾值 - 例如,您可以看到5個單詞出現在88%的字符串中,其他單詞以低得多的百分比出現 - 然後選擇前5作爲產品名稱。我害怕,需要手動調整。)這應該允許收集大部分信息,但永遠不會完美。

此外,您可以有一個預先定義的品牌列表並過濾掉這些單詞。我還會說明這些詞的部分匹配,因爲它們可能是手動輸入數據的產物,並且總會有拼寫錯誤。你可以看到這是多麼的相關,如果你通過簡單地丟棄它們而獲得足夠強的「信號」,那麼就不用擔心。

更進一步,您可以指定另一個過濾器來標記手動配準的項目,但這可能非常耗時。

恐怕沒有簡單的答案。你所做的實質上是文本挖掘。我剛剛提出了一些可以幫助你開始的想法和出發點。

上述方法假定您正在構建一些自動爬蟲,嘗試將多個來源的日期放在一起。如果您希望允許訪問者搜索您的網站並返回所有查詢的正確產品頁面,那麼我會建議潛入一些文本搜索(主要數據分析任何人?)。或者只是使用一些現成的解決方案。

+0

謝謝彼得 - 真的很有用。大量的想法來探索。 – 2012-02-04 09:09:31

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 
+0

謝謝托馬斯;非常好的策略和一個很好的起點! – 2012-02-04 09:10:02

2

在比較購物引擎工作過(儘管不是在這個問題上明確),我猜想,像你描述的問題非常困難。我的建議是放棄,只是選擇「最好」的字符串,而不是試圖合成或提取「產品名稱」(這是一個模糊的概念)。您嘗試提取產品名稱的大多數想法都會產生不一致且令人沮喪的結果。例如,僅僅看看你給出的例子,樸素的算法可能會產生像「Jk 1008 Rwd」這樣的神祕結果,或者像「BouilloireÉlectrique」那樣非常模糊的東西。即使托馬斯的聰明和好看的結果將失敗的許多產品,或產生令人尷尬的非語法結果。我腦海中涌現出的很多想法都會去掉類似「BouilloireÉlectrique」這樣的詞,這對用戶體驗和SEO來說都不是最理想的。

如果我處於你的位置,我可能會對此解決方案進行建模:爲標題中的每個單詞計算idf權重(查看所有產品或此類別中的所有產品作爲文檔空間)。然後將每個產品字符串轉換爲其idf加權向量,並計算產品所有加權向量的質心。找到最接近該質心的字符串,並將其稱爲「最佳」。使用該字符串作爲產品名稱。這並不完美,但在大多數情況下它可能會運行良好。在Lucene中可能有一個插件或查詢(或者你正在使用的任何搜索數據庫),可能會爲你做很多事情。

在您給出的字符串列表中,此方法傾向於從第四個不完整的字符串移開,因爲它不包含高度加權的1008號型號(大概在電水壺中不常見)。如果你有很多低信息,不完整的產品名稱,這可能是一個問題。然後質心可能不會特別接近包含型號的名稱。正如我所說,這是一個難題。

其他的想法:採摘前n個最常用的詞可能更好地工作比我猜它的

  1. 托馬斯的啓發。或者,可能有另一種啓發式方法來檢測它何時效果不佳
  2. 查找大多數字符串常見的長子字符串,並選擇IDF權重和最高的子字符串。

延伸閱讀:

TF-IDF

Centroid

Vector Space Model

+0

謝謝!一些不錯的文章,你指出我! – 2012-02-04 09:13:44

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); 
    } 

} 
相關問題