ブログ閉鎖のお知らせ

本ブログは2023年7月17日をもって閉鎖することになりました。

2021年12月24日の開設以来、42期FDPのアウトプット公開の場として情報発信してきました。

見てくれたり反応いただいた方々、本当にありがとうございました。

ブログのコンテンツは閉鎖のタイミングで公開停止となり、移転/再公開については今の所未定です。

チームの一年間の成果を出してみました

さいごに

私たちのチームでは今期一年間、機械学習をテーマにした活動をしてきました。

このチームでは、メンバ構成的にいわゆる「ソフト屋さん」の色が強く、それがチームの判断や行動のベースになっていた気がします。

そんな自分達が機械学習に取り組み、「ソフト屋が機械学習に挑むにはどうすれば良いか?」を試行錯誤した結果を成果物としてまとめてみました。

ソフトウェアエンジニアが機械学習プロダクト開発を始めるときの心構え github.com

機械学習をゴリゴリ掘り進めた、、というものではなく(一年間で深掘りするには機械学習の世界は深すぎました・・・)、普段ソフトウェア開発をやっているエンジニアが、いきなり機械学習に取り組むことになって体験したことや、そこで考えたことを振り返って整理してみた、という内容になっています。

今後、世の中のプロダクト開発に機械学習がもっと入って来るようになると、こんな体験をするソフトウェアエンジニアも沢山出て来るのかな?と想像しています。

興味があれば是非ご一読ください。

機械学習はアジャイル開発の夢を見るか?

ふと気が付くと期末を迎え(弊社は 7 月締めなのです)、本プロジェクトも Closing の時期になっていました。控えめに言って放置気味だったこのブログですが、最後に何か書いておこうと思います。

はじめに

機械学習プロダクトの開発をアジャイルで行うのはどうなのか?について、実際に私たちがトライした経験をベースに、個人的に思うところをつらつらと書いてみます。(ここからは、アジャイル=スクラムと読み替えてもらって差し支えありません)

本エントリとは別に『ソフトウェアエンジニアが機械学習にトライするためには?』という内容で報告書をまとめているのですが、そこで書ききれなかった内容が少し入ります。

fdp-blog.hatenablog.com

何をしてきたのか?

最初にこんなことを決めました。

  • 機械学習のプロダクト開発を通じで機械学習を学ぶ
  • 活動はスクラムで行う

そして一年間、こんなことを実践してきました。

  • 3 か月 ×2 回で 2 つのプロダクト開発を行った
  • 最初から最後まで、基本にかなり忠実なスクラムで活動した

fdp-blog.hatenablog.com

その結果として思うところ

機械学習はトライ&エラーだからアジャイルがマッチする?

No。

アジャイルが狙っている不確実性とは『やってみないと分からない』だと思っています。これは逆に言うと、やってみれば分かるので、その結果を見ながら計画をアジャストし続けようという作戦です。

一方で機械学習が直面する不確実性は『できるかどうかサッパリ分からない』です。乱暴に言うと、『イチかバチか』もしくは『下手な鉄砲も数撃ちゃ当たる』的な世界です。(異論は認めます、エンジニアのスキルに依るところも大きいかも)

やってみた結果、運が良ければ一発目で正解のモデルが見つかるかもしれないし、運が悪ければ 100 万回トライしても精度が出ないかもしれません。こういう不確実性に対して『とりあえず 1 スプリントやってみる』という作戦は、あまり有効に機能しません。また『このタスクどの位で終わりそう?』という見積もりも立てることができません。

※これに対してはMLOps という仕組みがあるのですが、これも本質は『どれだけ効率的に鉄砲を撃つか』だと思っています。

つまり、機械学習でトライ&エラーをやるための繰り返しと、アジャイル開発のスプリントとして知られている繰り返しとは、本質的に異なるものです。

これを理解せずに『機械学習は繰り返しでしょ。ならアジャイルがピッタリだね!』という安易な考えでアジャイルと組み合わせると、良いことはないんじゃないかな、というのが今の私の解釈です。

探索&学習型プロジェクトにはアジャイルがマッチする?

Yes。

