Lean Baseball

No Engineering, No Baseball.

CTOになる前・なった後に学んだこと - 「エンジニアのためのマネジメントキャリアパス」を読んで

f:id:shinyorke:20190211162241j:plain

去年からメチャクチャ気になってた「エンジニアのためのマネジメントキャリアパス」、読みました&あっという間に読了しました.*1

エンジニアのためのマネジメントキャリアパス ―テックリードからCTOまでマネジメントスキル向上ガイド

エンジニアのためのマネジメントキャリアパス ―テックリードからCTOまでマネジメントスキル向上ガイド

  • 作者: Camille Fournier,及川卓也(まえがき),武舎広幸,武舎るみ
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2018/09/26
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログ (1件) を見る

エンジニア組織のマネジメントをはじめて正味2年ちょい、CTO歴(やっと)1年の自分としては、

CTO・エンジニアリングマネージャーになる前に読んでおきたかった!!!ってぐらいの名著でした!!!

っていうくらい素晴らしい書籍でした、自信を持ってオススメできます.

このエントリーでは、

この三本立てで感想なりポエムなりしたいと思います.

TL;DR

  • テックリードやマネジメントへのキャリアを考えてる方もそうじゃない方も、「エンジニアのためのマネジメントキャリアパス」一度は読んでおけ
  • ゼロからはじめるエンジニア組織作りは、エンジニアとしてもビジネスマンとしても視座・視野が広がり、仕事を通じて色々と学べる
  • テックリード、エンジニアリングマネージャー、CTO(VPE)目指すなら小さいところからはじめるのオススメ&最後は技術に頼るトコ多いやぞ!

スタメン

私のエンジニア・マネジメントなキャリア

昨年のデブサミでもちょっと触れていますが、改めて棚卸し.

  • 2018年〜今:ネクストベースのCTO.フルタイムのエンジニアは2人(自分込み)、他に学生インターン1人、ちなみに経営陣ではありません*2
  • 2017年1月〜9月:Rettyでテックリード→エンジニアリングマネージャー
  • 2016年(半年程度):ビザスクでインターンのメンターやったり小規模プロジェクトのリードしたり
  • 2014年(三ヶ月ぐらい):SUUMO(リクルート)のとある事業のエンジニアリード
  • 2012年ごろ(これも半年):ベイカレント・コンサルティングのとある顧客チームのエンジニア・リード

途中メンバーに戻ったり色々と紆余曲折ありましたが今は何とかかんとか小さいチームながらもCTOやってる人、そう見てもらえればと思います.*3

「エンジニアのためのマネジメントキャリアパス」の感想

感想をザックリ書くと

技術系管理者のキャリアパスを大局的な見地に立って紹介している本。キャリアの各段階に即したきわめて戦術的な助言や提言が得られる。技術系の管理者は部下に対して、優れた管理術を身につける責任を負っている。本書で管理のノウハウを学んで欲しい。技術系管理者の職責を詳細に紹介、解説している実用的な手引書である。

エンジニアのためのマネジメントキャリアパス」 推薦の声より.

全くもって「推薦の声」どおり、ホントにそのとおりの本でした.

そして私の感想は、

  • 今までテックリードやエンジニアリングマネージャーをやってきた数々の失敗について大いに反省した
  • 何故失敗したか?どうすれば同じ失敗をしないか??、のヒントと指針をたくさん頂いた
  • CTO #とは という、エンジニアの数だけ考え・意見を持っているこの件に対する自分なりの「CTO道」が見えた&登る気になる元気をもらった

このエントリーを書くため、もう一度はじめの章あたりを読んでいるのですが、くしくも及川卓也さんの「まえがき」と同じことを言ってる気がします.

これから本書を読もうとする読者の方々にこんなことを言うのはふさわしくないかもしれないですが、本書を読み終わった後、私はひどく落ち込んでいる自分に気づきました。それは、本書の内容に不満があったり、不快に感じた部分があったということではまったくなく、むしろ逆にその内容が素晴らしい故に、いかに自分が未熟であったかを思い知らされたからでした。

エンジニアのためのマネジメントキャリアパス」 まえがき、から抜粋.

この本を手にとったマネージャーの方々(私含む)、きっと同じ感想なんだろうなと思います(真顔).

目次と概要

章ごとに何が書いてるかという簡単な解説を.

個人的には、

自分がどのフェーズにいようが、最初から最後まで読むとストーリーを十分追えるのでかなりオススメです!*4

推薦の声・まえがき・はじめに

読む前のイメージを掴む意味でもしっかり読んだほうがいいトコでした.

いやこれはホントすごい*5.

1章 マネジメントの基本

名前の通り、「そもそもマネジメントってなんぞや?」という話.

1on1やフィードバック、トレーニングって、、、というところを触れています.

個人的にはこの辺も合わせ読むと理解深まると思いました.

ヤフーの1on1―――部下を成長させるコミュニケーションの技法

ヤフーの1on1―――部下を成長させるコミュニケーションの技法

実際、1on1本読んでたおかげでこの辺はスッキリと内容が入りました*6.

2章 メンタリング

名前の通り、新人や新規加入メンバーに対するメンタリングについての章.

個人的には今まで複数社で学生さんや新人のメンターをしてきたので、その経験と合わせ、色々と思い出しながら読みました.

3章 テックリード

開発チームの責任者たる、「テックリード」に関する章.

  • 職務時間の3割程度、チームと共にコードを書きつつ
  • 開発チームに対する責任を担う、開発リーダー

たる方々に対する章です.

なお、この本で(特に心に傷負うことなく)スラスラ読めるのはこの辺までかなと思います(真顔)*7

4章 人の管理

こっから心の傷に塩をすり込むような内容が増えてきます(震え)

いわゆる、「部下を持った管理職」に対する助言・考え方が中心です.

自分は読みながらこの辺にブクマしてました.

「継続的なフィードバック」の文化をチームに根付かせる

勤務評価など、「管理職として何かしらのアクションを起こす」前にちゃんと「継続的にメンバーを見てフィードバックしてますか?」と説いててなるほど!と思いました.

  • 部下の基本情報を仕入れる
  • 日頃から部下を見守る習慣を
  • 深刻な話題も日常レベルのフィードバックで「さらり」と

それぞれ何書いてるかは実際に本を手にとって読んでほしいのですが、私からすると色んな思い出が走馬灯のように蘇る内容でした(真顔)

5章 チームの管理

一つのチームに対する課題・問題解決の章.

本の表現としては、

機能不全に陥ったチームの「デバッグ」の基本

というド直球な表現で記載されています.

いろいろと書いてあって学びも深かったのですが、私は特に、

誰しも人に好かれたいのはやまやまだが、管理者は「優しさ」よりも「親切」を旨とすべし

この言葉が一番刺さりました.

6章 複数チームの管理

複数のチームを束ねる職責、「技術部長」「開発部長」みたいな肩書を持ったときの心得など.

この章に書いてること、今の所無縁かなあ?と思いつつも、ここが刺さりました.

部長職を引き受ける前にたっぷり時間をかけてコードを書く作業を十分経験し、最低でも1種類のプログラミング言語を自在に使いこなせるようになっていないと、コード書きの作業からすっかり「足を洗ってしまう」ことの危険ははるかに大きくなります。

私は幸いにも(言うても2名+1名チームなので)バリバリコードは書いてる、Pythonであれば手足のように自在に操れる*8のでこの危険には面してないのですが、

「こいつイケてないなあ」っていうエンジニアリング・マネージャーや部長はこの傾向思いっきり当てはまるのでは?と思い震えました.

7章 複数の管理者の管理

複数チーム管理に加え、「管理者を管理する」という、「ヴァイス・プレジデント見習い」みたいな職責についたらどうしますか?の話.

  • 道を踏み違えてる新任管理者を何とかする
  • ベテラン管理者(会社のカルチャーに合ってない)をどうにかする

...中々震える話が多い印象でした(震え)

その他、技術投資(いわゆるR&Dとか)もこの辺で触れています.

8章 経営幹部

「あなたは経営陣のひとりです!」的なポジションについたら、の章.

こっからいよいよCTO的な内容です.

技術戦略や優先順位、やりにくい仕事(例:レイオフを伝える)をどうする?などに触れています.

9章 文化の構築

会社の文化・思想をどうやってポリシー作ったり、職務・給与レンジに合わせた組織作り(キャリアラダー)どうする?的な章.

横断的なチーム作りや、意外なところでは「コードレビューを通じた文化作り」などにも触れています.

10章 まとめ

まとめというか励ましというか...w

エンジニアリングなマネージャー業ふりかえり

...とまあ、色々と感想を書きましたが、自分の実務体験上どうだったか?のふりかえりをします.

「傾聴」の大切さ

メンバー相手の1on1、インターンくんや新人くんとの会話、経営陣とタイマンをはるetc...

結局何をするにしても、「傾聴」って重要だな!っていう学びがありました.

1on1でのアドバイスがうまく行ったときも、「予算くれ!」と交渉するときも、

  • 相手の立場や仕事だけじゃなく、人柄も把握する
  • 話を聞く、と同時に自分もオープンになる
  • 事によって、モノゴトが少しずつでも前に進む

これらがうまく行くと結果が出ましし、逆に結果に結びついてない時はどれかが欠けてるなあ〜、という印象があります.

「プロセス」の使い所(なんでもアジャイルにすんな)

「process czar(プロセスツァー)になるな!」そういうことです.

エンジニアのためのマネジメントキャリアパス」の3章で、かなりいいことが書いてました.

プロセスツァーの「対極」に位置するのは、「プロセスを完全に排除する管理者」ではありません。そうではなく、「プロセスは、チームのニーズや、チームが進めている作業のニーズを満たさなければならないという点を深く理解している管理者」です。

皮肉なことに、アジャイルは多くの場合、(「機敏な」「素早い」といった本来の意味とは正反対とも思える)「厳格な」方法論に基づいて実装されます。*9

私自身、アジャイルの信奉者ですが、エンジニアリング・マネージャーしたりCTOしながらこれに薄々気がつく→徐々にやり方を変えたことによってよかったことがあった(≒変える前はいくつもの失敗を重ねていた*10)なーっと学びました.

これはCTOになる前はちゃんと言語化出来てなかったのですが、知らない間に行動に移せたので良かったのかなと思っています.

なお、昨年のこちらのエントリーにそのまま直結する話であるとも思っています.

shinyorke.hatenablog.com

「技術アピール」からはじめる人脈つくり

カンファレンスでの発表、もくもく会の主催そしてこのブログを通じて今の仕事にたどり着いた、のもありますが、「この人はリードたる技術とかあるよね」的な信頼を外堀から埋める意味でやっててよかったと思っています.

何かのイベントをするときに登壇してくれたり会場提供してくれたりという支援をもらったり、逆に自分も支援して信頼貯金を稼げたりといい事づくしだったと思います.

っていう話はこの辺にもあるのでご興味ある方はぜひどうぞ.*11

note.mu

ゼロからのチーム作り(まさに今)

これはCTOとして現在進行系のことなのですが、今まで培ってきた人脈やつながり、採用スキルを生かして「世界最強の野球エンジニア・チーム作り」をゼロからやれているのは良いことかと思っています.

11月に一人フルタイムでJOIN、今後ももっと人増やせるように頑張ってる最中(詳細は言えませんが)ですが、ここまでに至る所で今までの経験が生きていて、

「ちょっと遠回りしたエンジニア人生だったけどよかったのでは?*12

と思っています.

テックリード、エンジニアリングマネージャー、CTOを目指す方へ

最近たまにこういう相談受ける&だいたい、いつも同じ回答な気がするのでまとめて書こうかなと.

CTO1年生を終えて2年生の自分が言うのも恐縮ですが、

  • 創業期もしくは資金調達後の1人目エンジニアからはじめようぜ!
  • 「目標とするエンジニア」「憧れのCTO」像を明確に持って自分を鍛える

この二つをオススメします.

創業期もしくは資金調達後の1人目エンジニアからはじめようぜ!

実を言うと、エンジニアのためのマネジメントキャリアパス」に書いてあること、まんまです.

望む望まない関係なく、色んな経験が降ってきますし、途中の採用や、「ブリリアントジャーク*13」対策など、嫌というほど味わえます.

「このチームで働きたい!」っていう所にあったらスッと挑戦すべきです.

なお、大企業出身者の人だと「部課長になってから動けばなれるのでは?」「声かかるまで待つ」的な人もたまに見受けられますが、

  • 確実にアテになる人脈あるならそれでも構わない、時期見て入っちゃおう
  • 人脈が無い(アテがない)場合、何かしらの外部アウトプット・活動が無いとそもそも検索にヒットしない(SEOみたいなもの)

という現実と向き合った上で判断したほうがいいかなと思います.*14

「目標とするエンジニア」「憧れのCTO」像を明確に持つ

これは本に書いてない事です.

CTOになる前・なった後両方共、

「あの人(スーパーなエンジニア)だったらどういう判断・決断するかな?」

という想像と、自分が下した判断・決断のDiffを取る事により、自分の技術・ビジネススキルや判断力・決断力を磨くようにしてました.

その対象がCTOやVPEだったりすると、Diffを取ってる内に自然とCTOやVPEに必要なスキル・判断力・決断力が身につくと思うので、ぜひやってみては!?

以上、今年はじめての書評でしたー

*1:出たのは昨年ですが、昨年は意図的にこの手の本を避けていたので今年に入ってから読み始めましたとさ.

*2:が、エンジニアリングに対する責任は自分が持っていること、決断・判断に必要な権限は有しているのでCTOと名乗っても問題ないと思っています.

*3:出入りが激しいのは転職が多いからってのとやっぱ寄り道と言うか紆余曲折が

*4:私はAction Reading好きで結構飛ばしながら読む派なのですが、この本に関してはそれは該当しないと思い、時間かけて最初から最後まで読みました.

*5:まえがきでここまで読み応えがある本も珍しい.

*6:1on1の是非そのものは別として、Yahooのこの本は名著です、結構好きだし参考にしました.

*7:ここまでは割と大体の人が経験するハズ、何らかの形で.

*8:今までは野球のことがしたくてずっと分析・解析コードを書いてましたが、今は休みの日はちょっとした作業や写経を通じてコード書くようにして腕が腐らないようにしています

*9:厳しいことを言うと、アジャイルコーチやスクラムマスターで結果でない・イマイチな人はこれに気がついてないもしくは気がついてるけど無視してる、のどちらかだと思う.

*10:失敗は成功の母とはよく言うもんだなと、いやホント学んだし当時の関係者には申し訳ないというお気持ち

*11:我ながらよくまとまってると思う

*12:今年でキャリア19年目、40歳でマネージャー業が正味2年ちょい、残り17年は思いっきり回り道してたよ!って意味

*13:意味は本読んで欲しい、実際この対策色々と経験してちょっと強くなった感ある

*14:これも厳しいこと言うと気が付かない人は「大企業病」に罹患してるよきっと

うわっ…私のpandas、遅すぎ…?って時にやるべきこと(先人の知恵より)

f:id:shinyorke:20190120111403j:plain
※あくまでもイメージです(適当)

仕事じゃなくて、趣味の方の野球統計モデルで詰まった時にやったメモ的なやつです.*1

一言で言うと、

約19万レコード(110MBちょい)のCSVの統計処理を70秒から4秒に縮めました.

# 最初のコード
$ time python run_expectancy.py events-2018.csv
       RUNS_ROI
outs          0     1     2
runner
0_000      0.49  0.26  0.10
1_001      1.43  1.00  0.35
2_010      1.13  0.68  0.32
3_011      1.94  1.36  0.57
4_100      0.87  0.53  0.22
5_101      1.79  1.21  0.50
6_110      1.42  0.93  0.44
7_111      2.35  1.47  0.77
python run_expectancy.py events-2018.csv  72.93s user 3.75s system 99% cpu 1:16.83 total

# 完成形
$ time python run_expectancy.py events-2018.csv
       RUNS_ROI
outs          0     1     2
runner
0_000      0.49  0.26  0.10
1_001      1.43  1.00  0.35
2_010      1.13  0.68  0.32
3_011      1.94  1.36  0.57
4_100      0.87  0.53  0.22
5_101      1.79  1.21  0.50
6_110      1.42  0.93  0.44
7_111      2.35  1.47  0.77
python run_expectancy.py events-2018.csv  3.68s user 0.64s system 100% cpu 4.291 total

学びの整理、自分への戒めとしてちょっとだけメモを公開します.

TL;DR

  • Dataframe処理からfor文を戦力外通告し、データを絞って処理したら70秒掛かってた処理が6秒になりました(小並)
  • df.iterrows()が許されるのは写経&実験コードぐらい.ちゃんとmapを使おう(applyは要審議),データは必要な分だけ読み取りましょう
  • テストを書こう,先人たちの知恵に感謝しよう

おしながき

やったこと

PyCon JP 2017の発表でやった、LWTSのうち、「得点期待値(Run Expectancy)*2」を以下の書籍を参考に算出コードをPythonで書きました(申し訳ないですがコードは非公開*3).

Analyzing Baseball Data with R, Second Edition (Chapman & Hall/CRC The R Series)

Analyzing Baseball Data with R, Second Edition (Chapman & Hall/CRC The R Series)

原著はタイトルの通り、Rで書かれている*4ので、

  • ひとまずRで写経する(JupyterでRカーネル動かして写経)
  • 途中計算の答え合わせをしながらPythonで書き直し、この時にpandasで実装
  • テスト(Pythonのunittest)を書いて動かし、ひたすらリファクタリング

というスタイルでやりました.

なお、対象データはメジャーリーグ1シーズン分の打撃スタッツ(公開データです*5)で、約19万レコード,100カラムくらいのCSVファイル(110MBちょい)というちょっと手ごわいデータです.

$ ls -lh events-2018.csv
-rw-r--r--@ 1 hoge fuga  113M 11 25 13:58 events-2018.csv

処理と出力の結果はこんな感じです.

$ python run_expectancy.py events-2018.csv
       RUNS_ROI
outs          0     1     2
runner
0_000      0.49  0.26  0.10
1_001      1.43  1.00  0.35
2_010      1.13  0.68  0.32
3_011      1.94  1.36  0.57
4_100      0.87  0.53  0.22
5_101      1.79  1.21  0.50
6_110      1.42  0.93  0.44
7_111      2.35  1.47  0.77

コードは見せられませんが、雰囲気(Interfaceと処理の役割)だけ伝えるとこのような感じです.

import csv

import pandas as pd


class RunExpectancy:

    def __init__(self):
        pass

    def calc_csv(self, filename: str) -> pd.DataFrame:
        # 何かしらの処理
        return self.calc_df(pd.read_csv(filename))

    def calc_df(self, df: pd.DataFrame) -> pd.DataFrame:
        """
        Calc Run Expectancy for Dataframe
        :param df: Pandas Dataframe(Retrosheet Events Data)
        :return: Pandas Dataframe
        """
        df['A'] = df['B'] + df['C']
        # ひたすら前処理と集計

        # 複数カラムにまたがる処理を愚直にforでやってるところ(イメージ)
        for i, row in df.iterrows():
            status = 0
            if row.D == 'chiba' or row.E == 'chiba':
                status = 33
            elif row.D == 'nishinomiya' or row.E == 'nishinomiya':
                status = 4

            df.at[i, 'NHK'] = status
        # ↑のようなforで回すやつが2箇所


        # いよいよ算出&出力
        return self._output(df)

    @classmethod
    def _output(cls, df: pd.DataFrame) -> pd.DataFrame:
        """
        Export Run Expectancy Data
        :param df: Pandas Dataframe(RUNS ROI Data)
        :return: Pandas Dataframe
        """
        # ひたすら整形するそして算出
        # ピボットしてRun Expectancyを出す
        return pd.pivot_table(df, index='runner', columns='outs')


if __name__ == '__main__':
    import sys

    run_ex = RunExpectancy()
    values = run_ex.calc_csv(sys.argv[1])
    print(values)

70秒を4秒に縮めた際にやったこと(ふたつ)

もういきなり結論書いちゃいますが、

  • df.iterrows(forでグリングリン回ってるところ)を戦力外通告してmapに置き換え
  • 計算に必要なカラムを定義、pd.read_csvのパラメータで「usecols」をカラムを指定(読み込むデータを限定)

これで一気に時間が縮まりました.

df.iterrowsを戦力外通告してmapを使う

pandasのDataframeに新しいSeries(カラム)を作りたい!でも複数のSeriesから計算しなくちゃ...!

っていう時に、人は(私は)どうしてもforで回すことを考えがちです.

def calc_df(self, df: pd.DataFrame) -> pd.DataFrame:

    # 中略
    # 複数カラムにまたがる処理を愚直にforでやってるところ(イメージ)
    for i, row in df.iterrows():
        status = 0
        if row.D == 'chiba' or row.E == 'chiba':
            status = 33
        elif row.D == 'nishinomiya' or row.E == 'nishinomiya':
            status = 4
        df.at[i, 'NHK'] = status

for文書いたら負けかなと思っている」という有名な格言?もあるとおり、19万レコードを全部forで舐め回しているこのコードは負けのコードです.*6

人のコードを写経してまず動かす!って時はいいのですが、たかだか100MBちょいのCSVの計算集計に70秒もかかるのはって思いはじめた段階で、真面目に考え、mapで処理を書き直しました.

mapで書き直す

上記の例をmap(Seriesの値から計算)するように書き換えるとこんな感じです.

def _nhk(self, status_text: str) -> int:
    # デリミタ(_)で分ける
    params = status_text.split('_')
    status = 0
    if params[0] == 'chiba' or params[1] == 'chiba':
        status = 33
    elif params[0] == 'nishinomiya' or params[1] == 'nishinomiya':
        status = 4
    return status

def calc_df(self, df: pd.DataFrame) -> pd.DataFrame:

    # 中略
    df['STATUS_TEXT'] = df['D'].astype(str) + '_' + df['E'].astype(str)   # 中間列を作ってデリミタでつなぐ
    df['NHK'] = df['STATUS_TEXT'].map(self._nhk)

STATUS_TEXTという名前で中間列を作り、これをmap関数内で分解(str split)して処理するようにしました.

applyはさほど速くない

なお、pandasにはDataframe(≒複数のSeries)を元に処理するapplyという関数もあり、上記のイケてないfor文コードをこういう書き方にもできます.

def _nhk2(self, row: pd.Series) -> int:
    status = 0
    if row.D == 'chiba' or row.E == 'chiba':
        status = 33
    elif row.D == 'nishinomiya' or row.E == 'nishinomiya':
        status = 4
    return status

def calc_df(self, df: pd.DataFrame) -> pd.DataFrame:

    # 中略
    df['NHK'] = df.apply(self._nhk2, axis=1)

コードの可読性・綺麗さ(かっこよさ)でいうと圧倒的にapplyを使ったほうがお得*7なのですが、残念ながらこのコードのパフォーマンスは、forを使うときよりだいぶ良かったのですが、mapよりダメな子でした.

なんでやろうな?と思い調べたらpandasでお馴染みsinhrksさん*8のブログに解説がありました.

sinhrks.hatenablog.com

pandas.DataFrame は列ごとに異なる型を持つことができる。DataFrame は内部的に 同じ型の列をまとめて np.ndarray として保持している。列ごとに連続したデータを持つことになるため、そもそも行に対するループには向かない。また、DataFrame.iterrows でのループの際には 異なる型を持つ列の値を Series として取り出すため、そのインスタンス化にも時間がかかる。

また 行ごと / 列ごとに 関数を適用するメソッドに DataFrame.apply があるが、このメソッドでは Python の関数を繰り返し呼び出すためのコストがかかる。apply は利便性を重視したメソッドのため、パフォーマンスを気にする場合は避けたほうがよい。

※「1. 行に対するループ / DataFrame.apply は 使わない」より引用

forで回すのはアレだよ!、for文は負けだよ!っていう件も含めて明確な答え、ありました.

for文を戦力外通告した結果(70s->20s)

最初に書いたコードはなんとforで回したところが二箇所、19万レコードのDataframeを二回も回すという恐ろしいことをしていました(反省).

33-4どころの負けじゃありません.*9

これらをひたすらリファクタリングし、もう一度計測した結果、

$ time run_expectancy.py events-2018.csv
       RUNS_ROI
outs          0     1     2
runner
0_000      0.49  0.26  0.10
1_001      1.43  1.00  0.35
2_010      1.13  0.68  0.32
3_011      1.94  1.36  0.57
4_100      0.87  0.53  0.22
5_101      1.79  1.21  0.50
6_110      1.42  0.93  0.44
7_111      2.35  1.47  0.77
python run_expectancy.py events-2018.csv  15.58s user 3.40s system 100% cpu 18.950 total

70秒が約20秒、7割ちかく処理時間をカットしました(震え).

そもそものデータを減らす

とはいえ20秒もまだかかり過ぎだな...と思い、データを見直した所、

  • CSVは100カラムちょいある
  • しかし、使ってるカラムは10個も無い
  • 必要なものだけ読めばよいのでは?(震え)

って事に気が付きました.

いつもは何も考えずに無邪気にread_csvしてDataframe作ってましたが、これを絞ることにしました.

カラム指定する(read_csv)

もう一度ソースコードと計算式を読み直し、必要なカラムのみ特定し、read_csvを書き直しました.

# 書き直す前
#    def calc_csv(self, filename: str) -> pd.DataFrame:
#        return self.calc_df(pd.read_csv(filename))

# 書き直したやつ
    COLUMNS = ('A', 'B', 'C', 'D', 'E') 
    def calc_csv(self, filename: str) -> pd.DataFrame:
        # 書き直した後
        return self.calc_df(pd.read_csv(filename, usecols=self.COLUMNS))

個人的にはread_sqlからやるときは明確に必要なカラムのみ指定(select文をちゃんと書けば出来る)して意識してやってたのですが、csvの時はあまり考えずにやってたので、「もしや!?」と思い調べてやってみました.

read_csvをいい感じにした結果(20s->4s)

参考にさせてもらったこちらのブログのベンチマークでも明確に結果が出ていたので期待してベンチをとりました.

starpentagon.net

$ time python run_expectancy.py events-2018.csv
       RUNS_ROI
outs          0     1     2
runner
0_000      0.49  0.26  0.10
1_001      1.43  1.00  0.35
2_010      1.13  0.68  0.32
3_011      1.94  1.36  0.57
4_100      0.87  0.53  0.22
5_101      1.79  1.21  0.50
6_110      1.42  0.93  0.44
7_111      2.35  1.47  0.77
python run_expectancy.py events-2018.csv  3.68s user 0.64s system 100% cpu 4.291 total

見事、処理時間が1/4近く短縮されました!

「うわ...私のpandas、遅すぎ...?」という懸念が見事に解消されました、めでたしめでたし.

なお、ここまでの高速化は調べながらリファクタリングとテストを繰り返して半日で達成しました.*10

高速化をちゃんとやる前に

テストを書きましょう!!!リファクタリングしましょう!!!データを把握しましょう!!!!

ホント、これに尽きます.

テストを書いてからリファクタリング

何故テストが重要か?という話はこちらの名著に譲るとして*11

テスト駆動Python

テスト駆動Python

この手のデータ分析のリファクタリングでありがちな失敗は

リファクタリングしてる内に、オリジナルのコードから正解がズレる(=コードを壊してしまう)

ことです.

手法やモデルが決まってるということは当然再現性あるはずなのに、リファクタリングの結果再現しなくなったらそれはバグです(やってることの意味がなくなる).

ある程度完成してprintやlogで書き出していい感じになったら、

  • インテグレーション(結合)レベルでいいのでテストを書く、ちゃんと書く
  • ややこしい処理や計算をしている関数は個別にユニット(単体)レベルで書く
  • 書いたテストを常に動かす仕組みを用意する(エディタの設定なりCIなり)

pytestとかじゃなくて、標準のunittestでも十分なクオリティを出せるので、早い段階で用意することをおすすめします.

import unittest

class TestRunExpectancy(unittest.TestCase):

    # テストデータはpy-retrosheetから別途ダウンロード

    def test_2016(self):
        """
        2016年データでのLWTS
        """
        run_ex = RunExpectancy()
        df = run_ex.calc_csv('./data/events-2016.csv')
        dict_run_ex = df.to_dict()

        # 0アウト
        dict_0_outs = dict_run_ex[('RUNS_ROI', '0')]
        self.assertEqual(dict_0_outs['0_000'], 0.5)     # ランナー無し

    def test_2017(self):
        # 省略

    def test_2018(self):
        # 省略

なお、個人的にはテスト駆動開発がしっくりこない*12為、必要と判断したとき以外はやってません(これは好みの問題).

必要なデータを認識する(でかいデータにビビらない)

統計モデルや計算手法をちゃんと確認して必要なデータだけに絞る.

この辺雑にやってついつい手を抜きがちですが、最初のコードを書いて動いた時点で吟味しても良かったのかな?と思っています.

最初の全体像がイマイチ不明でも、後ほどコードをgrepするとかで絞れると思う(今回はその方式でカラムを吸い出して決めました)ので、これは手を抜かずやっていきたい.

先人たちの知恵に感謝

mapやapplyの具体例などは定番のJupyter本を参考にしつつ.

PythonユーザのためのJupyter[実践]入門

PythonユーザのためのJupyter[実践]入門

今回はpandasのコントリビューターのsinhrksさんはじめ、有志のブログやドキュメントが大変参考になりました.

sinhrks.hatenablog.com

starpentagon.net

例を示した以外、私のこのエントリーでは新しいネタ・Tipsはほぼ無いわけですが、こういう知恵を少しでも残せる・継承できるようになれたらいいなあと改めて思いました.

以上、今年初の技術エントリーでした.

*1:もはやどっちだか見境つかない感あるが今回は間違いなく趣味

*2:LWTSはプレーを評価する方法の概念的な考えで、具体的な手法として得点期待値や得点価値があります.詳しくはウィキペディアもしくは私の過去発表を御覧ください(野球のエントリーではないのでここでは解説しません)

*3:趣味とはいえ、野球のコードを気軽にOSSにするのはちょっとですね(震え)なお、過去公開のコードやライブラリはそのままです&必要に応じてメンテをするお気持ちはあります.

*4:このRのやつに色々と苦労しましたがこれはどこかで書き残したい

*5:RETROSHEETという、公開データセットです.なお使い方には多少クセがあります(このブログのどこかに解説あったような) https://www.retrosheet.org/

*6:このブログは昨日個人的にやってたもくもく会で書き始めたのですが、ちょうど著者のはむかず氏からこのコメントが出たので引用させてもらいましたw

*7:この辺は明確すぎますね笑

*8:pandasで困ったらsinhrksさんですよねと、ホントいつも参考にしています

*9:NHK.

*10:これが2019年、私のプログラミング書き初めでした(仕事始めの前の日にリハビリでやった)

*11:元の本が素晴らしいのと、アジャイル・テスト駆動・Pythonのプロ、やっとむさん監訳で非常に安心と信頼ができる名著です

*12:テスト駆動開発、悪くはないんだけど、動くものがそこそこできてからテストを書き始める方がやりやすいと思っている

「世界一の野球エンジニア」を目指して - 2019年の目標と行動・スタンス

本題とは関係ありませんが、正月二日目は散歩して久々に旧図書館に行きました、あけましておめでとうございます!*1

f:id:shinyorke:20190102180733j:plain

早速ですが、今年、2019年の抱負は、

  • 「世界一の野球エンジニア」として、チームそして自分を次のステージに進ませる
  • 自分個人とチームの成功と幸せを両方取りに行く(二兎追って二兎得る)

以上となります!

...と言ってしまえばそれで終わりなのですが、これだと整理がつかなさ過ぎるので、

  • 2018年ふりかえり(前回のエントリー + 数字的なもの)
  • 2019年の目標・行動・スタンス(仕事と仕事以外)
  • 2019年の具体的な外部活動(決まってるモノだけ)

を整理したいと思います(つまり、抱負のエントリーです).

スターティングメンバー

2018年ふりかえり(とお礼)

前回のエントリーでほぼやりきりましたが、補足含めて.

1年間の行動とアウトプットについて

毎月ごとおよび外部アウトプットは前回のエントリーにありますのでそちらをご覧ください.

shinyorke.hatenablog.com

書き忘れた所としては、12月にRettyのイベント(Scrum Meetup)で「スクラム捨てたンゴ」って話をしました.*2

shinyorke.hatenablog.com

補足としては、アジャイル・コミュニティに関しては相変わらず「任意引退」状態なので、今年(2019)は特に目立った活動は予定していません.*3

定量的なふりかえり(主にこのブログ)

このブログの数字的なふりかえりです.

ひとまず言える数字だけ.

  • ユーザー数(年間):約20万 ※月間ユーザーは15,000〜20,000(直近4ヶ月)
  • ユーザー数およびPVは30〜40%増
  • 読者数は+100人以上で現在496人

ちなみに、アフィリエイトについても昨年より増えました(小声)

ひとえに皆様のご愛顧にささえられてここまで来ました.

誠にありがとうございました!!!(ジャンピング土下座)*4

なお、感謝の気持ちを込めて、とある区切りを迎える2019年はこのブログに関するイベントを開催する予定です(詳細は最後の方に).

2019年の目標・行動・スタンス

ここから2019年の話です.

昨日(1/2)に、

  • 2021年元旦に目指す姿(2年計画のゴール)
  • 今年(2019年)にあるべき姿(2020年元旦までの目標)

をリーンキャンバス*5などで言語化・可視化した後に、今年の目標を絞り込みました.*6

仕事

現職(ネクストベース)での本業と、本業以外の稼ぎ(副業や登壇、執筆など)ベースでの目標・行動・スタンスをまとめました.

野球エンジニアとしてのスキルマップ(わたしの話)

本業の方ですが、ベン図でスキルマップっぽくまとめました.

こちらの書籍にあった、データサイエンス版のスキルマップをパクってアレンジして作りました.*7

データサイエンティスト養成読本 ビジネス活用編 (Software Design plusシリーズ)

データサイエンティスト養成読本 ビジネス活用編 (Software Design plusシリーズ)

  • 作者: 高橋威知郎,矢部章一,奥村エルネスト純,樫田光,中山心太,伊藤徹郎,津田真樹,西田勘一郎,大成弘子,加藤エルテス聡志
  • 出版社/メーカー: 技術評論社
  • 発売日: 2018/10/30
  • メディア: 大型本
  • この商品を含むブログ (1件) を見る

色々試行錯誤して作った結果こんな感じになりました.

f:id:shinyorke:20190102221322p:plain
野球エンジニア・スキルマップ

これが全部独りで賄うのは到底無理*8(≒チームで成り立てばOK)なので、必要なモノ(ベン図で被ってる部分)に主なフォーカスを当てて今年の目標を決めました.

2019年に目指す姿(スキルマップ続き)

というわけで、特にフォーカスを当てたのはこちらとなります.

f:id:shinyorke:20190102221459p:plain
今年頑張りたいところ

今年、本職として頑張りたいポイントは、

  • データエンジニアリング(頑張るポイント①)
  • エンジニアリングとプロセスで「魅せる」(頑張るポイント②)
  • 野球エンジニア・チームを「創る」(野球CTOのアタリマエ)

この3つになりました.

データエンジニアリング(サイエンスとOps)

最初に断っておくと、OPSは野球の方(On base Plus Slugging)じゃなくて*9、「Operations(運用)」というエンジニア用語の方です.

今年は想定している&自分がメッチャ前のめりにやりたいミッションの性質が、

  • 事業ドメイン(=野球)に偏ったデータサイエンス
  • そんなデータサイエンスを実現するための解析・サービス構築
  • これらを継続的に運用するためのOps(Dev Ops, Data Ops)

だったりするので、これらをしっかりやりきって、野球界・エンジニア界そして自分にとって、後世に残るような価値とインパクトを残したい!と強く思っています.

この文脈では、

  • 昨年もかじってやったインフラの仕事をもっと頑張る.
  • データサイエンス、そろそろ機械学習にも突っ込む.
  • Opsをチームとして回せる仕組み作りをやる.

これらを今年一年でやれたらと思っています.

「魅せる」チカラ(フロントと可視化)

もちろん、データエンジニアリング・データサイエンスだけでは仕事は成立しなくて.

  • アスリートや現場の方々(ユーザーさん)が使えて
  • 得るもの・学ぶものという「価値」があって
  • これらがプレーや今後のキャリアに繋がり、よりスポーツが良い世界になる

為にはUX/UIといったフロントエンド、もっと広くいうと「魅せる」チカラが重要だと強く信じています.

目指す姿・やるべきこととしては、

  • 既存のフロントエンドを更に磨く(今もいいけどまだやれることはある).
  • AR/VRなど、やれる事を増やす(可能性・アプローチを広げる・増やす)
  • 現場のフィードバックを元にカイゼンを回すための透明化(カンバン等を用いた可視化・言語化)

のサイクルをより進めていければと思っています.

野球エンジニア・チームを「創る」

去年は2月から10月いっぱいまで、事実上1人チームでした*10が、11月からエンジニアが増え、今後も間違いなく増えます(採用頑張ってます).

スクラムを捨てた話でもちょっと触れましたが、

  • 去年は「ひとり」だったのでスクラムみたいなチーム前提のプラクティスは「捨てた」が
  • 今年(2019)は既にひとりじゃない、かつ人は間違いなく増える

という「ほぼ」約束された未来があるので、

  • エンジニアから提案型でやれることを増やしていく(例:めんどくさい業務の自動化、Slack Botなどで生産性を高める)
  • 場つくり・チーム作り(1on1、オフでのチーム作り*11
  • メンバー同士の「傾聴」「対話」を、「聞く 33-4 話す」の比率ぐらいで進めていく*12

といった所で、より良いチーム作りを進めていく所存です.

「フェーズによって役割が変わる」小さいチームのCTOだからこそ出来るミッションであり、自分にとっても素晴らしいチャレンジなので真摯に楽しんで行きたいと思います!

野球の仕事以外の目標

本職(野球)以外の目標・やりたい事を軽くいいます(と言いつつ、やりたい事を素直に述べていく).

技術顧問

強烈にやりたいです

今の仕事の可能性を広める意味でも、自分が持ってるモノを活かす意味でもガチでやっていきたいと思っています.

  • PythonなどでのWeb開発(フロント・バック両方)のご意見番・教育・サポート
  • データ基盤や分析を事業とつなげて活かす
  • アジャイル・スクラム・リーン等の導入サポート

純然たるエンジニアリングおよびその周辺ドメインの文脈でお困りの方、お声掛け頂けると嬉しいです(真顔).*13

英語

若干本職(野球)とも被りますが、海外での仕事の可能性や、今後のキャリアでも英語が必要になってくる感が増してきたのでちゃんと磨こうと思います.

何で学ぼう?DMM英会話とかですかね??

これぞ!って奴あったら教えてください :bow:

プライベート

具体的に何やるか,,,は省略.

健康

昨年比で+5kgちょい体重増えたので、戻していきたい.

ウォーキングに加えて運動量を増やす、食べる量を減らす.以上!!!

なお、体重は増えましたが昨年は望む仕事をしていたので病気らしい病気はしませんでした.

もしかすると風邪すら引かなかったかも...やはり環境って重要ですね.

Rettyで1,000投稿(あと193)

現在807投稿、去年の投稿数が350ちょいでした.

ので、昨年の半分ちょいのペースで行ける...ハズ(意訳・健康とダイエットと両立するはず).

独りになり過ぎない

独身・独り身リスクを取るつもりはありません!今の所.

つまり、察してください.*14

具体的な外部活動について

ここはちょっと真面目にやることを.

(一部を除き)具体的な予定は未定なので、スタンスめいたところがメインです.

登壇・執筆

昨年以上に、仕事と個人活動に打ち込む為、登壇・執筆はセーブしていきます!

正味な話オファーらしいオファーは無いのでセーブも何も無いのですが(真顔)

今の仕事・事業が人生で最もやりたい事なので当然ながらそっちに注力したいです.

とはいえ、

  • PyCon JP 2019およびBaseball Play Study(引退?知らない子ですよ?*15)は何かやりたい
  • 今の仕事や事業につながる面白い話があれば前のめりにやりたい

という感じでこの辺はちょいちょい変わると思います.

コミュニティ活動(運営・参加)

まず、主催している #rettypy は(参加者および、運営協力メンバーからソッポ向かれない限り)変わらずやります.

ちなみに次回(書き初め)は1/26です、抽選はまだ先なので気になる方は並んでください*16.

また、ここでの詳細は伏せますが、2〜3ヶ月に一度、クローズドな勉強会・もくもく会を #rettypy とは別にやるつもりです.*17

また、参加する方は例年通り、 #pyhack や #kwskrb 、 #bpstudy (野球じゃない方)および #mokupy には定期的に顔を出して行きます.

ブログ(Lean Baseball)

今年も引き続き、「技術」「野球」「キャリア」を中心にやりつづけます.

と、同時に昨年からnoteもはじめました.

note.mu

こっちのブログでは触れないネタ(趣味とか食とか諸々)で遊びたいと思っています、お時間ある時にぜひお邪魔してください :bow:*18

執筆ペースについて

自分としては、「月に一度」を基本ペースとしています、これをずっとキープしていきたいと思います.

月イチは特に理由はないのですが、ライフワークとして書き続けたい&前述の通り登壇・執筆はペース抑えるので、このブログは頑張っていきたいと思っています.

あと、ペースとは無関係ですが、最近このブログのエントリーのいち記事当たりの文字数が増えてばっかりなので、もうちょっとライトに書く努力をしたいと思っています.*19

ブログ開設5周年イベントをやる...つもり

最後になりますが、今年は

  • わたしが40歳(9/6が誕生日)
  • このブログ、「Lean Baseball」が5周年

という節目を迎えることになりました.

ちなみに最初のエントリーはこちらで、恐ろしいことに初回で大炎上しました(タイトルで察してほしい)

shinyorke.hatenablog.com

最初は燃えましたが、野球データ分析やPython、そして野球エンジニアへの転身というエントリーの数々のおかげで色んな方が見てくださり、ブログを通じて色々な体験ができ、私のライフワークにとって欠かせない存在になっています.

ので、ブログのネタを通じて何か楽しめる会を解説した7/20前後でやりたいと思っていますので、気になる方はぜひ来てもらえると幸いです.

会のスタイルは、私のプレゼン付きの懇親会(飲み会)でこちらのイベントのパクリとなる予定です.*20

atnd.org

※詳細は私のツイッター等で流します

最後になりましたが、本年もどうぞよろしくお願いいたします!

*1:小学生の頃から家を出た高校卒業までずっとお世話になってました、本が好きなので

*2:公開してから書き忘れたのに気がついた、すまん

*3:技量磨きの為にワークショップとかには参加したいなとは思いますが、カンファレンス・イベントで喋ったり、何かを執筆する予定は無いです&依頼があっても原則丁重にお断りさせてもらうつもりです.(もちろん中身による)

*4:野球エンジニアになったキッカケも弊社メンバーがブログを読んでいたこと、なのでホント感謝感謝

*5:こっちはかなり色々パーソナルなこと書いてるので申し訳ないけど非公開で :bow:

*6:いつの日からか、会社の目標面談とかすっごく苦手というか嫌いになったので正月のこの時期に自分で決めるようにしました.

*7:ベン図の構成は、リーンスタートアップでお馴染みの「Measure/Build/Lean」と、リクルートでお馴染みの「見立てる・仕立てる・動かす」をベースに書きました、多分雰囲気伝わると思うので説明はこんくらいで.

*8:個人としてはスーパーマン願望あれど、独りですべてを抱えても成功には繋がらないので.あくまで自分主体 + チームで成り立てばいいな!っていう発想です.

*9: OPS (野球) - Wikipedia

*10:厳密には春先からインターンが1人はいりましたが当然フルタイムではないので常に計算できる戦力は自分一人

*11:つまりイイゴハンです、前職の経験を愚直に活かす(真顔)

*12:なんでや在阪球団関係ないやろ(定型文)

*13:ただし、現職の野球や前職以前で絡んでた事業(飲食やHR、不動産など)は基本的にNGという事で :bow: 自分が在籍してた所に顧問として戻るのはOKですが(真顔)

*14:募集中です(何が)

*15:やきう民のテノヒラは360度まわる電動モーター製ですが何か?(真顔)

*16:抽選なので先着順ではありません、並んでいればチャンスはあります

*17:ちなみに初回は今月

*18:UK Rockのバンドに例えるなら、このブログはRADIOHEADやblurみたいなもので、noteの方はThom YorkのソロやGorillazみたいなモンです、察してください(趣味丸出しな説明)

*19:Python本エントリーで10,000超え、このエントリーも7,000文字近くあるので流石にね

*20:5年前にあった yumulog | 社会人博士の日記 の10周年パーティーで、これに参加してブログをはてなにした記憶があります、つまり繋がってます.