Как извлечь названия продуктов из набора строк? (РНР) - PullRequest
1 голос
/ 03 февраля 2012

Я работаю над приложением для покупок на основе PHP.У меня есть списки строк, которые я знаю, представляют один и тот же продукт.Эти строки, вероятно, содержат полное название продукта или его часть (полное название продукта, как правило, бренд + модель).

Интересно, каков наилучший подход для выполнения этого извлечения названий продуктов.

Например, вот список строк, которые представляют один и тот же продукт:

  • Tkg BOUILLOIRE TKG - JK 1008 RWD
  • Tkg Jk 1008 Rwd
  • TkgKalorik - JK 1008 RWD - электрическая розетка без фильтра 360 °
  • TKG электрическая розетка без фильтра 1,7 литра 2000 Вт Pois TKG Rouge et blanc
  • Tkg Kalorik - JK 1008 RWD - электрическая розеткаFil 360 °
  • Tkg JK 1008 RWD BOUILLOIRES

Я рассчитываю извлечь название продукта "Tkg JK 1008 RWD".Обратите внимание, что строка 4 содержит только частичную информацию.

Я пробовал подход, когда подсчитывал повторяющиеся слова во всех строках;но оттуда трудно идти дальше.

У вас есть какие-либо подсказки?

Приветствия Николас

Ответы [ 4 ]

2 голосов
/ 04 февраля 2012

Поработав над механизмом сравнения покупок (хотя и не над этой проблемой конкретно), я бы предположил, что описанная вами проблема чрезвычайно сложна.Мое предложение состоит в том, чтобы сдаться и просто выбрать «лучшее» из строк, а не пытаться синтезировать или извлечь «название» продукта (что в любом случае является туманной концепцией).Большинство идей, которые вы используете для извлечения названия продукта, дадут противоречивые и разочаровывающие результаты.Например, глядя на только что приведенные вами примеры, наивные алгоритмы, вероятно, дадут либо загадочные результаты, такие как «Jk 1008 Rwd», либо что-то чрезвычайно расплывчатое, например «Bouilloire Électrique».Даже умные и красивые результаты Томаса потерпят неудачу для многих продуктов или приведут к смущающе неграмотным результатам.Множество идей, которые приходят мне в голову, имеют тенденцию отбрасывать слова категории, такие как «Bouilloire Électrique», что было бы неоптимальным для пользовательского опыта и SEO.

Если бы я был на вашем месте, я, вероятно, смоделировал быРешение, подобное этому: вычислите веса IDF для каждого слова в названии (просматривая все ваши продукты или все продукты в этой категории как пространство документов).Затем преобразуйте каждую строку продукта в ее вектор весов idf и вычислите центр тяжести всех векторов весов для продукта.Найдите строку, ближайшую к центроиду, и назовите ее «лучшей».Используйте эту строку в качестве названия продукта.Это не идеально, но, скорее всего, в большинстве случаев будет работать хорошо.В Lucene может существовать плагин или запрос (или любая используемая вами поисковая база данных), которая может многое для вас сделать.

В приведенном вами списке строк этот метод будет иметь тенденцию отходить отчетвертая, неполная строка, потому что она не будет включать в себя высоко взвешенный номер модели 1008 (предположительно, не распространенный среди электрических чайников).Это может быть проблемой, если у вас много неполных и неполных названий продуктов.Тогда центр тяжести может быть не слишком близок к именам, содержащим номер модели.Как я уже сказал, это сложная проблема.

Другие идеи:

  1. Эвристика Томаса выбора первых n наиболее распространенных слов может работать лучше, чем я предполагаю.Или, в качестве альтернативы, может существовать другая эвристика для определения того, когда она будет работать плохо
  2. Найдите длинные подстроки, общие для большинства строк, и выберите ту, которая имеет наибольшую весовую сумму IDF.

Дополнительное чтение:

TF-IDF

Центр тяжести

Модель векторного пространства

2 голосов
/ 03 февраля 2012

Вы можете проанализировать, насколько сильно перекрываются строки (и сгенерировать список слов / подстрок, которые встречаются в большинстве из них), а затем выбрать наиболее релевантные слова.

Например, если слова появляются в определенном процентном соотношениииз строк вы можете определить их как наиболее вероятные кандидаты на название продукта.(Так похоже на то, что вы сделали, но добавьте пороговые значения - например, вы можете видеть, что 5 слов появляются в 88% строк, а остальные - в гораздо меньшем процентном соотношении), а затем выберите топ 5 в качестве названия продукта. Это не совсем точноеЯ боюсь и должен быть настроен вручную.) Это должно позволить собрать большую часть информации, но никогда не будет идеальным.

Кроме того, вы можете иметь заранее определенный список брендов и отфильтровать эти слова.Я также учел бы частичное совпадение слов, поскольку они могут быть результатом ручного ввода данных, и всегда могут быть опечатки.Вы можете видеть, насколько это актуально, если вы получаете достаточно сильный «сигнал», просто отбрасывая их, и вам не о чем беспокоиться.

Если пойти еще дальше, вы можете указать другой фильтр, чтобы пометить элементы для ручного курирования, но этоможет быть очень трудоемким.

Боюсь, что нет простого ответа.То, что вы делаете, это по сути текстовый майнинг.Я только что выдвинул несколько идей и отправных точек, которые могут помочь вам начать.

Вышеприведенное сработает, если вы создадите некоторый автоматический сканер, пытающийся собрать дату из нескольких источников.Если вы хотите, чтобы посетители могли осуществлять поиск по вашему сайту и возвращать нужную страницу продукта для всех запросов, то я бы предложил углубиться в поиск по тексту (анализ основных данных?).Или просто используйте готовое решение.

1 голос
/ 03 февраля 2012

Просто некоторые мысли

<?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 голосов
/ 04 февраля 2012

Первый шаг в реализации некоторых идей, которые вы, ребята, принесли.

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

}
...