今回の私たちのプロジェクトは、実際にお客さんから要求が受けるものではなく、学習のための社内プロジェクトであり、自分たちでやることを探しながら&考えながら進めていくというスタイルでした。

カッコよく言えば『探索型プロジェクト』、正直には『行き当たりばったり型プロジェクト』とも言えるかも知れません(怒られそうだ)。

このような案件では、例えば事前に年間の作業計画を立てることなど不可能です。しかしながら、従来の計画型プロジェクト管理手法では、まず計画がないと一歩も踏み出すことができません。無理に始めようとするなら、予見が不可能な事象に対して何か月もかけてそれらしい(=誰にも怒られない)計画を作成し、始めてみたら全員の予想通り炎上してあの数か月はドブに捨てたね、ということになっていたでしょう。どこかで見たことある風景ですね。

ここでアジャイルの『最初に全ての計画を立てなくても走りだして良い』、言い換えると『見切り発車が可能で、かつ途中でゴールを動かしても許される』という特性が、消極的ではありますが、探索型プロジェクトにマッチすると言えるでしょう。あるいは、アジャイルがマッチするというよりは、ウォーターフォール(言っちゃった)だと確実にロスが出てしまう、と言った方が正確かも知れません。

さらにアジャイルの繰り返しによって、チームはフィードバックを得て成長するチャンスがあります。これは未知の領域にチャレンジする行き当たりばったり型の案件にとっては明らかなアドバンテージですし、ましてチームやメンバの成長が目的である学習型プロジェクトにとっては、うってつけとも言えます。

アジャイル開発は要求されるスキルレベルが高いので上級者向けと言われます。私もこれには同意ですが、一方でメンバの成長を促すという一面も確実に存在し、これが学習型プロジェクトにマッチするのは間違いありません。

学習型プロジェクト(教育目的プロダクト)については、POによるこちらのエントリも参考にしてください。

fdp-blog.hatenablog.com

fdp-blog.hatenablog.com

1 週間スプリントはきつくない?

Yes。 正直ちょっときつかった。

スクラムでは 1 週間スプリントがデファクトになっている感があり、事実スクラムガイドにもそう書いてあります。しかし今回のように、機械学習の初学者がトライする場合、いくつかの理由で厳しいと感じる場面がありました。

一つには、単純に機械学習に不慣れなことにより、思った程には開発スピードがでないという問題です。5 日間のうち 1 日はスクラムイベントで埋まるとすると、残りの 4 日間で、データ収集して、特徴量を抽出して、モデルを作成して評価するといった、いわゆる機械学習のプロセスを回すことは難しいです。

では 4 日でこなせるサイズまでタスクを小さくすれば良いのでは?と思いましたが、実際にはそれも難しいのです。上記の機械学習のプロセスは、データ収集~評価まで行って初めて完了したかどうか?の判定が可能になります。これを例えば、データ収集だけのタスクとした場合、そのタスクの完了条件(Definition of Done)を設定することができないのです。

これが慣れ親しんだソフト開発であれば、例えば設計と実装を別のタスクに分けてしまい、最初のスプリントは設計を、次のスプリントでは実装を、ということ不可能ではありません。(突っ込みたくなる人はいるでしょうが)

つまり、分解できるタスクの最小サイズが制約されるために、今の私たちの開発力では 1 週間スプリントを上手く回すことができないケースが発生したのです。

もう一度やるとしたらどうする?

アジャイルでやります。

今期のプロジェクト期間中は、いろんなことに意識が発散しすぎてしまい(言い訳)、アジャイル/スクラムのプロセス自体を見つめ直したり、それを磨き上げることにリソースを充てられていませんでした。最終日前日になってこのエントリを書きながら、なるほどそういうことだったのか~と納得している始末です。言語化マジ大事。

でもカイゼンこそがアジャイルの最大の武器です。 もう一度やるとしたら、きっと『強くてニューゲーム』状態で無双できるんじゃないか? そんなことを考えています。

さいごに

と言っても、来期は別のメンバにバトンタッチです。

私たち42期のチームBoatがやってきたことが、少しでも次のチームの手助けになれば良いな、と願っています。

Serverless FrameworkでSlackアプリを作ってみる

