u++の備忘録

2週間のシアトル出張に行きます

明日14日から27日までの2週間、会社の都合でシアトルに出張します。弊社のR&D部署が主導する出張で、米国の最新技術動向の視察として、2週間にわたって技術系のイベント参加や現地企業訪問などを実施予定です。

私は昨年の10月に入社したので、期せずして帰国時には(ほぼ)1年在籍したことになります。

upura.hatenablog.com

もちろん若干の不安もある中での入社でしたが、1年経過した段階で「こういう案件で出張に行かせてもらえるくらいには自己発信できた」ことを素直に嬉しく思います。まだまだ力不足な点ばかりですが、今後も社内外で成果を出し続けられるよう精進します。

まずはこの2週間、英語力や技術力で苦戦する点もあるかと思いますが、多くを糧にして社に還元できるよう頑張っていきたいです。

Udemy講座「手を動かしながら2週間で学ぶAWS基本から応用まで」を修了したので感想など

Udemyの講座「手を動かしながら2週間で学ぶAWS基本から応用まで」を修了した*1ので、受講の動機や感想などをまとめます。

講座の概要

本講座は、オンライン学習プラットフォームの「Udemy」で先日*2にリリースされた講座です。タイトルの通りAWSを基礎から応用まで体系的に学ぶ内容となっています。

詳細は講師による下記ブログをご参照ください。

www.ketancho.net

受講の動機

筆者の会社での主の業務はデータアナリストですが、合わせてAmazon API Gateway + AWS Lambdaで構築したサーバーレスアーキテクチャのエンジニアとしての業務も担当しています。

正直なところ、後者の仕事に関わるまではAWSをほとんど触ったことがない状況でした。会社での研修や開発チームの猛者の方々のサポートを受けながら業務に取り組んでいますが、業務に直結する知見だけではなく体系的にAWSを学ぶ必要があると感じていました。

そんな折に上記のブログを拝見し、1200円のクーポンも発行されていたので、体系的に学ぶ良い契機だと思い購入に至った次第です。

受講の感想

全講座を閲覧し終わっての感想は多岐にわたりますが、ここでは良かった点を3つと気になった点1つを挙げたいと思います。

良かった点

AWSへの「怖さ」が拭える

筆者の場合、最初にAWSのコンソールを触ったときの感想は「なんかゴチャゴチャしてて何をイジれば良いか分からない」「既存の設定を壊してしまわないだろうか」「この操作では課金が発生しないだろうか」というものでした。これらはAWSへの無知から生じるもので、AWSに対する名状しがたい「怖さ」があったように思います。

本講座は最初に自分自身のAWSアカウントを作成するところから始め、課金アラートの設定も実施します。ほぼ全ての画面操作を動画で確認できるので初心者でも追従でき、個人のアカウントなので好き勝手に触ることができ、課金アラートがあるので安心して講座にない設定も試すことができます。

タイトル通り、実際に「手を動かしながら」学ぶことで、AWSへの「怖さ」をある程度払拭できたと思いました。

各サービスの立ち位置が分かる

AWSを学ぶ上での障壁の一つに、サービスの豊富さがあると思います。「たくさんサービスがあるけれど、何から勉強すれば良いのだろうか」「何がどういう役目を果たしているのだろうか」と感じていました。業務で触れたサービスに関しては当然理解が深まっていくのですが、AWS全体の中で個々のサービスがどういう位置付けなのかは漠然としか把握できない状況でした。

本講座では簡単なブログサービスを作っていく流れの中で、全体の中で優先的に学ぶべきサービスは何なのか確認できます。本講座で登場するのは講師が考えた「使われるシーンが多いであろうサービス」で、2018年現在においてAWS全体を理解する上で重要な順番になっているということです。

さらに本講座の中で新しく登場するAWSの各サービスについて、これまで登場したサービスとの関係性や位置付けが丁寧に説明されている印象を受けました。例えば、最初はAmazon EC2ベースで作成し、後にマネージドサービスに置き換えていくなど、各サービスの繋がりがつかみやすい構成になっていると感じました。

Webサービスの仕組みの大枠がつかめる

