Help us understand the problem. What is going on with this article?

Twitterのユーザーと文豪をAIで比較する

自己紹介

どうもこんにちは、ネプソンこと杉山航です。
N高等学校通学コースプログラミングクラス所属の2年生(N高3期生)です

各種リンク貼っておきます。

普段は機械学習を使った自然言語処理を主に開発しています

まえがき

  • この記事はチームラボさんでLTした内容を中心に進めていきます。
    その時のスライドはこちらです

  • 見せるのも恥ずかしいようなコードしかありませんがGitHubリポジトリはこちらです

作ったもの(制作途中)

タイトルの通り、TwitterのTweetをスクレイピングで取得し、人工知能に学習させ、青空文庫に掲載されている作家との類似度を出力するプログラムです。

実行環境

MacBookPro15(2017)
Mac OS High Sierra
Python==3.6
gensim==3.5.0
beautifulsoup4==4.6.3
requests==2.19.1
mecab-python3==0.996.1

記入漏れがあった場合コメントをくださいると幸いです。

Tweetを取得

Tweetの取得にはBeautifulSoup4RepuestsいうPythonの外部ライブラリを使用し、スクレイピングを行いました。

GitHubに載っているコードでは、同時に分かち書きを行い、のちに学習しやすいようcorpusというtxtファイルの一行目に追加してくれています。

こちらがツイートを取得し、テキストファイルに書き込むだけの単純なコードです。

tweget.py
import requests
import bs4
import re
import MeCab #学習させるための魔法
import sys

userurl = 'https://twitter.com/TWITTERID'#ツイートを取得したいユーザーのID
html = requests.get(userurl)
if html.status_code == 404:
    print('ユーザーがいません')
    exit()
soup = bs4.BeautifulSoup(html.text, 'html.parser')
tweets = soup.select('.js-stream-item')
result = ""
for n,l in enumerate(tweets):
    print(l.p.text)
    result += str(l.p.text)

result = re.sub(r'\r','',result) #のちに説明(Doc2Vecの仕様上)
result = re.sub(r'\n','',result) #のちに説明(Doc2Vecの仕様上)

corpus = m.parse(result) #学習させるための魔法

with open("tweet.txt", "w") as f:
    f.write(result)

変数userurlを変えなきゃいけないのが億劫なので

tweget.py
userurl = 'https://twitter.com/%s' % input('input user id => ')

こんな感じにしても良いでしょう。

コードの説明

変数htmlにはTwitterのユーザーページのhtmlが入っています。

次の行のif文では、ユーザーが存在していない時の処理をしています(ここではそのまま処理を終了させています)

変数soupに関してはこれを呼んでみたら良いかも知れません。

あとはツイートを取得して変数に代入しています。

テキストマイニング(もどき)とファイル管理

ツイートの取得が終わったら、青空文庫のtxtファイルを持ってきて、学習させられる状態にしましょう。

solid.py
import os
import shutil
import MeCab
import sys
import re

m = MeCab.Tagger("-Owakati")
sys.path.append("/.pyenv/versions/anaconda3-4.3.1/envs/word2vec/lib/python3.6/site-packages")

path = os.getcwd()
path += "/data"#あらかじめ"data"という名前のディレクトリが必要
files = os.listdir(path)
print(files)
files.pop(0) #.DS_Storeを削除
corpus = ""

for i in files:
    print(str(i))
    if str(i[-4:]) == ".txt":
        with open("data/"+str(i)+"","rb") as f:
            binarydata = f.read()
            text = binarydata.decode('shift_jis')
            # ルビ、注釈などの除去
            text = re.split(r'\-{5,}', text)[2]
            text = re.split(r'底本:', text)[0]
            text = re.sub(r'《.+?》', '', text)
            text = re.sub(r'[#.+?]', '', text)
            text = re.sub(r'「','',text)
            text = re.sub(r'」','',text)
            text = re.sub(r'、','',text)
            text = re.sub(r'。','',text)
            text = re.sub(r'?','',text)
            text = re.sub(r'!','',text)
            text = re.sub(r'…','',text)
            text = re.sub(r'(','',text)
            text = re.sub(r')','',text)
            text = re.sub(r'\n','',text)
            text = re.sub(r'\r','',text)
            newpath = path + "/" + re.sub(r'.txt','',str(i))
            if os.path.exists(newpath) == False:
                os.mkdir(newpath)
            if os.path.exists(newpath+".txt") == True:
                print("dataディレクトリを整理します")
                shutil.move(newpath+".txt", newpath)
        result = ""
        with open(""+str(newpath) + "/wakachi.txt", "w") as g:
           text1 = text.splitlines()
           for t in text1:
               result += m.parse(t)
           print("nowrodding... "+str(i)+"")
           g.write(str(result)) # skip first \s
           corpus += result

if corpus != "":
    with open("corpus.txt","a") as f:
        f.write(corpus)
else :
    print("新しいデータはありません")#新しく読み込んだファイルがなければそのまま終了

あらかじめdataディレクトリにtxtファイルを入れておき、正規表現を使ってtxtファイルのみを検出し記号などを除外して新しいファイルを作る+全体コーパスファイルへの書き込みをしています。

改行文字を除外しているのは、Doc2Vecの仕様らしいです。

いよいよ学習

gensimというライブラリを使うと本当に簡単に実装できます!

train.py
#coding: UTF-8
from gensim.models.doc2vec import Doc2Vec
from gensim.models.doc2vec import TaggedDocument

f = open('corpus.txt','r')

trainings = [TaggedDocument(words = data.split(),tags = [i]) for i,data in enumerate(f)]

#print(trainings)
print("学習中")
m = Doc2Vec(documents= trainings, dm = 1, vector_size=300, window=8, min_count=10, workers=4)
print("保存中")
m.save("model/doc2vec.model")
print(m.docvecs.most_similar(0))

これだけです!
最初に文章毎(行毎)にリストへ格納し、それぞれをベクトル上に配置している感じです。

これから

今あるコードに関しては、まだまだ自動化できるところがありそうなので人の手がほとんど触れなくてもenterキーを押したら結果まで出力してくれるレベルまで行こうと思っています。

そして今後はwebアプリ化をしてリリースを目指します。

まとめ

期日ギリギリになってしまいましたが、このアドベントカレンダーがなかったら僕のような人間だと絶対的に今回のこのプロジェクトの技術的アウトプットをしなかったと思っています。
Qiitaさんと、N高等学校さんに感謝しています。

僕自身もっとポエムろうとか、細かく書きたかったのかも知れませんが、明日もお楽しみに。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away