質問

私は、コンピューターサイエンス以外の学生で、多数のテキストの特定の用語の頻度を特定し、これらの頻度を経時的にプロットして変化と傾向を特定する歴史学論文を執筆しています。特定のテキストファイルの単語の頻度を決定する方法を理解しましたが、(比較的、私にとって)多数のファイル(> 100)を扱っています。一貫性のために、頻度に含まれる単語を制限したいと思います。特定の用語セット(「ストップリスト」の反対のようなもの)にカウントします

これは非常にシンプルに保つ必要があります。最後に、必要なのは、処理する各テキストファイルの特定の単語の頻度で、できればスプレッドシート形式(タブ区切りファイル)で、そのデータを使用してグラフと視覚化を作成できるようにします。

私は日常的にLinuxを使用しており、コマンドラインを快適に使用しており、オープンソースソリューション(またはWINEで実行できるもの)が大好きです。ただし、これは要件ではありません。

この問題を解決する方法は2つあります:

  1. 事前に定義されたリストを除くテキストファイル内のすべての単語を削除する方法を見つけて、そこから頻度をカウントするか、または:
  2. 事前に定義されたリストの用語のみを使用して頻度カウントを行う方法を見つけます。

アイデアはありますか

役に立ちましたか?

解決

2番目のアイデアに進みます。これは、提供された最初のファイルから単語のリストを読み取り、タブで区切られた形式で提供された2番目のファイルからリスト内の各単語のカウントを出力する単純なPerlプログラムです。最初のファイルの単語のリストは、1行に1つずつ提供する必要があります。

#!/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(

2番目のアイデアに進みます。これは、提供された最初のファイルから単語のリストを読み取り、タブで区切られた形式で提供された2番目のファイルからリスト内の各単語のカウントを出力する単純なPerlプログラムです。最初のファイルの単語のリストは、1行に1つずつ提供する必要があります。

linux
frequencies
science
words

words.txtファイルに次が含まれている場合:

perl analyze.pl words.txt text.txt

また、テキストtext.txtには、投稿のテキスト、次のコマンドが含まれています:

frequencies     3
linux   1
science 1
words   3

印刷されます:

s/-//g;
\ 。この場合、行の最後の文字がハイフンであるかどうかを確認し、ハイフンである場合は、行を単語に分割する前にハイフンを削除して別の行を読み取るだけです。

編集:大文字と小文字を区別せずに単語を処理し、複数行にわたるハイフン付きの単語を処理する更新バージョン。

ハイフンでつながれた単語があり、その一部は行をまたいで分割され、一部は分割されない場合、行末のハイフンのみが削除されるため、すべてが検出されないことに注意してください。この場合、すべてのハイフンを削除し、ハイフンが削除された後に単語を一致させることができます。これを行うには、分割関数の直前に次の行を追加するだけです。

<*>)} = 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) ?

2番目のアイデアに進みます。これは、提供された最初のファイルから単語のリストを読み取り、タブで区切られた形式で提供された2番目のファイルからリスト内の各単語のカウントを出力する単純なPerlプログラムです。最初のファイルの単語のリストは、1行に1つずつ提供する必要があります。

<*>

words.txtファイルに次が含まれている場合:

<*>

また、テキストtext.txtには、投稿のテキスト、次のコマンドが含まれています:

<*>

印刷されます:

<*> \ 。この場合、行の最後の文字がハイフンであるかどうかを確認し、ハイフンである場合は、行を単語に分割する前にハイフンを削除して別の行を読み取るだけです。

編集:大文字と小文字を区別せずに単語を処理し、複数行にわたるハイフン付きの単語を処理する更新バージョン。

ハイフンでつながれた単語があり、その一部は行をまたいで分割され、一部は分割されない場合、行末のハイフンのみが削除されるため、すべてが検出されないことに注意してください。この場合、すべてのハイフンを削除し、ハイフンが削除された後に単語を一致させることができます。これを行うには、分割関数の直前に次の行を追加するだけです。

<*> .= $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ファイルに次が含まれている場合:

<*>

また、テキストtext.txtには、投稿のテキスト、次のコマンドが含まれています:

<*>

印刷されます:

<*> \ 。この場合、行の最後の文字がハイフンであるかどうかを確認し、ハイフンである場合は、行を単語に分割する前にハイフンを削除して別の行を読み取るだけです。

編集:大文字と小文字を区別せずに単語を処理し、複数行にわたるハイフン付きの単語を処理する更新バージョン。

ハイフンでつながれた単語があり、その一部は行をまたいで分割され、一部は分割されない場合、行末のハイフンのみが削除されるため、すべてが検出されないことに注意してください。この場合、すべてのハイフンを削除し、ハイフンが削除された後に単語を一致させることができます。これを行うには、分割関数の直前に次の行を追加するだけです。

<*>

他のヒント

次のようなスクリプトでこの種のことを行います(bash構文):

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

個々の単語を区切るために使用する正規表現を調整できます。この例では、空白を区切り文字として扱います。 grepの-f引数は、関心のある単語を1行に1つずつ含むファイルです。

最初に、字句解析とスキャナージェネレーター仕様の作成方法に精通します。 YACC、Lex、Bison、または私の個人的なお気に入りであるJFlexのようなツールの使用に関する紹介をお読みください。ここで、トークンを構成するものを定義します。ここで、トークナイザーの作成方法について学習します。