本講座を受講しての「副産物」として、AWSに関する知見にとどまらず、Webサービスの仕組みの大枠もザックリと把握できたことが挙げられます。

自分で手を動かしながら簡単なブログサービスを作っていく中で、ブラウザにURLが入力されてからページが表示されるまでの流れを大まかに追うことができます。もちろん本講座で扱うのは非常に単純なブログサービスなので、説明が簡略化されている部分や省略した要素は数多くあると思いますが、DNSサーバやセキュリティグループの設定などWebサービス構築に必要な仕組みを学ぶことができました。

気になった点

ここまで、講師の回し者のような内容になっている気がしたので、気になった点についても少し言及しておきます。

Linux操作

「受講における必要条件」として「基本的な Linux の操作ができること(ls, cp, mv といったコマンド、vim 基本操作)」と記載されています。実際、本講座の中でLinuxの操作自体の解説はほとんどありませんでした。

一つの動画を多人数が閲覧するという仕様上、ある水準の知識を仮定するのは当然のことだと思います。とはいえ、もう少しLinux操作などが分からない人に向けて、せめて「検索ワード」の提供があると良いのではないかと思いました。

例えばセクション: 3「Day2: EC2を使ってサーバを立てる」において、EC2インスタンスSSH接続しミドルウェアを導入するパートがあります。ここで下記のようにパーミッション設定を変更する流れがあるのですが、パーミッションの権限の表現方法が分かっていない人や慣れていない人には、口頭での説明が不十分なように感じました。

~/project/udemy
❯ ll
total 8
-rw-r--r--@ 1 USERNAME  staff   1.7K  9  4 20:32 udemy.pem

~/project/udemy
❯ chmod 400 udemy.pem

~/project/udemy
❯ ll
total 8
-r--------@ 1 USERNAME  staff   1.7K  9  4 20:32 udemy.pem

もちろん本講座の大きな目的から考えると本筋ではないのですが、口頭で「この辺りの表現が分からない場合は、『○○○』で調べてみてください」などと補足があると、より親切なのではないかと思いました。

筆者の進め方

最後に、本講座を筆者がどのように進めたかを述べておきます。

筆者は今回、講師がブログで「おすすめの受講方法」として提案している①まずは講座を聞く②動画を流しながら手を動かすーーという2回聴講方式を実施しました。

①については、夜寝る前に横になりながらタブレットに入れたUdemyアプリで閲覧しました。音声や滑舌が明瞭なので、ほとんど2倍速で閲覧していましたが問題ありませんでした。十分に理解できていないと感じた部分は、動画コンテンツの強みを活かして何回か繰り返し確認しました。

②については、退社後の18〜21時など比較的集中してパソコンに向かえる時間帯に取り組んでいました。PC本体に動画を流し、液晶モニタではブラウザやターミナルを開いて操作していました。こちらも操作に手間取った場合には動画を巻き戻せるのがありがたかったです。

1日1セクション全14日想定のコンテンツでしたが、筆者の場合はある程度集中的に取り組みたかったこともあり、半分の7日間で修了することになりました。

おわりに

本記事では、ここ最近取り組んでいたUdemyの講座について紹介しました。端的に言って、1200円以上の価値ある知見を十分に得られたと感じています。

冒頭の「受講の動機」でも述べましたが、筆者は業務で主にAWS Lambdaをはじめとしたサーバーレスアーキテクチャを扱っています。講師のブログには「別途サーバーレスな講座も検討しています」とありましたので、ぜひ続編を期待したいと思います。

*1:特に修了試験などがあるわけではなく、単に講座を全て見終わって手を動かしたという話です

*2:筆者の確認しうる限りでは9月3日

Adversarial Validationのメモ

はじめに

下記の英語記事から要旨を抜粋して、日本語でまとめた。

fastml.com
fastml.com

Adversarial Validationとは

いつ使う?

  • TrainデータとTestデータの分布が異なる場合
  • → Trainデータから適切にValidationデータを作成するのが難しい
  • → Kaggleの場合、LocalCVとLBのスコアが一致しないなどの問題が生じる

解決策

