Определение частотности слова определенных условий

14
задан ROMANIA_engineer 28 June 2017 в 18:36
поделиться

7 ответов

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

#!/usr/bin/perl

use strict;
use warnings;

my $word_list_file = shift;
my $process_file = shift;

my %word_counts;

# Open the word list file, read a line at a time, remove the newline,
# add it to the hash of words to track, initialize the count to zero
open(WORDS, $word_list_file) or die "Failed to open list file: $!\n";
while (<WORDS>) {
  chomp;
  # Store words in lowercase for case-insensitive match
  $word_counts{lc($_)} = 0;
}
close(WORDS);

# Read the text file one line at a time, break the text up into words
# based on word boundaries (\b), iterate through each word incrementing
# the word count in the word hash if the word is in the hash
open(FILE, $process_file) or die "Failed to open process file: $!\n";

while (<FILE>) {
  chomp;
  while ( /-$/ ) {
    # If the line ends in a hyphen, remove the hyphen and
    # continue reading lines until we find one that doesn't
    chop;
    my $next_line = <FILE>;
    defined($next_line) ? $_ .= $next_line : last;
  }

  my @words = split /\b/, lc; # Split the lower-cased version of the string
  foreach my $word (@words) {
    $word_counts{$word}++ if exists $word_counts{$word};
  }
}
close(FILE);

# Print each word in the hash in alphabetical order along with the
# number of time encountered, delimited by tabs (\t)
foreach my $word (sort keys %word_counts)
{
  print "$word\t$word_counts{$word}\n"
}

Если файл words.txt содержит:

linux
frequencies
science
words

И файл text.txt содержит текст Вашего сообщения, следующей команды:

perl analyze.pl words.txt text.txt

распечатает:

frequencies     3
linux   1
science 1
words   3

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

Править: Обновленная версия, которая обрабатывает слова нечувствительно к регистру и обрабатывает написанные через дефис слова через строки.

Обратите внимание, что, если существуют написанные через дефис слова, некоторые из которых повреждаются через строки и некоторых, которые не являются, это не найдет их всех, потому что это только удалило дефисы в конце строки. В этом случае можно хотеть просто удалить все дефисы и распознать слова после того, как дефисы будут удалены. Можно сделать это путем простого добавления следующей строки прямо перед функцией разделения:

s/-//g;
7
ответ дан 1 December 2019 в 13:48
поделиться

Я делаю этот вид вещи со сценарием как следующее (в синтаксисе удара):

for file in *.txt
do 
  sed -r 's/([^ ]+) +/\1\n/g' "$file" \
  | grep -F -f 'go-words' \
  | sort | uniq -c > "${file}.frq"
done

можно настроить regex, который Вы используете для разграничивания отдельных слов; в примере я просто рассматриваю пробел как разделитель.-f аргументом grep является файл, который содержит Ваши слова интереса, один на строку.

4
ответ дан 1 December 2019 в 13:48
поделиться

