サイコロの目が6分の1の確率って本当!?
皆さん
こんにちは、こんばんは
TomoProgです。
なんか昨日一日で約50PVぐらいされたようで、今月も100PVを達成出来ました!!
多くの人に見ていただけるのは非常にありがたいことです。
これからもマイペースに記事を書いていけたらと思います。
今回はサイコロの確率をPythonで計算してみました。
それでは頑張っていきましょう。
6回振れば1回は出るって本当?
ふと思ったんです。
サイコロを振って指定した目が出る確率は6分の1です。
でも、実際に6回振っても出ないときもある・・・
じゃあだいたい何回振れば6分の1になるんだろう?
今回はこんな疑問をPythonで解いていこうと思います。
サイコロプログラムを書く
まずはサイコロをプログラムで書いてみます。
#-*- coding:utf-8 -*- import sys import random def dice_roll(): """ Content: サイコロを振る """ return random.randint(0, 5) def main(): """ Content: エントリーポイント """ #-------------------------------- # サイコロを振る回数を取得 #-------------------------------- roll_num = int(sys.argv[1]) #-------------------------------- # サイコロを振る #-------------------------------- dice_list = [0]*6 for i in range(roll_num): dice_list[dice_roll()] += 1 #-------------------------------- # 結果表示 #-------------------------------- print(dice_list) if __name__ == "__main__": main()
実行引数にサイコロを振る回数を指定します。
指定した回数分だけdice_roll関数を呼び出し、出た目の回数をカウントしていきます。
実際に100回サイコロを振ってみた結果は以下のようになりました。
実行: $ python3 dice.py 100 実行結果: [21, 11, 13, 11, 21, 23]
6分の1で出るのであれば
100 ÷ 6 = 16.66666....
それぞれの出た回数が16付近であればいいのですが、そうでもなさそうですね。
実行結果をグラフ化する
上記のプログラムでサイコロを振るプログラムは完成しました。
もっと沢山サイコロを降る前に、もう少し実行結果を分かりやすくするためにグラフで表示してみようと思います。
Pythonにはもちろんグラフを表示するための便利なモジュールも用意されています。
今回はmatplotlibというモジュールを使用します。
ただ、このmatplotlibは他のモジュールとの依存関係が強いのかインストールするのがかなり大変でした。
Ubuntu14.04で使用する場合は以下のコマンドを順に入力していけばインストール出来ました。
$ sudo apt-get install python3-pip $ sudo apt-get install libfreetype6-dev $ sudo apt-get install libxft-dev $ sudo apt-get install libffi-dev $ sudo pip3 install cairocffi $ sudo pip3 install matplotlib
さて、matplotlibを使用する環境が整ったので、先ほどのサイコロプログラムを改良し、円グラフを表示してみます。
#-*- coding:utf-8 -*- import sys import random import matplotlib.pyplot as plt def dice_roll(): """ Content: サイコロを振る """ return random.randint(0, 5) def main(): """ Content: エントリーポイント """ #-------------------------------- # サイコロを振る回数を取得 #-------------------------------- roll_num = int(sys.argv[1]) #-------------------------------- # サイコロを振る #-------------------------------- dice_list = [0]*6 for i in range(roll_num): dice_list[dice_roll()] += 1 ##-------------------------------- ## グラフ表示 ##-------------------------------- fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(111) labels = [str(x) for x in range(1, 7)] ax.pie(dice_list, labels=labels, autopct="%1.1f%%", startangle=90, shadow=True) plt.show() if __name__ == "__main__": main()
matplotlibを使う場合はimport文にmatplotlibを書いておきます。
import文でasを使用するとimportしたモジュールに別名を付けられるので便利です。
ax.pieでdice_listの中身の内容で円グラフを書くように指定しています。
実際に実行して表示してみます。
実行: python3 dice.py 100
リストの結果を表示するよりもグラフで表示できたほうが格段に見やすくなりました。
沢山振ってみる
グラフの表示も可能になったので、今度は沢山のパターンでサイコロを振ってみます。
30回ずつサイコロを振る回数を増やしていくとこんな感じです。
(スタートが左上でZ字の順です。)
1枚目の上段のグラフ(30回〜120回)はバラバラなイメージが有りますが、下段(150回〜240回)は結構綺麗な円になりました。
2枚目(270回〜480回)に入るとかなり6等分に近づき、あまり変化が見られなくなりました。
まとめ
- 大体150回くらいから6分の1の確率に近づいてくる。
- 大体300回くらいサイコロを振れば6分の1の確率にかなり近くなる。
今回はPythonでサイコロを振ってグラフを描いてみました。
やるたびにまた結果は違うと思うと確率って奥深いですね。
それではまた。
TomoProg
Pythonで百人一首ボットを作ってみる!! 最終回
皆さん
こんにちは、こんばんは
TomoProgです。
前回のボット作ってみるからまた日が空いてしまいましたが、
Pythonで百人一首ボットを作ってみるシリーズもこれで最後です。
パート2までで百人一首の画像と歌を投稿する機能を実装しました。
今回は投稿した百人一首の現代語訳を投稿する機能を実装してみます。
パート1、パート2を見ていない方はそちらからどうぞ!!
tomoprog.hatenablog.com
tomoprog.hatenablog.com
それでは最終回頑張っていきます!!
現代語訳データを収集する
現代語訳は以下のサイトの現代語訳を拝借しました。
www.hyakunin.stardust31.com
収集する方法はパート2でもやりましたが、
この方法でいきます!!
表計算ソフトに貼り付けるとこんな感じです。
左から
の順です。
これで、投稿する現代語訳の収集は完了しました!!
現代語訳を投稿するコードを実装する
さて、現代語訳の収集が終わったので、現代語訳を投稿するコードを追記します。
def karuta_tweet(karuta_info): """ Content: つぶやく """ global app global app_up #------------------------------ # かるた画像つぶやき #------------------------------ # 画像ファイル読み込み try: file_path = os.path.join("./karuta_img/", karuta_info["img"]) with open(file_path, "rb") as image_f: image_data = image_f.read() except Exception as e: logger.write("画像ファイル[{filename}]の読み込みに失敗しました".format(filename=filepath)) logger.write(str(e)) return False # つぶやきメッセージ作成 tweet_msg = ( karuta_info["first_part"] + "\n" + karuta_info["last_part"] + "\n" + karuta_info["name"]) # つぶやく try: id_img = app_up.media.upload(media=image_data)["media_id_string"] app.statuses.update(status=tweet_msg, media_ids=id_img) except Exception as e: logger.write("画像のTweetに失敗しました。") logger.write(str(e)) return False time.sleep(30) #------------------------------ # 現代語訳つぶやき #------------------------------ tweet_msg = karuta_info["translate"] try: app.statuses.update(status=tweet_msg) except Exception as e: logger.write("現代語訳のTweetに失敗しました。") logger.write(str(e)) return False return True
百人一首ボットプログラムのTwitterに投稿する関数を抜き取りました。
歌、歌人、かるた画像の投稿をしたあとに、time.sleep(30)で30秒スリープ後、日本語訳を投稿するようになっています。
少し雑ですが、例外処理を入れ、何かしらの例外があった際には自作のロガープログラムでログをファイルに出力するようにしています。
ボットを起動しておくサーバを借りる
今までは自分が使っているPCの仮想環境から投稿していました。
しかし、一日中投稿しようとすると、PCをずっと起動していないといけないのです。
スリープも出来ないのはきついと思ったので、さくらインターネットでVPSを借りました。
vps.sakura.ad.jp
ちなみに月額972円のHDD100Gのプランです。
今回はそこから起動してみます。
VPSサーバの設定
さくらのVPSサーバは標準だとOSがCentOS6ですが、CentOSをほぼ触ったことがないので、Ubuntu Server 14.04を使用することにしました。
とりあえず、Pythonを使用できる環境を整えます。
Ubuntu14.04では標準でPython3.4.3がインストールされているので、Python自体のインストールは不要です。
Pythonのパッケージ管理システムであるpipを使えるように以下のコマンドを入力します。
$ sudo apt-get install pip3
pip3ではなくpipでインストールすると、Python2系のpipがインストールされるので、注意が必要です。
pipがインストール出来たら、Pythonの仮想環境を構築するためにvirtualenvをインストールします。
$ sudo pip3 install virtualenv
virtualenvはPythonの仮想環境を作成する便利なモジュールです。
virtualenvを使えば作成した仮想環境ごとにPythonのバージョンやインストールするモジュールを分けることができます。
さて、あとは仮想環境にtwitterモジュールをインストールします。
# 仮想環境にて $ pip install twitter
これでサーバの環境構築は終了です。
サーバから起動する
さて、環境が整ったので、サーバから起動してみます。
仮想環境にて以下のコマンドを入力します。
# 仮想環境にて $ python karuta_bot.py &
この"&"記号をつけることで、バックグラウンドでプログラムを起動出来ます。
起動して約一日ほど放置してみた結果がこんな感じです。
twitter.com
画像につづいて現代語訳を投稿することが出来ました!!
今日の成果
- 現代語訳を投稿することが出来た!!
- サーバから起動することで、一日中起動しておくことに成功した!!
- 百人一首ボットが完成!!
やっと百人一首ボットが完成しました!!
Twitterボットは簡単に作成するサービスが既にありますが、自分で1から作ってみるというのが新鮮で面白かったです。
この記事を見て作りたくなったと思った人は是非自分で作ってみてください!!
ここまで読んでいただきありがとうございました。
それではまた。
TomoProg
vsftpdの設定で謎のエラーにハマった
皆さん
こんにちは、こんばんは
TomoProgです。
今日はTwitterボット用にサーバを設定していたら、vsftpdの設定でハマったのでここに書いておきます。
ちなみにサーバは「Ubuntu14.04 amd-64 LTS」です。
それでは頑張っていきましょう。
vsftpdをインストールする
まずはvsftpdをインストールします。
インストールするには以下のコマンドをターミナルで入力します。
$ sudo apt-get install vsftpd
インストールはこれだけです。
vsftpd.confを設定する
vsftpdのインストールが完了したら、vsftpdの設定ファイルであるvsftpd.confを設定します。
ちなみにvsftpd.confの場所は/etc/vsftpd.confです。
# 書き込み許可(コメント解除) write_enable=YES # アスキーモードの転送許可(コメント解除) ascii_upload_enable=YES ascii_download_enable=YES # ログイン時のバナーメッセージ(コメント解除) # (ログイン時にバージョン情報の表示を行わないように設定) ftpd_banner=Welcome to blah FTP service # chroot許可(コメント解除) chroot_local_user=YES chroot_list_enable=YES chroot_list_file=/etc/vsftpd.chroot_list # ディレクトリごと一括での転送有効(コメント解除) ls_recurse_enable=YES # FTP接続時のルートディレクトリを設定(追記) local_root=/home/tomoprog/ftp_root # これはよく分からんがとりあえず追記 seccomp_sandbox=NO
ちなみに設定は下記のサイトを参考にさせていただきました。
http://www.server-world.info/query?os=Ubuntu_14.04&p=ftpwww.server-world.info
さて、chroot_list_fileを有効にしたので、指定したリストファイルを作成しておきます。
今回はすべてのユーザのFTPでのルートディレクトリをlocal_rootに指定したディレクトリにしたかったので、空のリストファイルを作成します。
$ sudo touch /etc/vsftpd.chroot_list
すべての設定が終わったので、vsftpdを再起動します。
$ sudo service vsftpd restart
500 OOPSでハマる
さて、設定が終わったので、早速別の端末からFTP接続してみます。
# xxx.xxx.xxx.xxxはFTPサーバのIPアドレスを指定
$ftp xxx.xxx.xxx.xxx
上記のコマンドを入力すると、ユーザとパスワードを求められるので入力します。
すると以下のエラーメッセージが返ってきました。
500 OOPS: vsftpd: refusing to run with writable root inside chroot()
英語とか分からんよ・・・。
というわけでGoogle先生に聞いてみると以下のサイトを教えてくれました。
ftp接続でrefusing to run with writable root inside chrootが出た時の対処法 – ムッシューのIT備忘録
なるほど。
chrootした先に書き込み権限があるとエラーとなるようです。
かと言って書き込み権限を消してしまうとアップロードできないので、vsftpd.confに以下の一行を追記します。
allow_writeable_chroot=YES
これでもう一度FTP接続してみると・・・
230 Login successful. Remote system type is UNIX. Using binary mode to transfer files.
接続に成功しました!!
まとめ
今日はvsftpdを設定してみました。
エラーが出てから、たった1行の追加に2時間かかったのは内緒です。
それではまた。
TomoProg
Pythonで閏年を判定してみた
皆さん
こんにちは、こんばんは
TomoProgです。
昨日、2月29日だった・・・
今年は閏年だ!!
というわけで、記念すべき20記事目はPythonを使って閏年を判定してみます。
それでは頑張っていきましょう。
閏年の判定方法
閏年というと4年に一度あるんだから4で割り切れる年が閏年だ!!
と考えてしまう人も多いと思うのですが、実は意外と複雑なんです。
- 西暦が4で割り切れる年はうるう年
- ただし、4で割り切れても100で割り切れる年はうるう年でない
- ただし、100で割り切れても400で割り切れる年はうるう年
閏年判定プログラムを書いてみる
さっそく閏年判定プログラムを書いてみました。
#-*- coding:utf-8 -*- def check_leap_year(year): """ 閏年判定 """ if year % 400 == 0: return True elif year % 4 == 0 and year % 100 == 0: return False elif year % 4 == 0: return True else: return False def main(): """ エントリーポイント """ years = [2016, 2000, 1990, 1980] for year in years: if check_leap_year(year): print(str(year) + "年は閏年です。") else: print(str(year) + "年は平年です。") if __name__ == "__main__": main()
実行結果: 2016年は閏年です。 2000年は閏年です。 1990年は平年です。 1980年は閏年です。
check_leap_year関数で閏年かどうかを判定し、閏年か平年かを出力するプログラムです。
実行結果を見る限り、閏年を正確に判定できているみたいです。
calendarモジュールで閏年を判定する
上記のように自分で閏年判定を実装してもよいですが、Pythonにはもっと簡単に閏年を判定する方法があります。
その方法がcalendarという標準モジュールを使う方法です。
実はcalendarモジュールには年を渡すと閏年かどうかを判定してくれるisleapという関数がすでに実装されています。
isleap関数を使った場合のプログラムを書いてみました。
#-*- coding:utf-8 -*- import calendar def check_leap_year(year): """ 閏年判定 """ if calendar.isleap(year): print(str(year) + "年は閏年です。") else: print(str(year) + "年は平年です。") def main(): """ エントリーポイント """ check_leap_year(2016) check_leap_year(2000) check_leap_year(1990) check_leap_year(1980) if __name__ == "__main__": main()
実行結果: 2016年は閏年です。 2000年は閏年です。 1990年は平年です。 1980年は閏年です。
上記のプログラムと同じ結果が得られました!!
calendarモジュールを使った方が、短く簡単に書くことが出来ます。
Effective Pythonを買ってみた
皆さん
こんにちは、こんばんは
TomoProgです。
今日は題名の通り、「Effective Python」というPythonプログラムを書く上でのノウハウ本が売っていたので、買ってみました。
まだ、20ページほどしか読んでいないですが、ジェネレータやリスト内包表記など自分が普段使っていないテクニックの使い方や、Pythonで書くのであればこのように書いたほうが良いというプログラムの書き方など、我流でPythonを勉強した私にとっては得るものが多い書籍だなと感じています。
この本で学習したことはこのブログで掲載していけたらと思います。
それではまた。
TomoProg
Vimのインデントをファイル形式ごとに設定してみた
皆さん
こんにちは、こんばんは
TomoProgです。
皆さんVim使っていますか?
あんな気違いなエディタ使わねぇよ・・・
という人も多いと思いますが、私はよくVimを使います。
何故かって?
それは、
「俺、Vim使えるよ。」
ってドヤ顔できるからです!!
という半分冗談は置いておき、
今日はVimでのプログラミングを快適にするべく、ファイル形式ごとにインデントを設定してみました。
それでは頑張っていきましょう。
Vimって何?
設定に入る前に、Vimを少し紹介しておきましょう。
Vimはテキストエディタの一つです。
Windowsで言うとメモ帳と一緒の部類ですね。
ただ、メモ帳と大きく異る点があります。
それはVimがCUIベースのテキストエディタだということです。
CUIベースというとあれです。
映画とかでハッカーが黒い画面にカタカタと謎のコマンドを打ち込んでいるときがあると思います。
あの黒い画面上で起動するエディタがVimです!!
基本的にマウスが使えません!!
×ボタンで閉じるとかありません!!
名前をつけて保存ボタンとかありません!!
全部コマンドで処理します。
メモ帳みたいにスタートメニューから起動するなんてそんなことしません。
ターミナルを立ち上げて、コマンドを入力します。
$ vim ファイル名
そんなエンジニア向けのエディタ
それが、Vimです。
.vimrcにてプラグイン機能をONにする
さっそくVimを設定していきます。
ホームディレクトリ配下に.vimrcファイルを作成し、以下の一文を記述します。
filetype plugin indent on
これで、ファイル形式別にインデントを設定する機能が有効になりました。
filetypeを記述する
.vimディレクトリ内にfiletype.vimというファイルを作成し、インデントを設定するファイル形式を記述します。
pythonの場合はこんな感じです。
augroup filetypedetect au BufRead,BufNewFile *.py setfiletype python augroup END
filetypeに対応する設定を記述する
.vimディレクトリ内にftpluginディレクトリを作成し、filetypeで指定したsetfiletypeの名前でファイルを作成します。
今回はsetfiletypeにpythonを指定したのでpython.vimという名前でファイルを作成します。
set expandtab set tabstop=4 set softtabstop=4 set shiftwidth=4
これで、.pyのファイルではタブが4つのスペースで入力されるようになりました!!
まとめ
- ファイル形式ごとにVimのインデントを変更出来る!!
今日はVimのインデントをファイル形式ごとに設定してみました。
Pythonでプログラム書くときに毎回タブからスペースに変換していたので、この設定にしてからすごく快適です!!
それではまた。
TomoProg
Pythonで百人一首ボットを作ってみる!! パート2
皆さん
こんにちは、こんばんは
TomoProgです。
前の投稿から少し期間が空いてしまいましたが気にせず、書いていこうと思います。
今回は百人一首ボット作りのパート2です!!
パート1を見ていない方はパート1からどうぞ!!
tomoprog.hatenablog.com
パート1では絵札をTwitterに投稿するところまで出来ました。
今回は絵札と一緒に歌も投稿してみたいと思います。
それでは頑張っていきましょう。
歌と歌人を集める
まずは歌の上の句、下の句を集めるところからスタートです。
今回は以下のサイトを利用し、集めてみます。
百人一首の一覧
集め方はこんな感じです。
プログラムは一行も書きません!!
実際にやってみると、こんな感じです。
次は歌人を集めます。
と言ってもさっきとサイトが違うだけで、やり方はほぼ一緒です。
利用したサイトは以下のサイトです。
小倉百人一首の歌人名前・読み方
これで歌と歌人は準備出来ました。
jsonフォーマットに整形してみる
先ほど作ったCSVファイルのまま使用してもいいのですが、今回は勉強も兼ねてjsonフォーマットに整形してみました。
Pythonにはjsonというjsonファイルを扱う標準モジュールがあります。
19.2. json — JSON エンコーダおよびデコーダ — Python 3.6.5 ドキュメント
jsonモジュールを使って以下のCSV形式のテキストファイルを読み込んで、jsonフォーマットに整形してみます。
CSVファイル: 天智天皇,てんじてんのう,秋の田のかりほの庵の苫をあらみ,わが衣手は露にぬれつつ 持統天皇,じとうてんのう,春過ぎて夏来にけらし白妙の,衣干すてふ天の香具山 柿本人麻呂,かきのもとのひとまろ,あしびきの山鳥の尾のしだり尾の,ながながし夜をひとりかも寝む (以下省略・・・)
#-*- coding:utf-8 -*- import json json_info = [] cnt = 1 with open("karuta_info.csv") as f: f_str = [] for line in f: f_str.append(line) for line in f_str: d = {} line = line.rstrip("\n") info = line.split(",") info.append(str(cnt).zfill(3) + ".jpg") d["name"] = info[0] # 歌人名 d["hurigana"] = info[1] # ふりがな d["first_part"] = info[2] # 上の句 d["last_part"] = info[3] # 下の句 d["img"] = info[4] # 画像名 json_info.append(d) cnt += 1 with open("karuta_info.json", "w") as f_json: for info in json_info: json.dump(info, f_json, sort_keys=True, indent=4, ensure_ascii=False) f_json.write("\n")
実行結果: { "first_part": "秋の田のかりほの庵の苫をあらみ", "hurigana": "てんじてんのう", "img": "001.jpg", "last_part": "わが衣手は露にぬれつつ", "name": "天智天皇" } { "first_part": "春過ぎて夏来にけらし白妙の", "hurigana": "じとうてんのう", "img": "002.jpg", "last_part": "衣干すてふ天の香具山", "name": "持統天皇" } { "first_part": "あしびきの山鳥の尾のしだり尾の", "hurigana": "かきのもとのひとまろ", "img": "003.jpg", "last_part": "ながながし夜をひとりかも寝む", "name": "柿本人麻呂" } (以下省略・・・)
つぶやいてみる
百人一首の情報を一つのjsonファイルにまとめたので、あとは読み込んでTwitterに投稿するだけです!!
早速やってみましょう。
#-*- coding:utf-8 -*- from twitter import * import json import datetime import time import random import copy import os # global変数 app = None app_up = None app_auth = None conf_file_name = "conf.json" karuta_info_file_name = "karuta_info.json" def main(): """ Content: エントリーポイント """ global app global app_up global app_auth global conf_file_name global karuta_info_file_name # 設定ファイル読み込み with open(conf_file_name) as f: conf_data = json.loads(f.read()) # Twitterアプリ認証 app_auth = OAuth(conf_data["access_token"], conf_data["access_token_secret"], conf_data["consumer_key"], conf_data["consumer_secret"]) app = Twitter(auth=app_auth) app_up = Twitter(domain="upload.twitter.com", auth=app_auth) # 百人一首ファイル読み込み karuta_info = [] with open(karuta_info_file_name) as f: for line in f: karuta_info.append(json.loads(line)) # 初回起動メッセージをつぶやく tweet_time = datetime.datetime.now() tweet_msg = """ karuta_bot.pyが起動したよ!! これから5分毎に百人一首をつぶやくよ!! """ app.statuses.update(status=tweet_msg) # 5分毎につぶやく tweet_karuta_list = copy.deepcopy(karuta_info) while True: now_time = datetime.datetime.now() if int((now_time - tweet_time).seconds / 300) >= 1: idx = random.randint(0, len(tweet_karuta_list) - 1) karuta_tweet(tweet_karuta_list.pop(idx)) if not tweet_karuta_list: tweet_karuta_list = copy.deepcopy(karuta_info) tweet_time = now_time time.sleep(10) def karuta_tweet(karuta_info): """ Content: つぶやく """ global app global app_up # 画像アップロード file_path = os.path.join("./karuta_img/", karuta_info["img"]) with open(file_path, "rb") as image_f: image_data = image_f.read() id_img = app_up.media.upload(media=image_data)["media_id_string"] tweet_msg = (karuta_info["first_part"] + "\n" + karuta_info["last_part"] + "\n" + karuta_info["name"]) # 画像とメッセージを投稿 app.statuses.update(status=tweet_msg, media_ids=id_img) if __name__ == "__main__": main()
jsonファイルから1首ランダムに選び出して、Twitterに投稿しています。
実際に起動してみた様子はこんな感じです。
毎日百人一首くん (@TomoProgBot) | Twitter
これでTwitterに自由に画像付きツイートを投稿出来そうです!!