1. 「TrainデータかTestデータかを判定する分類器」を作る
2. Trainデータを、Testデータに似ている順にソートする
3. 似ている順に、Trainデータからデータを抽出し、Validationデータとする

応用例 "stochastic adversarial blending"

KaggleのHome Credit Default Riskコンペの2nd place solutionに使われた手法。

2nd place solution ( team ikiri_DS ) | Kaggle

The process is as follows,

  1. Sample data with a sampling ratio by using adversarial validation as a sampling weight.
  2. Optimize the weights with train prediction.
  3. Iterate 1~2 process to get converged weights.

【論文メモ】29組のデータアナリストに同じデータセットと同じ質問を与えても、分析結果がバラバラだったという研究

どんなもの?

29グループ(計61人)のデータアナリストに、同じデータセットと同じ質問を与えたときの分析アプローチのバラツキを分析。質問は「サッカーの主審は、肌の白い選手に比べて肌の黒い選手にレッドカードを与える可能性が高いですか?」。

分析アプローチはチーム間で大きく異なり、オッズ比で0.89から2.93の範囲だった(中央値は1.31)。20チーム(69%)が統計的に有意な正の結果を示した一方で、9チーム(31%)は有意な関係を示さなかった。

2018-08-29 19 57 16

これらの知見は、たとえ真摯な専門家集団であっても、複雑なデータの分析結果に主観的な要素が入り込むのは避け難いことを示唆している。 分析を透明化する手段として、同じ研究課題を同時に調査するために多数の研究チームを採用する「クラウドソーシング」が有用であると提言している。

論文リンク

著者/所属機関

R. Silberzahn et.al

媒体

SAGE Journals

投稿日付

First Published August 23, 2018

所感

単純にバラツキの大きさに驚き。自分も同じデータセットで追実験して、オッズがどういう結果になるか確認したい。

データアナリストとして真摯に受け止めて熟読すべきは、論文の結論に含まれた考察部分。どうやっても完全に「客観的」はあり得ないので、その中でどうやって意思決定に値する分析をしていくかを考えさせられる論文だった。

github.com

阪神タイガース、今季初の八回から逆転勝利 昨日までの「0勝50敗」は他チームと比べ酷い数字か検証する

はじめに

本日朝、サンスポに次の記事が掲載されました。阪神タイガースは今季、「七回終了時にリードを許している試合で0勝50敗」という少し衝撃的なデータです。

www.sanspo.com

この記事に刺激されたか否かは分かりませんが、阪神は本日の試合で八回表に一挙6得点。今季初の八回からの逆転勝利を収めました。

f:id:upura:20180826173155p:plain

baseball.yahoo.co.jp

今回は「七回終了時にリードを許している試合で0勝50敗」という数字が他チームと比べてどれほど突出している数字なのか(はたまた特に驚くべき数字ではないのか)、他チームも含めたデータ分析を通じて検証してみたいと思います。

データの取得

どこかに良さげなデータベースがあるかと思い10分程度探しましたが見つからなかったので、Pythonを用いて自分で収集しました。

import pandas as pd
from tqdm import tqdm

result = []
match_id = []
for i in tqdm(range(330, 826)):
    for j in range(6):
        url = 'https://baseball.yahoo.co.jp/npb/game/20180' + str(i) + '0' + str(j+1)+ '/top' 
        try:
            fetched_dataframes = pd.io.html.read_html(url)
            result.append(fetched_dataframes[0])
            match_id.append('20180' + str(i))
        except:
            pass

データの前処理

最初に、分析に必要な情報をデータから抽出します。今回は、resultというリストにpandas.DataFrame形式でスコアボードが格納されています。

result[0]

f:id:upura:20180826174214p:plain

このデータから「七回終了時にリードを許している試合か否か」の情報を取り出します。具体的な処理については、雑なpandasの処理をしてしまったので割愛しますが、興味のある方はGitHubのipynbをご参照ください。

github.com

前処理を終えた後のDataFrameの最初の10行を、下記に示します。上から2行ずつ区切りの情報になっており、例えば最初の2行は「阪神ー巨人戦で、阪神も巨人も八回から逆転勝利しなかった(False)」という意味です。9, 10行目は「楽天ーロッテ戦で、楽天は八回から逆転勝利した(True)」ことを表しています。

f:id:upura:20180826190353p:plain

データの分析

本題の分析に入る前に、きちんと全データが抽出できているかを確認しておきます。

データをチーム名でまとめ上げて(groupby)、合計を出力した結果を、実際の試合数を比較しました。オールスター戦2試合も含めて、昨日(2018年8月25日)までの全試合の情報がデータに含まれていると確認できました。

オリックス     114
ソフトバンク    108
ヤクルト      109
ロッテ       109
中日        115
全セ          2
全パ          2
巨人        117
広島        110
日本ハム      112
楽天        112
西武        111
阪神        106
DeNA      11

f:id:upura:20180826191112p:plain

そしていよいよ、「七回終了時にリードを許していた試合」に関する情報を出してみます。ここではオールスター戦の情報は省きました。

f:id:upura:20180826191915p:plain

冒頭のサンスポの記事通り、阪神は「0勝50敗」でした。

「割合」を見ると、巨人が「1勝48敗」でワースト2位。本日阪神が1勝目を挙げたので、本日時点では阪神と並んでワーストになりました。

個人的に、広島は終盤の逆転が多いイメージがありましたが、3試合のみで割合はワースト4位でした。しかし、そもそも「七回終了時にリードを許していた試合数」が38と、他チームと比べて圧倒的に少ないです。序盤から優位に試合を進めている様子がうかがえます。

DeNAは「七回終了時にリードを許していた試合数」が64で12チーム中最多。広島の約1.7倍もありました。

楽天は55試合中8試合で八回から逆転勝利に成功。順位ではパ・リーグ最下位に沈んでいますが、逆転した試合数・割合ともに12チーム中1位になりました。

まとめ

  1. 今回は、サンスポの記事の分析結果を受けて「七回終了時にリードを許している試合」について分析しました。
  2. 他チームも含めたデータ分析を実施したところ、阪神の「0勝50敗」は巨人の「1勝48敗」と合わせて12チーム中で突出して悪い数字だと分かりました。
  3. とはいえ、一番数字が良かったのがパ・リーグ最下位の楽天で、セリーグを独走する広島は数字が良くないなど、決して一般的なチーム成績と関係ある指標ではないと示唆されました。

Kaggle APIとLINE APIを用いたKernelの新規投稿を通知する仕組みの構築

はじめに

Kaggle*1において、上位の成績を収めるためには日々投稿されるDiscussionやKernel、変化するLeaderboardの動向を注視することが大切です。

現状、Discussionについては公式で新しい投稿をメール通知する仕組みがあります*2が、KernelやLeaderboardについては存在していません。8月上旬には、日本人のKaggle参加者が集まるコミュニティ「kaggler-ja」*3での会話を発端として、Leaderboardの通知に関する要望も提案されています*4

もちろん公式で実装されるのが一番良いですが、今回は暫定的な対応としてKaggle公式が提供する「Kaggle API*5を利用して、Kernelの新規投稿をLINE通知する仕組みを構築しました。

同様の枠組みを用いることで、Leaderboardの情報などKaggle APIで扱える範囲の通知機能を実装することが可能です。私自身が一番欲しかったのがKernelの通知機能だったので、優先的に実装しました。実装はGitHubで公開しています。

github.com

システムの概要

構築したシステムの概要を下図に示します。

f:id:upura:20180825162810p:plain

大まかな処理の流れは以下の通りです。

  1. 「launchd」を用いて30秒に一度シェルスクリプトを定期実行
  2. シェルスクリプトの処理
    1. Kaggle APIを実行して、Kernelの最新の情報を取得
    2. Pythonを呼び出し、前回実行時からKernelの情報に差分があるか確認
    3. 差分がある場合には、「LINE API*6で通知を送る

以下では、個々の処理について説明していきます。

launchdによる定期実行

launchdを用いることで、Mac OS Xスクリプトを定期実行する仕組みを実現できます。詳細は、私が実装時に参考にした記事*7をご参照ください。