はじめに

こんにちは。永和システムマネジメント FDPメンバの坂部です。

FDPでは、4月からSlackアプリの作成に取り組んでいます。

今回は、下記のツールセットでSlackアプリを作ってみます。

  • Bolt
  • Python
  • AWS Lambda
    • コンテナイメージ
    • AWS Lambda Function URLs
  • Serverless Framework
  • VS Code Remote Container

目指すのは、「hello」と発言すると、応答してくれるアプリです。

Boltのチュートリアルにあるやつです)

VS Code Remote Containerの設定

開発環境にはVS Code Remote Containerを使用します。

./devcontainer/devcontainer.json

{
  "name": "sample-serverless-slack-app",
  "dockerFile": "Dockerfile",
  // Lambdaコンテナイメージのデプロイで使うDocker
  "features": {
    "docker-in-docker": {
        "version": "latest",
        "moby": true,
        "dockerDashComposeVersion": "v1"
    }
  },
  // AWSのクレデンシャルはコンテナ外の環境変数に設定して、コンテナ内に渡す
  "containerEnv": {
    "AWS_ACCESS_KEY_ID": "${localEnv:AWS_ACCESS_KEY_ID}",
    "AWS_SECRET_ACCESS_KEY": "${localEnv:AWS_SECRET_ACCESS_KEY}"
  },
  "postCreateCommand": "pip install -r requirements.txt",
  "settings": {
    ...
  },
  "extensions": [
    ...
  ]
}

./devcontainer/Dockerfile

# Python3.10を試したかったが、Lambdaのコンテナイメージが3.9までしかサポートしていない
FROM python:3.9.11

# serverlessをインストール
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash -
RUN apt-get install -y nodejs
RUN npm install -g serverless@3.12.0

Serverless Frameworkの設定

serverless.yml

service: sample-serverless-slack-app

frameworkVersion: "3"

provider:
  name: aws
  region: ap-northeast-1
  ecr:
    images:
      appimage:
        path: ./ # 同じディレクトリのDockerfileを参照
  iamRoleStatements:
    - Effect: Allow
      Action:
        - secretsmanager:GetSecretValue
      Resource:
        - "*"  # よくない 😡

functions:
  app:
    image:
      name: appimage
    url: true # AWS Lambda Function URLsを使う
    events:
      - http:
          method: post
          path: /slack/events

Lambdaの設定

Dockerfile

FROM public.ecr.aws/lambda/python:3.9

COPY requirements.txt ./

RUN pip install -r requirements.txt

COPY app.py ./

CMD [ "app.handler" ]

requirements.txt

slack-bolt==1.13.0
boto3==1.12.42

app.py

import json
import logging
import os

import boto3
from slack_bolt import App
from slack_bolt.adapter.aws_lambda import SlackRequestHandler

logging.basicConfig(level=logging.DEBUG)

# SlackのクレデンシャルはSecrets Managerに格納している
# serverlessに環境変数として渡した方が良いかも 🤔
secretsmanager = boto3.client("secretsmanager", region_name=<your_region>)
secret_value = secretsmanager.get_secret_value(SecretId=<your_secret_id>)
secret = json.loads(secret_value["SecretString"])

os.environ["SLACK_BOT_TOKEN"] = secret["SLACK_BOT_TOKEN"]
os.environ["SLACK_SIGNING_SECRET"] = secret["SLACK_SIGNING_SECRET"]


app = App(process_before_response=True)


# 「hello」のメッセージに応答する
@app.message("hello")
def message_hello(message, say):
    say(f"Hey there <@{message['user']}>!")


def handler(event, context):
    slack_handler = SlackRequestHandler(app=app)
    return slack_handler.handle(event, context)

デプロイしてみる

コンテナ外でAWSのクレデンシャルを設定します。

export AWS_ACCESS_KEY_ID=<your access key>
export AWS_SECRET_ACCESS_KEY=<your secret access key>

あと、AWSコンソールでぽちぽちして、Secrets ManagerにSlackのクレデンシャルを登録しておきます。

デプロイします。

sls deploy
sls deploy

Deploying sample-serverless-slack-app to stage dev (ap-northeast-1)
Warning: Docker authentication token will be stored unencrypted in docker config. Configure Docker credential helper to remove this warning.

✔ Service deployed to stack sample-serverless-slack-app-dev (182s)

endpoints:
  POST - https://??????.execute-api.ap-northeast-1.amazonaws.com/dev/slack/events
  app: https://???????????????.lambda-url.ap-northeast-1.on.aws/
functions:
  app: sample-serverless-slack-app-dev-app

1 deprecation found: run 'serverless doctor' for more details

下記を参考に、Slackアプリを作成します。

slack.dev

https://slack.dev/bolt-python/ja-jp/tutorial/getting-started-http#httpを利用したイベントを設定する あたりを参考に、発行されたURLをSlackアプリに設定します。

「hello」と発言してみます。

f:id:sakabehiroki:20220416192806p:plain

無事、動作しました 🎉

余談

2022/04/16時点で、Serverless Frameworkでよく使われるプラグインの、serverless-offlineがLambdaのコンテナイメージに未対応なので、注意したほうが良いかもです。

github.com

参考

slack.dev

slack.dev

github.com

docs.aws.amazon.com

www.serverless.com

1on1をやってみた

はじめに

Agile Studioの岡本です。

チーム内で1on1をやってみたのでその様子を紹介(という程の中身はない)してみます。

1on1とは

とりあえずググってみると・・・

1on1ミーティングとは、人材育成を目的として上司と部下が1対1で行う対話(面談)のことです。

↑ だいたいこんな感じ。

ウソーーー!!

いや、嘘ではないでしょうが、やりたかったのはこういうのではないです。

やりたかったこと

メンバのみんなが、私やこのプロジェクト、チーム、他のメンバ達に対してどんなことを考えているか、もうちょっとプリミティブなレベルでどんな感情を持っているかを知りたかったです。

普段の業務から分かることもあれば、雑談の中で感じ取れることもあるでしょうし、もしかしたら1対1で会話をしたらそれ以外のことも何か見えてくることがあるかも知れない、くらいのフワッとした期待です。

やってみた

1on1 グランドルール

開始前にこれだけを相手に伝えてからやりました。

  1. フラットな会話
  2. 内容はオフレコ
  3. 来た時よりもスッキリして帰る

上司と部下面談ではないのでフラットなのは当たり前(そもそもチーム内の4人に上司部下の関係はありません)ですし、そもそもの目的が私個人の『何か知りたい、感じたい』位なので、話の内容を誰か外部に出すこともありません。

最後の1つはちょっとルールとは違う努力目標みたいなものですが、これは昔の上司に言われた『相談に来たのに余計暗くなってどうすんねん!』という言葉を今でも真理だと信じているためです。

話すネタ

基本的に手ぶらで臨みました。
なので8割くらいは雑談の延長という感じでした。

一応は保険として、チームビルドの時にやったドラッガー風エクササイズから、『AさんがBさんに期待すること』を内容をメモしておいて、『こんな期待で始めたけど実際はどんな感じ?』みたいな話をしたメンバもいました。

お互いの期待

fdp-blog.hatenablog.com

総当たり方式

いわゆる総当たり方式でやってみました。 これは別にが勧めた訳ではなく、メンバの中で自発的にやってみようか?という流れでこうなっています。

総当たり方式

上司部下の面談ではないので、これも当たり前と言えば当たり前ですね。

他のメンバ同士ではどんな会話をしていたのかちょっと気になりますが、オフレコなのでまったく想像できません。気になる。

感想

単純に面白かったです。

世の中的には冒頭のように『上司と部下の面談』みたいな固いものを指す場合もあるようですが、こんな感じで緩くやるのも良いんじゃないかなと思いますね。

オチはありません。

私たちのスクラム紹介 ~守破離の守を目指して~

はじめに

Agile Studioの岡本です。
今回は私たちのチームがやっているスクラムのスタイルと、チームで独自に工夫している点について紹介してみます。

チーム構成

PO1名(組織体制上の上司でもある岡島さん)、SM1名(岡本、DEVも兼任)、DEV3名(坂部さん、見澤さん、三田村さん)で構成しています。

各メンバ紹介はこちらにも書いています。

fdp-blog.hatenablog.com

メンバ全員のスクラム経験が浅い(SMの岡本も!)ため、まずは教科書通りのスクラムつまり『守破離の守』を目指してやってみよう、という所から始まっています。

スクラムイベント

下記のような基本パターンをかなり忠実(意図的)に実施しています。
「守破離の守」ですので!

お手本にしているスクラムイベント

スプリントプランニング

  • 開催:水曜日(11:00-12:00)
  • 参加者:PO、DEV、SM
  • 目的:次のスプリントの計画
  • アクション
    • スプリントゴールの設定:スプリントのゴールについて合意する
    • タスクの優先度決定:PBIを優先順に並べかえる
    • スプリント達成条件の確認:POと達成条件について合意する
    • スプリントバックログの作成:チームのベロシティ分だけPBIをスプリントバックログに積み上げる

デイリースクラム(朝会)

  • 開催:毎日(09:15-09:30)
  • 参加者:PO、DEV、SM
  • 目的:一日の起動トリガ、タスク状況確認、情報共有
  • アクション
    • あいさつ:気持ちを仕事モードに入れる
    • 昨日のタスク:各自で昨日やったことを共有
    • 今日のタスク:全員でカンバンをみながらタスクの確認
    • 連絡事項:休みや直近の予定があれば共有

バックログリファインメント

  • 開催:火曜日(15:00-16:00)
  • 参加者:DEV、SM
  • 目的:次のスプリントプランニングの準備
  • アクション
    • タスクの細分化:プロダクトバックログアイテム(PBI)を見積もり可能&完了定義が可能なレベルまで分割する
    • タスクの見積もり:PBIにストーリーポイントを設定する

スプリントレビュー

  • 開催:水曜日(10:00-11:00)
  • 参加者:PO、DEV、SM
  • 目的:今スプリント成果の確認
  • アクション

    • デモ:成果物をPOに対してデモする
    • 受け入れ:成果物が完了条件を満たしているか確認する
    • フィードバック:POからスプリントに対するフィードバックを受ける
  • 完了の定義
    当初は完了の定義を明文化しておらず、スプリントレビューの度にPOへの補足説明に追われたり、微妙な空気のOKになったりして不安定だったので、最近になってカイゼンしてみました。

完了の定義

  • 受け入れ条件の一例
    レビューを受けるユーザーストーリーの単位でPOがスムーズ&客観的なチェックが出来るようにテスト項目的に書き出しています。
    受け入れ条件の例

レトロスペクティブ(ふりかえり)

  • 開催:水曜日(13:00-14:00)
  • 参加者:DEV、SM
  • 目的
  • アクション
    • ネタ出し:KPTをベースに各自が感じていることを付箋に貼りだす
    • 感想戦:付箋を見ながらチーム内で雑談する、結論は出さなくていい、改善Tryも無理に出さなくていい

ふりかえりのKPT

ツール

スクラムのワークで中心的な役割を持っているツールです。

カンバン(GitHub Projects Beta

こちらのエントリでも紹介している通り、GithHub Projects(Beta)をカンバンとして使っています。

fdp-blog.hatenablog.com

プロジェクト開始当初(学習メインのフェーズ)ではツールに不慣れなメンバもおり、とっつきやすさを重視してMiroでカンバンを運用していましたが、開発メインのフェーズに入ってくるとソースコードから離れて生きることは不可能なので、チームで相談してカンバンを含めてプロジェクト管理の大半をGitHubに寄せてしまいました。

タスクカンバン

ホワイトボード(物理)

リモートワーク主体のチームですが、たまに出社するとホワイトボードを使っての議論や説明をすることもあります。

言葉では上手く説明できないのですが、個人的に手描きのスピード感と温度感が好きなので、使える場面では割と積極的に使っています。

f:id:Okamoto-Takuya:20220314230252j:plain
手描きの何か

その他

リモートワークを効率的に行うために他にもいろいろなツールを試しながら使っています。

fdp-blog.hatenablog.com

カスタマイズポイント

冒頭で書いた通り、初心者スクラムチームなのでまずは可能な限りシンプルなルールでやってみようというところから始めています。
とは言っても、開始から3か月近くスクラムを回していると、色々と自分たちの文脈に沿って調整したい点も出てきました。

以下、チームで考えて工夫している点をいくつか挙げてみます。

タスク単位の見積もり

通常のスクラムではストーリー(=PBI)単位にストーリーポイントを付けて見積もりますが、私たちのチームではもう一段階詳細化したタスク単位で見積もりを行っています。

このようにしている理由は、今回の開発対象ドメインにチーム全体が不慣れだったため、ストーリーの粒度では必要になる作業の大きさがサッパリ想像できなかったためです。
そのために、より具体的な作業がイメージできるタスク単位に分解してから、そのタスクの大きさを見積もることにしました。

PO(顧客)目線から見ると『このプロダクトはいつ頃完成するのか?』という問いには答えにくくなりますが、今回はそれよりもメンバ自身が自分たちの作業量やベロシティを把握しやすくなることを優先しました。

見積もりの粒度はS・M・Lの3段階

いわゆる『Tシャツサイズの見積もり』です。

これも自分たちが見積もりに不慣れなため、詳細なポイント付けは不可能(やっても意味はない)と考え、であれば一番シンプルなやり方でということでこの3段階にしています。

ストーリーポイントは、S(1ポイント)、M(3ポイント)、L(5ポイント)と単純明快になっています。

タスクのサイズ

カイゼンタスク

スプリントプランニングで洗い出したタスクとは別に、途中で発生した/やりたくなった作業については カイゼン という扱いにして自由に追加するようにしています。

外部からの割り込みに似ていますが、こちらはチーム内部で発生した(もしくは発見された)作業が中心になります。
プランニング時により精緻な洗い出しをしていれば最初から計画できた作業もありますが、今はそこに時間を掛けるよりは気が付いたらすぐに手を動かせるスピード感を優先してこのような運用にしています。

カイゼンタスク

もちろん弊害も認識していて、このカイゼンタスクはポイントとして計上していないために、チームのベロシティを正しく把握できなくなるリスクも あります。これは次に解決したい課題だと思っています。

バーンダウンではなくバーンアップチャート

プロジェクト開始時に全てのストーリーとタスクを洗い出しポイントを付けることが出来なかったため、一般的なバーンダウンチャートを描くのは困難になってしまいました。頑張って描いたとしても、途中でストーリーやタスクの追加が頻発して、チャートが乱高下するのは必至です。

こうなると本来の目的であるベロシティの可視化が難しくなるため、今回はベロシティ(の変化傾向)の把握を最優先として、バーンアップチャートを描くことにしました。

またこれは各スプリント内のペース変化よりも、全スプリント期間を通しての傾向を掴む意味でも良かったのではないかと考えています。

バーンアップチャート

ちなみに現在のチャートからは以下の点が可視化されています。

  • チームのベロシティはプロジェクト開始当初からほぼ一定であり、チームはあまり改善されていない
  • タスクに対する見積もりの精度は、それなりに安定している(大きく外している訳ではなさそう)
  • スプリント終盤(最終日)に駆け込みで達成するタスクが多く、計画的に消化できていない

こういうところを見つけて改善のアクションに繋げていく必要があると思っています。

夕会

デイリースクラムとしては一般的な朝会をやっていますが、それとは別に一日の締めくくりとして夕方に軽く雑談を兼ねて各自の状況共有を行う時間を作りました。

最初はやっていなかったのですが、タスクの進み具合に不安があったり他のメンバにヘルプを求めたいときには、次の日の朝会まで持ち越さずに早めに共有したいという意見が出てきたのでスクラムイベントとして追加しました。

想定していた『困っていること』の共有の他に、『今日はここまでできた!』といった前向きな情報も共有できるので、以前よりもスッキリした気分で一日を終えられる感じがして気に入っています。

ミニマムで始める

これは具体的なカスタムポイントではありませんが、SMとして意識している点です。

スクラムはシンプルなルールであると言われますが、それでもいきなり全部を理解して実践するのは難しいと考えました。
形を真似て実行することは出来ると思いますが『本当に腹落ちしているか?』と聞かれるとかなり怪しいと思います。

そこで最初は必要最小限の決め事だけでやってみて、メンバ自身が『何か足りないな』『これはもうちょっと決めないとダメかも』と感じたタイミングで、そこに必要なプラクティスを追加したり、簡略化したルールを本来の定義に戻したりするように心掛けています。

内部プロジェクトかつ育成のミッションを持っているからこそできる贅沢とも言えますが、一年かけて色々と実験してみようの精神でトライ&エラーを沢山積み重ねていきたいと思っています。

さいごに

『守破離の守』ということでベーシックな運用をしているつもりですが、思った以上に自分たちで考えるポイントがあったかな、というのが正直な感想です。

これは足りていないから考えるという訳ではなく、スクラム的にはこれ位のカスタマイズをするのが標準(変な日本語ですが)なんだろうと思います。

スクラムの研修などを受けると『スクラムプレイブック(自分たちのチームのルール)を作りなさい』と言われますが、今回やってみてその意味が良く分かりました。

機械学習の定番お題「タイタニック号の生存予測」をやってみた

はじめに

こんにちは。FDPメンバの見澤です。

今回(といっても2カ月くらい前)、機械学習初心者向けの定番お題「タイタニック号の生存予測(回帰)」に取り組みました。 機械学習について2021年10月から勉強を始めて、少しは分かってきたかなという状態での「タイタニック号」への挑戦でした。

やったこと

データを眺める

データを入手して、教師データを眺めてみました。

基本統計量は、こんな感じ f:id:k-misawa:20220225161345p:plain

前処理

欠損データがあるかを確認をしました。すると、「年齢」・「客室番号」・「出港地」に欠損データがあるようです。 これらの欠損データをどのように扱うのか?ということを考えることがとても大事だな、といつも感じます。

欠損データを削除するのか、何かの値で補完するのか。補完する場合、どのように補完するのか。 機械学習初心者の私が、まず立ち止まる箇所がここです。 それで、「乗船クラス」という項目があるので「客室番号」は、説明変数から削除しても良いかと考えたので、補完はしませんでした。 「年齢」と「出港地」については、生存との関係がありそうだと考え、それぞれ中央値と最頻値で補完しました。

そして、文字列を数字に変換し、教師データとテストデータに分割したら、いよいよ学習です!

学習と予測

今回は、決定木を使用しました。

なぜ、これを選択したのか?10月から機械学習の学習を始め、ナイーブベイズ法とk-means法を学習しました。 そこで、まだ学習に取り組んだことのない手法でやってみたい、という気持ちでこの手法にしました。

学習と予測

# 説明変数(X)がPclass,Sex,Age,Embarked
# 目的変数(Y)がSurvived

train_X = train_a[["Pclass", "Sex", "Age", "Embarked"]].values
train_Y = train_a["Survived"].values

tree.DecisionTreeClassifier().fit(train_X, train_Y)

test_X = test_a[["Pclass", "Sex", "Age", "Embarked"]].values
pred_Y = tree.DecisionTreeClassifier().fit(train_X, train_Y).predict(test_X)

予測の評価

予測結果を評価しました。 評価には、accuracy_score precision_score recall_score f1_score を使用しました。

正解率:0.8161434977578476
精度:0.7866666666666666
検出率:0.7023809523809523
F値:0.7421383647798742

評価の数字を見ると、それなりに良さそうです。

感想

これまでは、チームで一つのお題をモブプロとかで取り組んでいたのですが、今回のお題は、初めて一人で取り組みました。 分からないことは調べながら、何とか一通りできました。

今回感じたことは、

  • グラフで可視化するって分かりやすくていいな(データの数字だけを眺めるよりも分かりやすい!)
  • データの扱い方(欠損データの扱い、説明変数の扱いとか)を考えることって、大事!
  • 機械学習に限ったことではないけど、変数名は、意味合いが予測しやすいものにしないと、自分でも混乱してしまう

一人で取り組んだことで、自分が何を理解できていないのか(理解した気になっていた)、が分かったような気がします。

同じお題を別の手法でやってみるのも、結果が違ってくるだろうから面白そうだしやってみたい、と思いました。