プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、Python3、ラズパイなど。

janome(蛇の目)でマルコフ連鎖【正規表現の初歩】

マルコフ連鎖を使って文の生成をします。
自分のtimelineのtweetを参考に、電子工作やプログラミングっぽいtweetを生成するのが目標です。

↓参考
こちらには、urlやmenshonを正規表現でdeleteする方法も記載されています。
qiita.com

マルコフ連鎖については↓を参考に。
qiita.com

まずは、自分のタイムラインを取得します。
ここで、URL、返信、ハッシュタグ正規表現で抽出し削除します。
これが、マルコフ連鎖のソースになります。

def login(acount):
    if acount=="s":  #アカウントの切り替え用
        CONSUMER_KEY = "####"
        CONSUMER_SECRET = "####"
        ACCESS_TOKEN = "####"
        ACCESS_SECRET = "####"
    else:
        exit()

    auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
    api = tweepy.API(auth)
    return api

def my_tweet(acount):
    file = open('markov_sorce.txt', 'w', encoding='utf')  # 書き込みモードでオープン
    count=0
    api =login(acount)
    for tweet in api.home_timeline(count=100): #タイムライン
        if count>100: #タイムラインを100tweet取得
            break
        text = tweet.text
        text = tweet.text.replace('\r', ' ')  # 改行コードを削除
        text = text.replace('\n', ' ')  # 改行コードを削除
        replypattern = '@[\w]+'
        urlpattern = 'https?://[\w/:%#\$&\?\(\)~\.=\+\-]+'
        hashpattern = r'[##]([\w一-龠ぁ-んァ-ヴーa-z]+)'
        text = re.sub(replypattern, '', text)
        text = re.sub(urlpattern, '', text)
        text = re.sub(hashpattern, '', text)
        text = text.replace('RT : ', '')
        #print(text)
        file.write(text)
        file.write("\n")
        count+=1
        time.sleep(0.2)

次にマルコフ連鎖の中身になります。
元記事を参考に、もうすこし簡単なLogicにしました。
tweetごとに単語に区切りlistに格納し、tweetの終わりには’EOS’という文字列を識別子として入れて、これを見つけたら文の終わりという意味がわかるようにしました。
また、参考元の記事では、単語の連続数を3にしてますが、より自然になるように4にしました。
自然になりすぎても面白くないので、ここら辺は感性です。
ランダムでlistにアクセスし、文(tweet)の先頭('EOS'の次の単語)をさがし、4つ続けて単語を取得。
4つめと同じ単語を次の単語列の先頭として探します。
取得した単語列の中に’EOS’がみつかればそれで終了です。

# -*- coding: utf-8 -*-
from janome.tokenizer import Tokenizer
import random
import re #正規表現

def markov():
    text="1" #適当に初期化
    sentence=[]
    file = open('markov_sorce.txt', 'r', encoding='utf')  # UTFを指定する

    while text != "":
        text = file.readline()
        for token in t.tokenize(text):
            sentence.append(str(token.surface))    # 単語、表示形
        sentence.append('EOS') # 1つのtweetごとに区切りを入れる

    tweet=''
    rand=random.randint(1,len(sentence)-4) #乱数を生成し、listから単語を選択
    while sentence[rand]!='EOS': #'EOS'を探し
        rand+=1
    rand+=1 #'EOS'の次の単語をスタートとする
        word3=sentence[rand+3] #選択した最後の単語を記憶
    tweet=sentence[rand]+sentence[rand+1]+sentence[rand+2]+sentence[rand+3]
    rand = random.randint(1,len(sentence)-4)
    while sentence[rand+3]!='EOS' and sentence[rand+2]!='EOS' and sentence[rand+1]!='EOS': #'EOS'が出現するまで
        rand = random.randint(1, len(sentence)-4)
        if rand > len(sentence)-4: #listのサイズを超えたら0(listの先頭)に戻る
            rand = 0
        while sentence[rand]!=word3: #最後の単語と同じ単語を探す
            rand+=1
            if rand>len(sentence)-4:
                rand=0
        tweet=tweet+sentence[rand + 1] + sentence[rand + 2]+ sentence[rand + 3]
        word3 = sentence[rand + 3]
   if len(tweet) > 180: #長すぎるときは中断してRetry
            print('Error! Too long sentence.')
            markov()
    fd=tweet.find('EOS')
    tweet = tweet[:fd] #'EOS'より前をスライスで取得
    if len(tweet)<23: #tweetが短いときはRetry
        print('Error! Too short sentence.')
        markov()
    print(tweet)

if __name__ == '__main__':
    razpiTweet.my_tweet('s')
    markov()

このようにして、5回生成したのが↓。
twitterの仕様が変わって280文字までTweetできるはずだが、180文字で切ってもOverすることがある。
twitterの文字カウントの仕様がよくわからないと最適化できないなぁ。

【ITIL】   マック・ケンタ・回転寿司のスマホ代「3千円」を節約する方法まとめ』 格安SIMでドコモアドレスを維持しながら手軽に毎月の話、世の中の親御さんを必殺技に使ってるんだろう Elm 先日発表に使うかよくわからんの転職成功者忘年会!

ArduinoをVisual Studio Code ローカライズ え、もしかしてサンタさんに現れたゴミUIImageView

【定期ツイート】 HTMLのは私です。再配布や改変の偉くね

静電容量方式タッチパネルとは、世界を理解しているものである。  &gt;もしもいまのようなくらいブレブレ。そうだ、今回はそれを上回る53量子ビットの品 ゲーミングノートPC 外でもゲームをやりたい方や、それを公に発言します。 [電子ボルト]

()は、当フロアでのニュースをついて「サンタより」を節約する考えは、同時にバイファムが、今回は電流の単位アンペアから組み立てられた組立単位であり、代理行為」は立派な「代理といえそうなおっさんがなかった時代に作られ、タッチして欲しいという定義は必ずしも成り立たない。1989年に使うかよくある話。 お味はお土産として及第点だけどラスクとしてはもう少し。


次にラズパイにマルコフ環境をセットアップします。
ラズパイにjanomeをインストールしようとしたら、ラズパイゼロではできなかった。

$pip install janome

*だれかたすけて下さい。 (pip3も試しました)

Command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-4ppLvZ/janome/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-eQlIyU-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /tmp/pip-build-4ppLvZ/janome
Storing debug log for failure in /home/pi/.pip/pip.log

→Raspbianをstretchにupdateしたらpip3でインストールできるようになりました。 2018/06/25

あきらめてラズパイ3でインストールしたら、インストールは成功したのにパスが通らないという状況に陥った。
そんなライブラリ無いよ的な感じで、プログラムを走らせようとしても、Errorで止まってしまいます。

pip showというコマンドでインストールが確認できる。

$ pip show janome
Name: Janome
Version: 0.3.5
Summary: Japanese morphological analysis engine.
Home-page: http://mocobeta.github.io/janome/
Author: Tomoko Uchida
Author-email: tomoko.uchida.1111@gmail.com
License: AL2
Location: /home/pi/.local/lib/python2.7/site-packages
Requires:

python2のフォルダ名だが???
と思って、もしや!!

$pip3 install janome

でインストールしなおしたら動いた。
明示的にpip3にしなきゃダメなんですね~。

$ pip3 show janome
Name: Janome
Version: 0.3.5
Summary: Japanese morphological analysis engine.
Home-page: http://mocobeta.github.io/janome/
Author: Tomoko Uchida
Author-email: tomoko.uchida.1111@gmail.com
License: AL2
Location: /home/pi/.local/lib/python3.5/site-packages
Requires: