よって、この文書の単語数は$9$です。1/9$のようになります。ゆえに、この文書に関するtf値は、競技プログラミングに関してのみ$2/9$、それ以外の単語は$1/9$の$8$次元のtf値のベクトルとして見ることができます。tf値が高い競技プログラミングがこの文書のキーワードと言えそうです。tfの欠点ただ、このtfのみでは文書のキーワードを求めることができません。$私の彼の夫の弟の姉は姉だみたいな文章があったとします。)このとき、この文書で一番大きいtf値はなんでしょうか?当然、「の」になってしまいます。出現頻度が大きいからです。このように出現頻度が大きいだけでは、このキーワードが重要かどうかは計ることができません。そこで、$idf$の概念を取り入れます。Frequencyの略であり、日本語では逆文書頻度といいます。この値で分かることは、ある単語$t$がより多くの文書に含まれているとしたとき、その単語$t$はあまり特徴的とは言えない、ということです。ような単語は、日本語の文書を$2000$個集めたら、$1990$個くらいには入ってそうです。このように一杯の文書に入っている単語は当然重要とはいえません。逆に、$2000$個の文章のうち$10$個ぐらいにしか入っていない単語$t$があれば、この単語$t$は重要・文書を特徴づけるといえます。$idf$の計算式は以下のようになります。1}})$$以上の式において、$N$は集めた文書数、$t$は単語を表します。0$$みたいな計算式になります。よって、より多くの文書に含まれる単語$t$ほど、Inversed・分数を使っているため、逆にidfの値は小さくなります。1.61$$のように大きくなります。ここで、注意するべきなのが$tf$は文書$d$に関する単語$t$の割合・重要度$idf$は単語$t$の全体における逆文書頻度であり、$tf$では文書$d$の単語$t$に関するものですが、$idf$は全体の文書を見ているので単語$t$のみしか引数にとらない関数です。ここの違いが頭に入ると見通しが立つ気がします。分母の+1は0除算を防ぐために使用します。tf-idfついに、tf-idfについてです。tfは、文書$d$において単語$d$の重要度・割合を表します。tfのみではですのような最もよく出てくる単語が重要視されてしまいます。そこで、idfという単語$t$のレアリティを求めることで、$tf$をある意味抑制する(ですなど)効果をもたせます。$tf-idf$の計算式は以下です。idf(t)$$tf値にそのままidf値をかけたものです。シンプルに書くことができます。scikit-learnとMecabでtf-idfを求めるそれでは、実際にscikit-learnとMecabでtf-idfを求めてみます。MecabMecabとは文書や文章を形態素解析して、単語ごとに分かち書きしてくれるライブラリです。英語なら単語と単語ごとに半角スペースが入っているため単語にすぐ分割できるのですが、日本語は非常に扱いづらい文法であるため、Mecabなどの形態素解析ライブラリで分割してからtf-idf値を求めます。Mecabの導入は多くの記事で扱われているため、各OSごとに参考にしてみてください。mecab-python3というライブラリを使用していきます。先程tweetsフォルダに入っているすべてのライバーの文書のパスを取り出したいのでpathlibライブラリを使用して取り出します。あとは実際に文書を取得してMecabで分かちをしていきます。sklearnでtf値を求める自然言語処理や科学処理に多く用いられるライブラリscikit-learnを使って、tf値を求めていきます。CountVectorizertf値を求めるには、上記のCountVectorizerクラスを使用します。出現する単語の出現頻度をベクトル化してくれるクラスです。実際に使用してみます。count_vectorizer.fit_transform(corpus)上記のようにすればtf値を計算できます。このままだとtfがよくわからないので追加で色々とprintで調べてみます。24218)$の形になっていてこれは$87$個の文書があり、その$87$個の文書に$24218$だけの単語が存在しているようです。文書dにおける単語tの頻度$$というタプルで格納されているようです。次にtfのtoarray()を調べてみます。先程のprint(tf)では関係あるもののみを取り出したものですが、toarray()はどうやら、$87{\times}24218$、つまりすべての文書*総単語の二次元配列を返すようです。それぞれの配列の中の数字は出現頻度を表しています。0]は、ID0の単語が文書0に3回出現していることを表します。print(count_vectorizer.get_feature_names())get_feature_names()をvectorizerオブジェクトに使うと、すべての学習した単語を返します。この学習したが大事であり、fit_transoformにコーパスを入れるとコーパスを解析してtfベクトルを計算しながら、vectorizerモデルを学習して作ってくれます。これによって、文書にどれくらい単語が出てくるかを記憶してくれます。print(count_vectorizer.vocabulary_)vectorizerのvocaburary_オブジェクトで、それぞれの単語に値するIDを取得することができます。ように変更しましょう。tfidf値を計算する今度はsklearnでtfidf値を計算します。TfidfTransformer上記のTfidfTransformクラスを利用します。実際に使用してみます。tfidf値が計算できました。tfidf値はtf値と同様にprintを行うことができます。tfidf$のような形式で取得することができます。試しに卯月コウの特徴的な単語を取り出してみる試しに、自分の一番好きなライバー卯月コウの最も特徴的な単語を$10$個取り出してみます。卯月コウのTwitterアカウント名は卯月コウとシンプルなので取り出しやすいのも嬉しいです。print(uduki_id)となり、卯月は$83$番目の文書のようです。(0-index)よって、$83$番目の文書を解析していきます。uduki_tfidfで卯月コウのtfidf値を求めます。indicesを持っています。dataは、uduki_tfidfのifidf値の配列です。indicesは、uduki_tfidfの単語IDの配列です。tfidfの値の大きいものを使用したいので、numpyのargsortをuduki_tfidf.dataに行います。これはitdifの小さい順なので大きい順にするために[::-1]でReverseをします。上位$20$単語にしぼりたいため、[:20]で絞ってあげます。180]のインデックスにあることが分かりました。実際に、単語IDのインデックスを上位順に取得してみます。'''上位$20$件を取り出してみました。・の・に・た・からのような助詞が多く入ってしまったのは痛いです。原因としては文書数が少ない一字を許しているMecabで文書数が少ないなら外すべきだったといったものがあると思います。Yay!コサイン類似度で似ているライバー同士を探すtf-idfで各メンバーの発言の特徴量tfidf値をベクトルとして取り出しました。今度はコサイン類似度を使って、このベクトルがどれくらい似ているか?を計算します。このコサイン類似度を利用することでどのライバーとどのライバーが似ているか?を多少なりとも分析することができます。b$のベクトルがにているか?を表します。b$のベクトルは$90$度以内の差以内であるため、値が大きいほど似ていると判定できます。b$のベクトルは正反対側を互いに向いているため、かなり似ていないと判定できます。今回tfidf値は必ず$0$以上にベクトルの要素単語$t$に関して成り立つため、内積の結果は$0$以上の値になります。このままでは問題がありベクトル自体が大きいほど内積も大きくなる傾向にあるため、各ベクトルの大きさで割ってあげましょう。これがコサイン類似度になります。b){\leq}1$の値の範囲を取ります。値が大きいほど2つのベクトルが似ていることを表します。sklearnでコサイン類似度を実際に求めるsklearnにコサイン類似度の関数が同様にあるため、その関数を利用して実際にライバーの類似度を求めてみます。cosine_similarityで取り出すことができます。実際に計算をしてみます。それぞれのライバーに似ているライバーは誰なのかを判定していきます。Mecabのアップデートここで、一度脇道にそれますが、Mecabの辞書をより良いものに更新したいと思います。https://www.pytry3g.com/entry/2018/04/24/143934#ipadic%E3%81%A8NEologd%E3%81%AE%E4%BD%B5%E7%94%A8の記事を参考にhttps://github.com/neologd/mecab-ipadic-neologdをインストールしてください。この辞書によってライバーのようなより新しい単語に対応できる可能性が高くなります。0.09921343631642188を得ることができます。sklearnでコサイン類似度を実際に求める・続まず、誰と誰が似ているかを判別するためにライバー名をファイル名から取り出します。exit()次にcosine_similarityを計算します。cosine_similarityにはndarrayを第一引数と第二引数に入れてそれぞれを比べます。入れて、cosine_similarityを計算します。87)$の二次元配列になっているようです。cos_sim[0]は0番目のライバーが、$0$~$N-1$番目のライバーとどれくらい類似しているかのコサイン類似度の値が入っています。よって、$i$番目のライバーと$j$番目のライバーの類似度はcos_sim[i][j]で計算できます。それでは、一人ずつ誰と誰が似ているのかを見てみましょう。numpyの添字指定ができると取り出しやすいのでliver_namesをndarrayにしておきます。$i$番目のライバー名を取り出し、類似度配列を取り出します。その後、先程と同様に添え字ソートで大きい順にソートし、自分は除きます。(自分とは当然一致するので)あとはprintをします。結果は以下のようになります。]結果を見るとどうやら特定のライバーがよく似ていると判定されています。したら、ライバーのツイートが特有のものだったり、他の人の名前を利用していたりするとこのような結果になるのかもしれません。比較的交友関係がありそう?な部分も多少見られるので結果は良しとします(おい)やはりデータ数$87$では特徴的なキーワードが出しづらいのかもしれません。おまけ各ライバーごとに特徴的な単語を求めてみます。上記のコードでは、toke_patternを消して、一文字系を消してみました。「て」「に」のような助詞が多く入るためです。一部切り出しですが、だいぶその人っぽいデータが取れています!うれしいです!最後にはじめて、自然言語処理をやってみました。長くなってしまいましたが、tf-idfはかなりキーワードをスパッととれるなぁと思いました。他にもWord2Vec・Doc2Vecという概念があるようなのでそちらも勉強していきたいです。