在宅リーマン勉強日誌

忘れがちな毎日のメモ。

【3日目】KaggleでPythonの勉強してみた【独学】

KaggleのCourseタブからPythonの勉強ができるのでそのノートを取ります

 

Lesson:Booleans<Exercise>

勉強時間:120分以上

 

Lesson:Booleans<Exercise>

 Q1:入力値が正であれば1、負であれば-1、0であれば0を変えすsign関数を作成せよ。

 

Q2:入力値が1の場合はprintの内容を単数形、複数の場合はprintの内容を複数形で返す関数を作成せよ。

 

Q3:定義されている関数のバグを探せ。

 当たりはつけてたけど、特定に時間をかけてしまった。

Q4:負の数だけTrueを返す関数を作成せよ

 

Q5:ホットドッグの3つのトッピングが下記の場合にTrueを返す関数を作成せよ。

①オニオン抜き

②すべてのトッピングなし

③ケチャップ・マスタードどちらかを選んだ場合

問題を勘違いして、めちゃくちゃ難しく考えてしまった…。

無駄な時間…。

ベン図を使うとすぐわかる。

Q6:④一つのトッピングのみをオーダーした場合。

bool()に対してint()を呼ぶとどうなるだろうか?またそれを利用して簡潔な関数を書くこと。

bool(int())はTutorialで行っている通り、0以外はFalseで返す。

int(bool())にするとどうなるか?

これは、関数外で、やってみるとすぐわかるけど、True=1, False=0になる。

ベン図じゃなくて、一覧表を書くと容易に四則演算で何とかなることわかる。

 

www.cs.shinshu-u.ac.jp

 

Q7:(選択問題)ブラックジャックでプレイヤーになってコントロールする関数を作る。

  • プレイヤーは2枚のカードをもち、ディーラーは1枚のカードを持つ。
  • プレイヤーは何回でも”ヒット”によってカードを受け取ることができるが、カードの合計が21を超えるとラウンドは終了し、負ける
  • ディーラーは以下を満たすまでカードを配り続ける。
  1. ディーラーのカード合計が21を越したとき。(プレイヤーの勝ち)
  2. ディーラーのカード合計が17を超え、かつ、プレイヤーのカード合計がディーラーのカードより大きい場合。(プレイヤーの勝ち)
  3. それ以外の場合はディーラーの勝利

合計の計算

ジャック・クイーン・キングは10

エースは合計が21を超えないように、1または11として数える。

 

ゲームで勝率を上げられるか。これは正解も何もないんだけど、条件式の練習です。

ちなみに結果(デフォルト)は勝率38.3%(5万回試行、以下すべて)で、ブラックジャックはディーラーの勝率の方が高いといわれているそうなので、50%を超えれれば万々歳です。

 

一応ルール的に17以上はヒットしない方がよいようにみえたので、17あればヒットしない関数を作りました。
if player_total<=17:
return True
else:
return False

結果(条件1つ追加)は勝率39.4%

あんまり変わらないですね。

条件式の練習なので、戦略は下記のベーシックストラテジーを参照にしてみます。

chisou-sympo.jp

 

ここではスタンドとヒットしかできないので、Rはヒット、Dはヒット、Dはスタンドとします。

スプリットは今回のルールではできない…。ので、スプリットは一回無視します。

=ハードハンドとソフトハンドのみ

ちょっと面倒くさくなってるところは、ちょっと省く感じで笑

返り値 プレイヤー手札 ディーラー手札 Aあり/なし
ヒット(True) 8~11 問わない なし
  13~16 7~A なし
  12 2~3 なし
  12 7~A なし
スタンド(False) 13~16 2~6 なし
  17 問わない なし
  12 4~6 なし
ヒット(True) 2~6 問わない あり
スタンド(False) 7~8 問わない あり

 

関数のきれいさは置いておいて、愚直にコーディングしていきます。

if player_high_aces == 0:
if 8<=player_total<=11:
return True
elif (13<=player_total<=16) and (7<=dealer_total<=10):
return True
elif player_total == 12 and *1:
return True
elif (13<=player_total<=16) and (2<=dealer_total<=6):
return False
elif player_total == 12 and (4<=dealer_total<=6):
return False
elif player_total == 17:
return False
elif player_high_aces ==1:
if 13<=player_total<=17:
return True
if 18<=player_total<=19:
return False

 

そして結果は…

結果(ベーシックストラテジー)は 勝率42.3%

 

確かに、勝率上がったものの、+3%かーーーー!

こういうたぐいの勝率を上げるのは、大変なんですよね。

ちなみに一般的な勝率は47~48%らしいので、全然届いていません。

 

勝率を出すのは5万回試行ですが、1回のみ試すという関数もあって実行してみました。

------------------------------------------------

Player starts with 2 and A (total = 13)
Dealer starts with K

__Player's turn__
Player hits and receives 3. (total = 16)
Player hits and receives 8. (total = 14)
Player hits and receives 10. (total = 24)
Player busts! Dealer wins.

------------------------------------------------

Player turnの2列目(赤字)ところ、なんでこうなるんだろう。

ここで14になる理由がわかってないので、多分相変わらずここの英語が読めてないのかなー笑

------------------------------------------------

Player starts with 3 and 3 (total = 6)
Dealer starts with 8

__Player's turn__
Player stays

__Dealer's turn__
Dealer hits and receives 3. (total = 11)
Dealer hits and receives 5. (total = 16)
Dealer hits and receives 6. (total = 22)
Dealer busts! Player wins.

------------------------------------------------

ステイをとるとこういう挙動

DealerのTurnになるとPlayerは動かないのか。

したら、確かにデフォルトの「Stayしかとらない」という戦略はDealerの自爆を誘発するだけだから、ある程度ありうる戦略なのかも

 

 

もう少し勝率をあげに行きたいところだけど、この関数は仕組みがブラックボックスになっているし、試行の中身がわからない=何が敗因だったかわからないので、以上でやめることにしました。

 

この設問に関しては解がないので、残念ながら参照することもできず。

奥が深いよなー

 

ブラックジャックの他の人の回答はこんな感じ。

42%を引っ提げていくとあまり悪くはない気がする。

www.kaggle.com

 

一つだけ面白そうなのを見つけたので、真似してみました。

結果は見事!

Player won 50000 out of 50000 games (win rate = 100.0%)

関数の裏を突いたのかなあ。追加行はたった3行だけでした。すごい笑

 

<新出単語>

get credit:面目を施す

verbose:くどい、冗長な

 

 

*1:2<=dealer_total<=3)or (7<=dealer_total<=10