pythonでfasttextを使って文書分類してみた

# はじめに
- 文書分類をしたくなりました
- pythonの練習も兼ねて、pythonで実装することにしました

# 前提
- Windows 10 pro バージョン1803
- Windows Subsystem for Linux(WSL)版ubuntu バージョン8.04 LTS (Bionic Beaver)

# 全体の流れ
1. linuxを用意する
2. pythonを入れる
3. 日本語コーパスを手に入れる
4. 日本語パーサーを入れる
5. 分類ライブラリを入れる
6. 教師データを作る
7. モデルを作る
8. 分類する

# Windows Subsystem for Linux(WSL)でubuntuを入れる
- [こちらの記事](https://qiita.com/ezmscrap/items/7a7f555faf7371a56e9d#windows-subsystem-for-linuxwslでubuntuを入れる)を参照のこと

# Windows Subsystem for Linuxにssh接続する
- [こちらの記事](https://qiita.com/ezmscrap/items/30eaf9531e240c992cf1)を参照のこと
- 以下、基本的にはteratermで作業

# viを初心者でも使いやすくする
- [こちらの記事](https://qiita.com/ezmscrap/items/063f585ed2812cc149d6)を参照のこと
- 初心者なりに、以下、ソースはvimでがりがり書いていきます

# gitに最低限の設定をする
- gitはバージョンによっては最低限の設定をしないとgit clone出来ないので最低限の設定をする

```
git config --global user.name "First-name Family-name"
git config --global user.email "username@example.com"
```

- gitでコミットした時に起動するエディタがnanoなのは初心者には不便なので、vimにする
- ソースを書くときは出来る限りコミットは細かくして、コミット理由も日本語で良いので書いた方がいい
- 後で楽が出来ます

```
git config --global core.editor 'vim -c "set fenc=utf-8"'
```

- ついでに、色も付けておく
- 不要なら設定しなくても良い

```
git config --global color.diff auto
git config --global color.status auto
```

# pythonを入れる
- [Anacondaのページ](https://www.anaconda.com/download/)に行って、linux版の最新版のダウンロードurlを「リンクのアドレスをコピー」で取得
- あとは、wgetでファイルを取得してインストールコマンドを入力

```
wget https://repo.anaconda.com/archive/Anaconda3-5.2.0-Linux-x86_64.sh
bash Anaconda3-5.2.0-Linux-x86_64.sh
```

- 上記のurlは記事作成時点の最新なので、適宜修正する
- 最初はライセンスが表示されるので、スペースで読み進める
- ライセンスに同意するか聞かれるので同意する

```
Do you accept the license terms? [yes|no]
[no] >>> yes
```

- インストール場所を聞かれるので、特にこだわりがなければエンターで進める

```
  - Press ENTER to confirm the location
  - Press CTRL-C to abort the installation
  - Or specify a different location below

[/home/hoge/anaconda3] >>>
```

- 環境変数にAnaconda3のパスをいれるか聞かれるので、好みによって、yesを入力する
- 迂闊にyesにすると、curlがAnaconda環境のものを優先使用するようになったりするので、各自の判断でどうぞ
- noを選んでも、「export PATH=(アナコンダをインストールしたパス)/anaconda3/bin:$PATH」でいつでも使用できるので特に気にしない
- なんなら、あとで、「vi ~/.bashrc」して末尾に、「export PATH=(アナコンダをインストールしたパス)/anaconda3/bin:$PATH」加えて、「source ~/.bashrc」しても同じ

```
Do you wish the installer to prepend the Anaconda3 install location
to PATH in your /home/ubuntu/.bashrc ? [yes|no]
[no] >>> yes
```

- Microsoft VSCodeをインストールするか聞かれるので、不要ならnoを入力する
- vimで編集していくつもりなので、ここではno

```
Do you wish to proceed with the installation of Microsoft VSCode? [yes|no]
>>> no
```

- 編集した.bashrcを有効にする

```
source ~/.bashrc
```

# 日本語コーパスの取得
- [ロンウイット様](https://www.rondhuit.com)が、livedoor ニュースのクリエイティブ・コモンズライセンスが適用されるニュース記事のデータを[公開](https://www.rondhuit.com/download.html#ldcc)してくださっているのでそれを使う
- 上記ページで「収集時期：2012年9月上旬 ダウンロード（通常テキスト）：ldcc-20140209.tar.gz ダウンロード」と書いてあるリンクのダウンロードurlを「リンクのアドレスをコピー」で取得
- 上記urlをwgetして、展開する

```
wget https://www.rondhuit.com/download/ldcc-20140209.tar.gz
tar -zxvf ldcc-20140209.tar.gz
```

# 日本語パーサーを入れる
- 今回はMeCabを使う
- コマンドライン版も入れたけど、もしかしたら、不要かも
- git cloneして、makeしてインストールする

```
git clone https://github.com/taku910/mecab.git
cd mecab/mecab
./configure  --enable-utf8-only
make
make check
sudo make install
```

- 辞書もmakeして、インストールする

```
cd ../mecab-ipadic
./configure --with-charset=utf8
make
sudo make install
```

- もしかしたら、ここまで不要かも
- 以下だけでいいという話を聞いたので、上記までは無視してよいかも

```
pip install mecab-python3
```

- 上記だけで済むならそれに越したことはない
- 念のため、サンプルスクリプトで、日本語のパーシングが出来ることを確認しておく

``` mecab_test.py
import MeCab

def get_token(content):
    tokens = []
    tagger = MeCab.Tagger('')
    tagger.parse('')
    node = tagger.parseToNode(content)
    while node:
        tokens.append(node.surface)
        node = node.next
    return tokens

def main():
    content="これはテストコーパスです。これをうまく分割できるかな？"
    print(get_token(content))

if __name__ == '__main__':
    main()
```

- tagger.parse('')は、やらないと動かない既知の不良を避けるバッドノウハウ
- スクリプトを実行する

```
python mecab_test.py
```

- 以下のように出力されていたらOK

```
['', 'これ', 'は', 'テスト', 'コーパス', 'です', '。', 'これ', 'を', 'うまく', '分割', 'できる', 'か', 'な', '？', '']
```

# 分類ライブラリを入れる
- 今回はFastTextを使う
- git cloneして、makeしてインストールする

```
git clone https://github.com/facebookresearch/fastText.git
cd fastText/
make
```

- makeすると以下のようなメッセージが出るはず

```
c++ -pthread -std=c++0x -march=native -O3 -funroll-loops -c src/args.cc
c++ -pthread -std=c++0x -march=native -O3 -funroll-loops -c src/dictionary.cc
c++ -pthread -std=c++0x -march=native -O3 -funroll-loops -c src/productquantizer.cc
c++ -pthread -std=c++0x -march=native -O3 -funroll-loops -c src/matrix.cc
c++ -pthread -std=c++0x -march=native -O3 -funroll-loops -c src/qmatrix.cc
c++ -pthread -std=c++0x -march=native -O3 -funroll-loops -c src/vector.cc
c++ -pthread -std=c++0x -march=native -O3 -funroll-loops -c src/model.cc
c++ -pthread -std=c++0x -march=native -O3 -funroll-loops -c src/utils.cc
c++ -pthread -std=c++0x -march=native -O3 -funroll-loops -c src/fasttext.cc
c++ -pthread -std=c++0x -march=native -O3 -funroll-loops args.o dictionary.o productquantizer.o matrix.o qmatrix.o vector.o model.o utils.o fasttext.o src/main.cc -o fasttext
```

- エラーが出たりしなければ、pipでインストール

```
pip install fasttext
```

# 教師データを作る
- 上で取得したlivedoorニュースのデータから、教師データを作る

## ファイル一覧を持っておく
- 以下の処理で楽をするために、ファイル一覧を持っておく
- そのためのファイル一覧作成スクリプトを作る

``` make_file_list.py
import os
import sys

def print_list(list):
    for item in list:
        print(item)

def get_files(path,file_list):
    for file in os.listdir(path):
        full_path = path + file
        if os.path.isfile(full_path):
            file_list.append(full_path)
        elif os.path.isdir(full_path):
            get_files(full_path + "/",file_list)

def main(argv):
    path = argv[0]
    file_list = []
    get_files(path,file_list)
    print_list(file_list)

if __name__ == '__main__':
    main(sys.argv[1:])
```

- 日本語コーパスを置いた場所を指定して、標準出力をファイルに吐きだす
- 引数はパスで、そこから再起的にサブディレクトリ内のファイルも出力する
- パスは環境に合わせて修正すること

```
python make_file_list.py /home/hoge/text/ > all_file_list.txt
```

## 分野ごと教師データの元を選ぶ
- 教師データのもとをいれるディレクトリを決める
- 上記ディレクトリを掘っておく
- Politics、Economy、Societyの分類にする予定なので、それも掘っておく
- パスは環境に合わせて修正すること

```
mkdir -p /home/hoge/text_category/Politics
mkdir /home/hoge/text_category/Economy
mkdir /home/hoge/text_category/Society
```

- 日本語コーパスの中からキーワードマッチングして、一致したものを、先ほど掘ったディレクトリに格納するスクリプトを書く
- 二重持ちになるけど気にしない
- キーワードは[産経新聞記事分類](http://t21.nikkei.co.jp/public/help/contract/price/64/bunrui/sankei.html)を参考にした
- カテゴリーが3個だけなのは、キーワードを作るのが面倒くさかったから

``` make_categorize_text.py
import sys

def get_content(file_name):
    contexts = []
    with open(file_name, 'r', encoding='utf-8') as file:
        line = file.readline()
        while line:
            contexts.append(line.strip())
            line = file.readline()
    return ''.join(contexts)

def put_content(file_name,content):
    with open(file_name, 'w', encoding='utf-8') as f:
        f.write(content)

def make_categorized_data(file_list, text_path):
    keyword_dict = {
            'Politics':['政治','国会','選挙','政党','行政','司法','警察','財政','外交','在日外国人','旧日本領土','軍事'],
            'Economy':['経済','金融','株式','貿易','為替','産業','企業','農林','水産','鉱業','工業','運輸','通信','土木','建築','商業'],
            'Society':['社会','厚生','医事','衛生','公害','地球','環境','生活','料理','住生活','婦人','子供','青少年','趣味','娯楽','観光','旅行','行事','祝祭','世相','風俗'],
            }
    file_num = {
            'Politics':'0',
            'Economy':'0',
            'Society':'0',
            }
    for file_name in file_list:
        content = get_content(file_name)
        flag = -1
        for category in keyword_dict.keys():
            for keyword in keyword_dict[category]:
                flag = content.find(keyword)
                if flag > -1:
                    break
            if flag > -1:
                full_path_file_name = text_path+category+'/'+category+file_num[category]
                put_content(full_path_file_name,content)
                file_num[category] = str( int(file_num[category]) + 1 )

def get_file_list(file_name):
    file_list = []
    with open(file_name, 'r', encoding='utf-8') as file:
        line = file.readline()
        while line:
            file_list.append(line.strip())
            line = file.readline()
    return file_list

def main(argv):
    file_name = argv[0]
    text_path = argv[1]
    file_list = get_file_list(file_name)
    make_categorized_data(file_list, text_path)

if __name__ == '__main__':
    main(sys.argv[1:])
```

- 教師データのもとになるデータを作る

```
python make_categorize_text.py all_file_list.txt /home/hoge/categorized_text/
```

- 教師データのもとになるデータのリストを作る

```
python make_file_list.py /home/hoge/categorized_text/ > categorized_file_list.txt
```

## 教師データを作る
- 教師データは、以下のような構造になっている

```
__label__0  「 三浦 春 馬 」 さん と ドライブ に 行き たい 1 月 17 日 に スタート し た 、 三浦 春 馬 さん …
__label__0  “ 神社 コンシェルジュ ” が 選ぶ 、 恋愛 成就 を 祈願 し て 、 美人 証明 を 受ける …
: 
__label__1  ・ 解説 － 怪物 と の 戦い 、 その ピーク － ドラマ 『 クリミナル・マインド ／ FBI vs . 異常 犯罪 』…
:
```

- 先頭に`__label__(数字)`で、あとは分かち書きされたテキスト列になっている
- 分かち書きには、日本語パーサとして入れたMeCabを使用する
- labelと分類の対応辞書もついでに作る

``` make_training_data.py
import MeCab
import os
import re
import sys

def get_content(file_name):
    contexts = []
    with open(file_name, 'r', encoding='utf-8') as file:
        line = file.readline()
        while line:
            contexts.append(line.strip())
            line = file.readline()
    return ''.join(contexts)

def get_token(content):
    tokens = []
    tagger = MeCab.Tagger('')
    tagger.parse('')
    node = tagger.parseToNode(content)
    while node:
        tokens.append(node.surface)
        node = node.next
    return tokens

def get_file_name(path):
    return os.path.basename(path)

def get_label(path,label_dict):
    file_name = get_file_name(path)
    name, ext = os.path.splitext(file_name)
    category_name = re.sub(r'[0-9]+','',name)
    if category_name in label_dict.keys():
        label = label_dict[category_name];
    else:
        label = label_dict['category_number']
        label_dict[category_name] = label
        label_dict['category_number'] = str( int(label) + 1)
    return str(label)

def make_training_data(file_list,label_dict):
    for file_name in file_list:
        print_training_data(file_name,label_dict)

def format_content(content):
    content = re.sub(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-…]+', "", content)
    return content

def print_training_data(path,label_dict):
    content = get_content(path)
    content = format_content(content)
    tokens = get_token(content)
    text = ' '.join(tokens)
    label = get_label(path,label_dict)
    print('__label__'+label+' '+text)

def get_file_list(file_name):
    file_list = []
    with open(file_name, 'r', encoding='utf-8') as file:
        line = file.readline()
        while line:
            file_list.append(line.strip())
            line = file.readline()
    return file_list

def output_dict(file_name, label_dict):
    with open(file_name, mode='w', encoding='utf-8') as file:
        for key, value in label_dict.items():
           file.write(key+':'+value+'\n')

def main(argv):
    #file_name = ""
    #dict_name = ""
    file_name = argv[0]
    dict_name = argv[1]
    label_dict = {'category_number':'0'}
    file_list = get_file_list(file_name)
    make_training_data(file_list,label_dict)
    output_dict(dict_name, label_dict)

if __name__ == '__main__':
    main(sys.argv[1:])
```

- 教師データのもとになるデータのリストとラベルの辞書名を指定して、標準出力をファイルに吐きだす
- 引数は、第一引数が教師データのもとになるデータのリストのファイル、第二引数がラベルの辞書名
- パスは環境に合わせて修正すること

```
python make_training_data.py categorized_file_list.txt dictiory > training_data.txt
```

# モデルを作る
- fasttextの機能でサクッとモデルを作成

``` make_model.py
import fasttext as ft
import sys

def main(argv):
    input_file = argv[0]
    output_file = argv[1]
    ft.supervised(input_file, output_file, label_prefix='__label__', thread=8)

if __name__ == '__main__':
    main(sys.argv[1:])
```

- 引数は、第一引数が教師データ、第二引数が出力するモデル名
- ファイル名は環境に合わせて修正すること

```
python make_model.py training_data.txt model
```

# 分類する
- おまちかねの分類タイム

## コマンドラインから入力した文章を分類する
- 引数に直接文字列を渡し、その文字列を分類してみる

```fasttext_check.py
import fasttext as ft
import MeCab
import sys

def get_score(result,label_dict):
    scores = []
    for item in result:
        scores.append(label_dict[item[0]]+':'+str(item[1]))
    return scores

def get_label_dict(dict_name):
    dictionay = {}
    with open(dict_name, 'r', encoding='utf-8') as f:
        line = f.readline()
        while line:
            category_name, category_number = line.split(':')
            dictionay['__label__'+category_number.strip()] = category_name
            line = f.readline()
    return dictionay

def get_token(content):
    tokens = []
    tagger = MeCab.Tagger('')
    tagger.parse('')
    node = tagger.parseToNode(content)
    while node:
        tokens.append(node.surface)
        node = node.next
    return tokens

def main(argv):
    model_name = argv[0]
    dict_name = argv[1]
    content = argv[2]
    label_dict = get_label_dict(dict_name)
    classifier = ft.load_model(model_name)
    tokens = get_token(content)
    estimate = classifier.predict_proba([' '.join(tokens)], k=3)
    scores = get_score(estimate[0],label_dict)
    print(file_name, scores)

if __name__ == '__main__':
    main(sys.argv[1:])
```

- 第一引数にモデル名、第二引数に辞書名、第三引数に分類したい文字列を入れる
- モデル名は、指定したモデル名の後ろに拡張子.binが付くので注意

```
python fasttext_check.py model.bin dictiory 自民党の党・政治制度改革実行本部（塩崎恭久本部長）は１３日、党本部で総会を開き、党改革に関する提言案をまとめた。
```

- 結果は以下の通り

```
['Society:0.529297', 'Economy:0.361328', 'Politics:0.105469']
```

- あかん。Politicsのつもりだったけど、一番低い
- 次、経済っぽい文字列

```
python fasttext_check.py model.bin dictiory パウエル議長は12日、ラジオ局アメリカン・パブリック・メディアの番組でインタビューに応じ、「米経済は非常に良好」で失業率が近年まれに見る低水準にあり、インフレ率は当局の目標とする２％に近いと述べた。
```

- こちらも、あかん感じ
- Politicsは下がったけど、Economyも下がって、Societyが上がっている始末

```
['Society:0.585938', 'Economy:0.34375', 'Politics:0.0664063']
```

- 最後に、社会っぽい文字列も入れてみる

```
python fasttext_check.py model.bin dictiory 人生100年時代とも言われるこれからの時代においては、技術の進展に伴う産業構造の変化や、長寿命化社会の到来など、大きな転換に直面することになる。こうした時代においては、新たなステージで求められる能力・スキルを身に付けながら、個人が主体的に人生を再設計できるよう、経済社会環境の変化に対応した社会人の学び（リカレント教育）を推進することが重要である。
```

- まぁ、Societyが上がって、EconomyとPoliticsは下がってる
- と、いえなくもないかな

```
['Society:0.609375', 'Economy:0.333984', 'Politics:0.0527344']
```

## ファイル一覧を渡してまとめて分類する
- 日本語コーパスを全てぶち込んでみる

```fasttext_test.py
import fasttext as ft
import MeCab
import sys

def get_score(result,label_dict):
    scores = []
    for item in result:
        scores.append(label_dict[item[0]]+':'+str(item[1]))
    return scores

def get_label_dict(dict_name):
    dictionay = {}
    with open(dict_name, 'r', encoding='utf-8') as f:
        line = f.readline()
        while line:
            category_name, category_number = line.split(':')
            dictionay['__label__'+category_number.strip()] = category_name
            line = f.readline()
    return dictionay

def get_content(file_name):
    contexts = []
    with open(file_name, 'r', encoding='utf-8') as f:
        line = f.readline()
        while line:
            contexts.append(line.strip())
            line = f.readline()
    return ''.join(contexts)

def get_token(content):
    tokens = []
    tagger = MeCab.Tagger('')
    tagger.parse('')
    node = tagger.parseToNode(content)
    while node:
        tokens.append(node.surface)
        node = node.next
    return tokens

def get_file_list(file_name):
    file_list = []
    with open(file_name, 'r', encoding='utf-8') as f:
        line = f.readline()
        while line:
            file_list.append(line.strip())
            line = f.readline()
    return file_list

def main(argv):
    model_name = argv[0]
    dict_name = argv[1]
    test_data = argv[2]
    label_dict = get_label_dict(dict_name)
    classifier = ft.load_model(model_name)
    file_list = get_file_list(test_data)
    for file_name in file_list:
        content = get_content(file_name)
        tokens = get_token(content)
        estimate = classifier.predict_proba([' '.join(tokens)], k=3)
        scores = get_score(estimate[0],label_dict)
        print(file_name, scores)

if __name__ == '__main__':
    main(sys.argv[1:])
```

- 第一引数にモデル名、第二引数にラベル辞書名、第三引数にファイル一覧ファイルを渡す
- 結果は標準出力なので、ファイルで受ける

```
python fasttext_test.py model.bin dictiory all_file_list.txt > result.txt
```

- 分類結果を見てみる
- 分類順はSociety > Economy > Politicsがずらりと並んでいた

``` result.txt
/home/hoge/text/peachy/peachy-6731010.txt ['Society:0.625', 'Economy:0.326172', 'Politics:0.0449219']
:
/home/hoge/text/smax/smax-6913983.txt ['Society:0.507812', 'Economy:0.367188', 'Politics:0.121094']
:
/home/hoge/text/sports-watch/sports-watch-4604621.txt ['Society:0.582031', 'Economy:0.34375', 'Politics:0.0703125']
:
```

- なんか全部、Societyに一番近いことになってしまった。
- 教師データの作り方があかんかった気がする
- 教師データの元になるデータを見てみたが、どの分類も似たような文書が渡されてしまっていたようだった
- キーワードで絞り込んで教師データの元になるデータを作るのは無理があったようだ

# 考察
- 教師データの元となるデータの数を調べてみた

```
ls /home/hoge/text_category/Politics/ | wc
    320     320    3730
ls /home/hoge/text_category/Economy/ | wc
   1561    1561   17622
ls /home/hoge/text_category/Society/ | wc
   2518    2518   29106
```

- 10倍近く差があった
- これが悪影響を与えた可能性がある

# 改善案1
- とりあえず、教師データを300個づつに制限してみる
- categorized_file_list.txtを加工すればよい
- viで開いて、「/Politics」に飛んで「20dd」で20行削除
- 「/Economy」に飛んで「1261dd」で1261行削除
- 「/Society」に飛んで「2218dd」で2218行削除
- 確認する

```
grep Society categorizd_file_list2.txt | wc
    300     300   16805
grep Economy categorized_file_list2.txt | wc
    300     300   16770
grep Politics categorized_file_list2.txt | wc
    300     300   17292
```

- いい感じ
- あとは同じ
- 折角だからファイル名などはあとで比較できるように、変えた

```
python make_training_data.py categorized_file_list2.txt dictiory2 > training_data2.txt
python make_model.py training_data2.txt model2
```

- モデルを作ったので、チェックする

```
python fasttext_check.py model2.bin dictiory2 自民党の党・政治制度改革実行本部（塩崎恭久本部長）は１３日、党本部で総会を開き、党改革に関する提言案をまとめた。
['Politics:0.332031', 'Economy:0.332031', 'Society:0.332031']

python fasttext_check.py model2.bin dictiory2 パウエル議長は12日、ラジオ局アメリカン・パブリック・メディアの番 組でインタビューに応じ、「米経済は非常に良好」で失業率が近年まれに見る低水準にあり、インフレ率は当局の目標とする２％に近いと述べた。
['Politics:0.332031', 'Economy:0.332031', 'Society:0.332031']

python fasttext_check.py model2.bin dictiory2 人生100年時代とも言われるこれからの時代においては、技術の進展に伴う産業構造の変化や、長寿命化社会の到来など、大きな転換に直面することになる。こうした時代においては、新たなステージで求められる能力・スキルを身に付けながら、 個人が主体的に人生を再設計できるよう、経済社会環境の変化に対応した社会人の学び（リカレント教育）を推進することが重要である。
['Politics:0.332031', 'Economy:0.332031', 'Society:0.332031']
```

- 悪化している
- 全てのカテゴリの評価値が0.332031になっている、怪しいことこの上ない
- 300件程度では学習ができないのか、教師データの作り方が間違っていたのか不明
- web上で調べたデータでは3,000件からの学習データを用意しているので、少なすぎなのかなぁと首をかしげていました

# 改善案2
- 投稿してみると、関連記事に[「scikit-learnとgensimでニュース記事を分類する」](https://qiita.com/yasunori/items/31a23eb259482e4824e2)があったので読んでみた
- その結果、名詞に絞った方がよさそうなことが分かった
- また、300では少なすぎるならば、分類をSocietyとEconomyに絞って、それぞれ1561件にしてみることにした
- 上と同じようにcategorized_file_list.txtを操作して件数を調整

```
grep Society categorizd_file_list3.txt | wc
   1561    1561   87969
grep Economy categorizd_file_list3.txt | wc
   1561    1561   87867
grep Politics categorizd_file_list3.txt | wc
      0       0       0
```

- トークンを名詞だけにするようにスクリプトを改変
- 具体的にはmake_training_data.pyのdef get_token(content):内の処理

``` make_training_data.py
def get_token(content):
    tokens = []
    tagger = MeCab.Tagger('')
    tagger.parse('')
    node = tagger.parseToNode(content)
    while node:
        if node.feature.split(',')[0] == '名詞':
            tokens.append(node.surface)
        node = node.next
    return tokens
```

- これでモデルを再作成してまとめて分類してみた
- 「しいて言えば、SocietyとEconomyのどちらか」の分類が出来るはず

```
python make_training_data.py categorized_file_list3.txt dictiory3 > training_data3.txt
python make_model.py training_data3.txt model3
python fasttext_test.py model3.bin dictiory3 all_file_list.txt > result3.txt
```

- 結果ファイルを見ると、マシになっていた
- 一ジャンルに1000文書以上は必要のようだ

``` result3.txt
/home/hoge/text/dokujo-tsushin/dokujo-tsushin-5619249.txt ['Economy:0.53125', 'Society:0.466797']
:
/home/hoge/text/it-life-hack/it-life-hack-6306744.txt ['Society:0.5', 'Economy:0.498047']
:
/home/hoge/text/kaden-channel/kaden-channel-6249654.txt  ['Economy:0.501953', 'Society:0.496094']
:
/home/hoge/text/kaden-channel/kaden-channel-6250765.txt ['Society:0.511719', 'Economy:0.486328']
```

- 中を少し見てみる

``` dokujo-tsushin-5619249.txt
6月9日「ロックの日」10周年記念に“MIWA ROCK!!”に新モード「HARD」が追加
MIWA ROCK!!
```

- 上記の記事のスコアは['Economy:0.53125', 'Society:0.466797']
- あぁ、このに分類には入らないものを強引に入れてるので理不尽感が漂う

``` it-life-hack-6306744.txt
毅然とした態度で臨んでいく！グリー田中社長が訴訟の判決にコメント
グリーは2012年2月23日、ディー・エヌ・エー及びORSOを被告とする著作権侵害差止等請求訴訟（以下「本訴訟」）を提起していたが、本日、東京地方裁判所より、ディー・エヌ・エーらに対して、同社への損害賠償として2億3,460万円の支払い及び「釣りゲータウン2」の配信行為等の差止を命じる判決が下されたことをあきらかにした。
```

- 上記の文書のスコアは['Society:0.5', 'Economy:0.498047']。まぁ社会情勢っぽいから、Society優勢は分かる

``` kaden-channel-6249654.txt
どうしたmixi！　減収減益で最終損益は61.6％減の４億7,400万円【ニュース】
人気ＳＮＳ「mixi」が2012年３月期第３四半期の連結業績を発表した。これによると最終損益が前年同期比△61.6％の４億7,400万円となり、減収減益だった。「mixiゲーム」による課金売上は順調に拡大しているが、スマートフォン利用の拡大に伴うモバイル広告の出稿減少が原因だという。

はっきりと数字が出たことにより、ネット上では「もうダメなのか？」「衝撃！」などいう驚きのコメントが見られる。
```

- 上記の文書のスコアは['Economy:0.501953', 'Society:0.496094']。わずかな差だが、確かにEconomyっぽい内容に見える
- 以上から、「一分類1500文書程度の教師データがあると、最低限の分類が出来そう」と分かった
- 少なくとも常にどちらかに判定されたり、同じ値が出続けることは無くなった

# おわりに
- 今回の試みは納得のいかない結果に終わった
- 得られた教訓は教師データ作成の難しさだった
- pythoの基本的なコーディングとfasttextの基本的な使い方が分かったので良しとする