端的に説明すると ~/Library/LaunchAgents/ に以下のようなファイルを配置して、定期実行の条件を設定できるようになっています。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
    <string>kernel-notify</string>
  <key>ProgramArguments</key>
    <array>
      <string>/usr/local/bin/zsh</string>
      <string>/Users/{user_name}/{project_name}/kernel-notify.sh</string>
    </array>
  <key>StartInterval</key>
    <integer>30</integer>
  <key>RunAtLoad</key>
    <true/>
  <key>StandardOutPath</key>
    <string>/Users/{user_name}/{project_name}</string>
  <key>StandardErrorPath</key>
    <string>/Users/{user_name}/{project_name}</string>
</dict>
</plist>

Kaggle APIの実行

Kaggle API自体の導入については、GitHubのREADMEや下記の記事などをご確認ください。

www.currypurin.com

今回はKernelの情報を取得したかったので、以下のコマンドを実行しました。ここでオプションとしてコンペティションの指定をしています。

kaggle kernels list --competition home-credit-default-risk --sort-by 'dateCreated'

前回実行時からKernelの情報に差分があるか確認

この処理以降、Pythonに委託することにしました。単純に情報を前回実行時と比較し、変更があるか否かを確認しました。

LINE APIでの通知

LINE APIの導入については、下記を参考にしました。

s4t.hatenablog.com

以下の関数を用いて、LINEに通知を送ることができます。文言も自由に編集できるので、今回は新規投稿されたKernelのURLを通知することにしました。

def line(Me):
    line_notify_token = 'YOUR TOKEN'
    line_notify_api = 'https://notify-api.line.me/api/notify'
    message = '\n' + Me
    payload = {'message': message}
    headers = {'Authorization': 'Bearer ' + line_notify_token}
    line_notify = requests.post(line_notify_api, data=payload, headers=headers)

デモンストレーション

実際に本日15時44分ごろに新規投稿されたKernel*8について、LINE通知が確認できました。

投稿されたKernel
f:id:upura:20180825171132p:plain
LINE通知
f:id:upura:20180825171002p:plain

おわりに

今回はKaggle APIとLINE APIを用いて、Kernelの新規投稿を通知する仕組みを構築しました。この仕組みを応用することで、Kaggle APIで扱える範囲のさまざまな条件下の通知機能を実装できます。

こういった仕組みも活用して、より一層Kaggleを楽しんでいきたいと思います。

脚注

KaggleのSantander Value Prediction Challengeで銀メダルを取るためにしたこと(85th place solution)

注釈

初回公開時から89→90→85位に順位変動しました。

Santander Value Prediction Challengeが本日終わり、順位は8985位で銀メダルでした。既にdiscussionに解法を投稿していますが、ブログにも日本語で共有します。

f:id:upura:20180821095435p:plain

85th place solution

主な戦略は、以下の組み合わせです。

  • "leak" が発表される以前から作成していた単一のlightGBMモデル
  • @amrrs らによる "leak" 発見モデル

単一のモデルでは、Public LBで1.37を得ていました(ローカルcvでは1.30でした)。

また、次のように "leak" を利用しています。

df1[~test_leak['compiled_leak'].isnull()] = df0[~test_leak['compiled_leak'].isnull()]

ここで、df1, df0, test_leakは下記の通りです。

  • df1は単一モデルのsubmission csvファイル
  • df0は@amrrsのsubmission csvファイル
  • test_leakは@amrrs'sの "test_leak.csv"

もちろん、こちらは概要で、実際にはもっと色々なことを試しています。

Santander Value Prediction Challengeに携わった全ての方々に感謝したいと思います!

English

85th place solution

The main strategy is the combination of the following:

  • The single lightGBM model I've created before discovering"leak"
  • The "leak" finding model shared by @amrrs

With a single model, I got 1.37 on public LB (and 1.30 on local cv).

In addition, I utilize "leak" in the following way:

df1[~test_leak['compiled_leak'].isnull()] = df0[~test_leak['compiled_leak'].isnull()]

where

  • df1 is the submission csv file of my single model
  • df0 is the submission csv file of @amrrs's
  • test_leak is "test_leak.csv" of @amrrs's

Of course, this is a simple description and I've tried a lot more.

I'd like to thank everyone involved in Santander Value Prediction Challenge!