次に、シードリストと呼ばれるものがあります。ストップリストの反対は、通常、スタートリストまたは限定辞書と呼ばれます。語彙も学習するのに適しています。アプリの一部は、すぐにクエリを実行できるように、開始リストをメモリに読み込む必要があります。保存する一般的な方法は、1行に1ワードのファイルを作成し、アプリの起動時に1回、マップのようなものに読み込むことです。ハッシュの概念について学びたいかもしれません。

ここから、結果を保存するために必要な基本的なアルゴリズムとデータ構造について考えます。分布は、2次元のスパース配列として簡単に表されます。スパース行列の基礎を学びます。それが何をするのかを理解するのに6ヶ月の線形代数は必要ありません。

より大きなファイルを扱うため、ストリームベースのアプローチを推奨します。ファイル全体をメモリに読み込まないでください。トークンのストリームを生成するトークナイザーへのストリームとして読み取ります。

アルゴリズムの次の部分では、トークンリストを必要な単語のみを含むリストに変換する方法について考えます。考えてみると、リストはメモリ内にあり、非常に大きくなる可能性があるため、開始時に非開始語を除外することをお勧めします。したがって、トークナイザーから新しいトークンを取得する重要なポイントで、トークンリストに追加する前に、メモリ内のstart-words-listで検索を行い、単語が開始単語かどうかを確認します。その場合、出力トークンリストに保持します。それ以外の場合は無視して、ファイル全体が読み取られるまで次のトークンに移動します。

これで目的のトークンのリストができました。重要なのは、位置やケース、コンテキストなどの他のインデックス指標を見ていないということです。したがって、すべてのトークンのリストは本当に必要ありません。カウントが関連付けられた個別のトークンのまばらなマトリックスが必要なだけです。

したがって、最初に空のスパース行列を作成します。次に、解析中に新しく見つかったトークンの挿入について考えます。発生した場合、リストにある場合はカウントをインクリメントするか、カウント1の新しいトークンを挿入します。今回は、ファイルの解析の最後に、少なくともそれぞれの頻度の個別のトークンのリストがあります。 1。

そのリストはインメモリになり、あなたは何でもできます。それをCSVファイルにダンプするのは、エントリを繰り返し処理し、各エントリをその行数ごとに書き込むという簡単なプロセスです。

その点については、「GATE」と呼ばれる非営利製品をご覧ください。またはTextAnalystなどの商用製品または http://textanalysis.info

にリストされている製品

時間の経過とともに新しいファイルが導入されると思いますが、それが状況の変化の仕方ですか?

あなたの最善の策は、オプション2のようなものを使うことだと思います。キーワードの出現をカウントするだけなら、ファイルを前処理することはあまり意味がありません。リスト内の単語が表示されるたびにカウントして、各ファイルを1回調べます。個人的にはRubyでやりますが、perlやpythonのような言語もこのタスクを非常に簡単にします。たとえば、キーとしてキーワードを使用し、値として出現回数を使用した連想配列を使用できます。 (ただし、発生に関する詳細情報を保存する必要がある場合、これはあまりにも単純すぎるかもしれません。)

ファイルごとに情報を保存するのか、データセット全体に関する情報を保存するのかわかりませんか?組み込むのはそれほど難しくないでしょう。

取得したデータをどう処理するかはわかりません。必要なものが得られれば、スプレッドシートにエクスポートしても問題ありません。または、長期的に見れば、データを適切に表示する余分なコードを少し書くだけで簡単になるかもしれません。データをどのように処理するかによって異なります(たとえば、演習の最後にいくつかのグラフを作成してレポートに入れたい場合は、CSVにエクスポートするのが最も理にかなっていますが、生成したい場合は、 1年ごとに毎日新しいデータセットを作成し、それを自動的に実行するツールを構築することは、ほぼ間違いなく最良のアイデアです。

編集:あなたは歴史を勉強しているので、ドキュメントが時間とともに変化するのではなく、すでに起こった一連の変化を反映している可能性があります。誤解して申し訳ありません。とにかく、私が上記で述べたほとんどすべてがまだ当てはまると思いますが、CSVへのエクスポートや、自動表示ではなくあなたが持っているものに向かって傾くでしょう。

楽しいプロジェクトのように聞こえます-幸運を祈ります!

ベン

「grep」を実行しますファイル上で、キーワードを含むすべての行を見つけます。 (grep -fは、検索する単語の入力ファイルを指定するために使用できます(grepの出力をファイルにパイプします)。これにより、単語のインスタンスを含む行のリストが表示されます。単語の区切り文字(ほとんどの場合スペース)を改行で置き換え、個別の単語(1行に1単語)のファイルを作成します。今度は同じ単語リストを使用して、grepを再度実行します。指定された単語を含む行の数、つまり元のファイル内の単語の出現数)。

2パス方式では、「sed」の作業が簡単になります。最初のgrepは多くの行を削除する必要があります。

これはすべて、基本的なLinuxコマンドラインコマンドで実行できます。プロセスに慣れたら、すべてを簡単にシェルスクリプトに入れることができます。

別の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 をお勧めします。これにより、入力データとは無関係に出力を調整できます。

大きなスクリプトで地獄へ。 すべての単語をつかむつもりなら、このシェル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 をパイプラインに挿入してみてください(テストされていません)。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top