Я сделал бы "grep" на файлах для нахождения всех строк, которые содержат ключевые слова. (Grep-f может использоваться для определения входного файла слов для поиска (передайте вывод по каналу grep в файл). Это даст Вам список строк, которые содержат экземпляры Ваших слов. Затем сделайте "sed", чтобы заменить Ваших разделителей слов (скорее всего, пробелы) с новыми строками, дать Вам файл отдельных слов (одно слово на строку). Теперь пробежавший grep снова, с Вашим тем же списком слов, кроме этого времени указывают-c (для получения количества строк с указанными словами; т.е. количество случаев слова в исходном файле).

метод с двумя передачами просто делает жизнь легче для "sed"; первый grep должен устранить много строк.

можно сделать это все в основных командах командной строки Linux. После того как Вы довольны процессом, можно поместить все это в сценарий оболочки довольно легко.

1
ответ дан 1 December 2019 в 13:48
поделиться

Я предполагаю, что новые файлы представляются со временем, и это - то, как вещи изменяются?

я считаю, что Ваш лучший выбор состоял бы в том, чтобы пойти с чем-то как Ваша опция 2. Нет большого количества точки, предварительно обрабатывающей файлы, если все, что Вы хотите сделать, считать случаи ключевых слов. Я просто прошел бы каждый файл однажды, рассчитав каждый раз, когда слово в Вашем списке появляется. Лично я сделал бы это в Ruby, но язык как жемчуг или Python также сделает эту задачу довольно простой. Например, Вы могли использовать ассоциативный массив с ключевыми словами как ключи и количество случаев как значения. (Но это могло бы быть слишком упрощенно, если необходимо хранить больше информации о случаях).

я не уверен, хотите ли Вы хранить информацию на файл, или о целом наборе данных? Я предполагаю, что это не было бы слишком трудно для слияния.

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

Редактирование: Я просто выяснил, что, так как Вы изучаете историю, возможности являются Вашими документами, не изменяются со временем, а скорее отражают ряд изменений, которые уже произошли. Извините за недоразумение этого. Так или иначе я думаю в значительной степени все, что я сказал выше, все еще применяется, но я предполагаю, что Вы склонитесь к движению с экспортом в CSV или что имеет Вас, а не автоматизированный дисплей.

Походит на забавный проект - удачи!

Ben

1
ответ дан 1 December 2019 в 13:48
поделиться

Сначала ознакомьтесь с лексическим анализом и как записать спецификацию генератора сканера. Считайте введения в использование инструментов как YACC, Закон, Бизон, или мой любимый, JFlex. Здесь Вы определяете то, что составляет маркер. Это - то, где Вы узнаете о том, как создать токенизатор.

Следующий Вы имеете то, что называют списком семени. Противоположность стоп-листа обычно упоминается как список запуска или ограниченный словарь. Словарь также был бы хорошей вещью узнать о. Часть приложения должна загрузить список запуска в память, таким образом, это может быть быстро запрошено. Типичным способом сохранить является файл с одним словом на строку, затем считайте это в в начале приложения, однажды, во что-то как карта. Вы могли бы хотеть узнать о понятии хеширования.

Отсюда Вы хотите думать об основном алгоритме и структурах данных, необходимых хранить результат. Распределение легко представлено как двумерный разреженный массив. Изучите основы разреженной матрицы. Вам не требуются 6 месяцев линейной алгебры для понимания то, что она делает.

, поскольку Вы работаете с большими файлами, я защитил бы подход на основе потоков. Не читайте в целом файле в память. Считайте его как поток в токенизатор, который производит поток маркеров.

В следующей части алгоритма думают о том, как преобразовать маркерный список в список, содержащий только слова, которые Вы хотите. Если Вы думаете об этом, список находится в памяти и может быть очень большим, таким образом, лучше отфильтровать non-start-words в запуске. Таким образом в критической точке, где Вы получаете новый маркер от токенизатора и прежде, чем добавить его к маркерному списку, сделайте поиск в start-words-list в оперативной памяти, чтобы видеть, является ли слово словом запуска. Если так, сохраните его в выходном маркерном списке. Иначе проигнорируйте его и переместитесь в следующий маркер, пока целый файл не будет считан.

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

Так, сначала создайте пустую разреженную матрицу. Затем думайте о вставке недавно найденного маркера во время парсинга. Когда это происходит, увеличьте его количество, если его в списке или иначе вставляет новый маркер с количеством 1. На этот раз, в конце парсинга файла, у Вас есть список отличных маркеров, каждого с частотой по крайней мере 1.

, Что список теперь в мадам и можно сделать то, что Вы хотите. Дамп его к файлу CSV был бы тривиальным процессом итерации по записям и записи каждой записи на строку с ее количеством.

В этом отношении, смотрите на некоммерческий продукт под названием "ЛОГИЧЕСКИЙ ЭЛЕМЕНТ" или коммерческий продукт как TextAnalyst или продукты, перечисленные в http://textanalysis.info

2
ответ дан 1 December 2019 в 13:48
поделиться

Другая попытка Perl:

#!/usr/bin/perl -w
use strict;

use File::Slurp;
use Tie::File;

# Usage:
#
# $ perl WordCount.pl <Files>
# 
# Example:
# 
# $ perl WordCount.pl *.text
#
# Counts words in all files given as arguments.
# The words are taken from the file "WordList".
# The output is appended to the file "WordCount.out" in the format implied in the
# following example:
#
# File,Word1,Word2,Word3,...
# File1,0,5,3,...
# File2,6,3,4,...
# .
# .
# .
# 

### Configuration

my $CaseSensitive = 1;       # 0 or 1
my $OutputSeparator = ",";   # another option might be "\t" (TAB)
my $RemoveHyphenation = 0;   # 0 or 1.  Careful, may be too greedy.

###

my @WordList = read_file("WordList");
chomp @WordList;

tie (my @Output, 'Tie::File', "WordCount.out");
push (@Output, join ($OutputSeparator, "File", @WordList));

for my $InFile (@ARGV)
    { my $Text = read_file($InFile);
      if ($RemoveHyphenation) { $Text =~ s/-\n//g; };
      my %Count;
      for my $Word (@WordList)
          { if ($CaseSensitive)
               { $Count{$Word} = ($Text =~ s/(\b$Word\b)/$1/g); }
               else
               { $Count{$Word} = ($Text =~ s/(\b$Word\b)/$1/gi); }; };
      my $OutputLine = "$InFile";
      for my $Word (@WordList)
          { if ($Count{$Word})
               { $OutputLine .= $OutputSeparator . $Count{$Word}; }
               else
               { $OutputLine .= $OutputSeparator . "0"; }; };
      push (@Output, $OutputLine); };

untie @Output;

, Когда я поместил Ваш вопрос в файл wc-test и ответ Robert Gamble в wc-ans-test, Выходной файл похож на это:

File,linux,frequencies,science,words
wc-ans-test,2,2,2,12
wc-test,1,3,1,3

Это - разделенное значение запятой (csv) файл (но можно изменить разделитель в сценарии). Это должно быть читаемо для любого приложения для обработки электронных таблиц. Для построения графиков я рекомендовал бы gnuplot, который полностью scriptable, таким образом, можно настроить вывод независимо от входных данных.

1
ответ дан 1 December 2019 в 13:48
поделиться

К черту большие сценарии. Если вы хотите получить все слова, попробуйте эту оболочку fu:

cat *.txt | tr A-Z a-z | tr -cs a-z '\n' | sort | uniq -c | sort -rn | 
sed '/[0-9] /&, /'

Это (проверено) даст вам список всех слов, отсортированных по частоте в формате CSV, которые легко импортируются из вашей любимой электронной таблицы. Если вам нужны стоп-слова, попробуйте вставить grep -w -F -f stopwords.txt в конвейер (не тестировалось).

1
ответ дан 1 December 2019 в 13:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: