2014-10-19 2 views
-2

У меня есть PHP-массив:PHP найти п-граммы в массиве

$excerpts = array(
    'I love cheap red apples', 
    'Cheap red apples are what I love', 
    'Do you sell cheap red apples?', 
    'I want red apples', 
    'Give me my red apples', 
    'OK now where are my apples?' 
); 

Я хотел бы найти все п-граммы в этих линиях, чтобы получить результат, как этот:

  • дешевые красные яблоки: 3
  • красные яблоки: 5
  • яблоки: 6

Я попытался взорвать массив, а затем проанализировать его, но это глупо, потому что новые n-граммы можно найти из-за конкатенации строк, которые не видят друг друга.

Как вы продолжите?

+1

Чтобы продолжить, я бы поискал n-граммовые алгоритмы, а затем решил, какой из них целесообразно реализовать в этом наборе данных. Первый вызов: [wikipedia on N-grams] (http://en.wikipedia.org/wiki/N-gram). –

+0

Спасибо за ваше предложение, это то, что я сделал, но мне нужно было какое-то решение или, по крайней мере, конкретные примеры, которые дали бы мне конечный результат, который я предоставил. – mattspain

+0

Здравствуйте, Эта библиотека делает это за вас: https://packagist.org/packages/drupol/phpngrams Дайте мне знать, как все идет! –

ответ

2

Я хочу найти группу слов, не зная их, прежде чем хотя с вашей функции мне нужно обеспечить их перед чем

Попробуйте это:

mb_internal_encoding('UTF-8'); 

$joinedExcerpts = implode(".\n", $excerpts); 
$sentences = preg_split('/[^\s|\pL]/umi', $joinedExcerpts, -1, PREG_SPLIT_NO_EMPTY); 

$wordsSequencesCount = array(); 
foreach($sentences as $sentence) { 
    $words = array_map('mb_strtolower', 
         preg_split('/[^\pL+]/umi', $sentence, -1, PREG_SPLIT_NO_EMPTY)); 
    foreach($words as $index => $word) { 
     $wordsSequence = ''; 
     foreach(array_slice($words, $index) as $nextWord) { 
       $wordsSequence .= $wordsSequence ? (' ' . $nextWord) : $nextWord; 
      if(!isset($wordsSequencesCount[$wordsSequence])) { 
       $wordsSequencesCount[$wordsSequence] = 0; 
      } 
      ++$wordsSequencesCount[$wordsSequence]; 
     } 
    } 
} 

$ngramsCount = array_filter($wordsSequencesCount, 
          function($count) { return $count > 1; }); 

Я предполагаю, что вам нужна только повторная группа слов. выводе из var_dump($ngramsCount); является:

array (size=11) 
    'i' => int 3 
    'i love' => int 2 
    'love' => int 2 
    'cheap' => int 3 
    'cheap red' => int 3 
    'cheap red apples' => int 3 
    'red' => int 5 
    'red apples' => int 5 
    'apples' => int 6 
    'are' => int 2 
    'my' => int 2 

Код может быть оптимизирован, чтобы, например, использовать меньше памяти.

+0

это так прекрасно, именно то, что я просил. Большое спасибо! – mattspain

-1

Предполагая, что вы просто хотите, чтобы подсчитать количество вхождений строки:

$cheapRedAppleCount = 0; 
$redAppleCount = 0; 
$appleCount = 0; 
for($i = 0; $i < count($excerpts); $i++) 
{ 
    $cheapRedAppleCount += preg_match_all('cheap red apples', $excerpts[$i]); 
    $redAppleCount += preg_match_all('red apples', $excerpts[$i]); 
    $appleCount += preg_match_all('apples', $excerpts[$i]); 
} 

preg_match_all возвращает количество совпадений в данной строке, так что вы можете просто добавить количество матчей на прилавке.

preg_match_all для получения дополнительной информации.

Извинения, если я неправильно понял.

+1

Я думаю, что OP, вероятно, хочет найти все n-граммы в любом наборе строк, а не только в трех этих строках. : \ –

+0

Я хочу найти группу слов, не зная их раньше, и, к сожалению, это не соответствует моим требованиям. В любом случае, спасибо за помощь. – mattspain

0

Попробуйте (с помощью implode, так как это вы упоминали как попытку):

$ngrams = array(
    'cheap red apples', 
    'red apples', 
    'apples', 
); 

$joinedExcerpts = implode("\n", $excerpts); 
$nGramsCount = array_fill_keys($ngrams, 0); 
var_dump($ngrams, $joinedExcerpts); 
foreach($ngrams as $ngram) { 
    $regex = '/(?:^|[^\pL])(' . preg_quote($ngram, '/') . ')(?:$|[^\pL])/umi'; 
    $nGramsCount[$ngram] = preg_match_all($regex, $joinedExcerpts); 
} 
+0

Дело в том, что я хочу найти группу слов, не зная их раньше, хотя с вашей функцией мне нужно предоставить их перед чем-либо. В любом случае, спасибо за помощь. – mattspain

+0

Извините, я не понял этот вопрос. Если группа слов «я», «я люблю» и «есть» считаются n-граммами, и если не будут проигнорированы повторяющиеся групповые слова («Do», «Do you» и т. Д.)? –

1

The code provided by Pedro Amaral Couto выше очень хорошо. Так как я использую его для французского языка, я изменил регулярное выражение следующим образом:

$sentences = preg_split('/[^\s|\pL-\'’]/umi', $joinedExcerpts, -1, PREG_SPLIT_NO_EMPTY); 

Таким образом, мы можем анализировать слова, содержащие дефис и апостроф («ЭСТ-Ce Que», «J'ai», и т.д. .)