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

技術屋の末端。プログラミングも電気回路も専門外です。 コードに間違いなど見つけられたら、気軽にコメントください。 VC#、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: