For Your ISHIO Blog

データ分析や機械学習やスクラムや組織とか、色々つぶやくブログです。

DataFrameのメモリサイズを節約する

新年あけましておめでとうございます。2019年最初のブログになります。本投稿では、DataFrameを扱う際のメモリサイズの節約について書きたいと思います。

私はGCP上のVMPythonの開発環境としており、Kaggleのデータセット等を利用して学習しています。Pandasを利用してDataFrameを扱うわけですが、以下のようなことに遭遇します。

  • 残念ながらお金がないので、メモリを大量に積んだVM環境を常備できない
  • Daskよりも、Pandasの方がやっぱり使い慣れている
  • kaggleのデータセットがでかすぎてメモリーエラーになる

少しでもメモリを節約するための方法をツラツラメモしています。結論としては以下です。

  1. データ読み込み時に型を指定しないと、一番大きなメモリサイズが確保されるので気を付ける
  2. 新しいカラム作ると、一番大きなメモリサイズの型が確保されるので気を付ける
  3. いらなくなったオブジェクトはお掃除

より良いテクニックあればコメントお待ちしています。

目次

利用したデータセット

KaggleのMicrosoft Malware Predictionのデータセットを利用します。8,921,483レコード、カラム数は83です。

Microsoft Malware Prediction | Kaggle

$ import pandas as pd
$ train = pd.read_csv('./data/train.csv')
$ print(train.shape) 
(8921483, 83)

メモリサイズの確認方法

定義した変数のメモリサイズ確認には、sys.getsizeof()を利用します。

$ import sys
$ sys.getsizeof(train)
20945097222

また、DataFrameの各カラムで利用されるメモリサイズの確認には、memory_usage()メソッドを利用します。

同時にカラム名とdtypeを確認すると、デフォルトではobjectint64float64になっており、各カラムで71,371,864バイトのメモリが必要です。これらは全て1レコード当たり8バイト必要となるため、各カラムは8バイト × 8,921,483レコード = 71,371,864となる計算です。

$ for col, dtype, memory in zip(train.columns, train.dtypes, train.memory_usage(index=False)): 
       print(col, dtype, memory) 
                                                                                                          
MachineIdentifier object 71371864
ProductName object 71371864
EngineVersion object 71371864
AppVersion object 71371864
AvSigVersion object 71371864
IsBeta int64 71371864
RtpStateBitfield float64 71371864
IsSxsPassiveMode int64 71371864
DefaultBrowsersIdentifier float64 71371864
AVProductStatesIdentifier float64 71371864
AVProductsInstalled float64 71371864
AVProductsEnabled float64 71371864
...

データ読み込み時にdtypeを指定する

データを読み込み、DataFrameを作成する際に、オプションとしてdtypeを指定することができます。仮に指定しない場合には、上述の通りデフォルトの型(int64、float64、object)が指定されます。

思想としては、どのようなデータでも対応できるように、整数・小数型のうち最も大きなtypeが確保されるようです。このため、実データで必要とされる以上に、メモリを確保してしまうことになります。

各typeのサイズと値の範囲は以下の通りです。dtypeを指定することによるメモリサイズの節約は、本質的には必要なメモリサイズの型を指定して、必要な分だけ利用しましょう、ということです。

type サイズ 値の範囲
int8 1バイト -128 to 127
int16 2バイト -32768 to 32767
int32 4バイト -2147483648 to 2147483647
int64 8バイト -9223372036854775808 to 9223372036854775807

私の場合は、.pyでdtypeを辞書型で定義し、それをread_csv時に読み込んでいます。これにより、もともとのインポートデータは20,945,097,222から2,477,814,730に節約出来ました。8~9分の1に節約できています

$ from lib.dtype import dtypes

$ dtypes
{'AVProductStatesIdentifier': 'float32',
 'AVProductsEnabled': 'float16',
 'AVProductsInstalled': 'float16',
 'AppVersion': 'category',
...
 'UacLuaenable': 'float32',
 'Wdft_IsGamer': 'float16',
 'Wdft_RegionIdentifier': 'float16'}

$ train = pd.read_csv('./data/train.csv', dtype=dtypes)

$ sys.getsizeof(train)
2477814730

新たな特徴量生成時のデータ型確認

object型の変数をモデリングに利用するために、pandasのfactorize()メソッドを利用してカテゴリカル変数に変換することがあります。これにより、0から始まる整数型の値に変換でき、モデル構築時に利用しやすくなります。

データの読み込み時だけであなく、新たな特徴量を生成する場合にもデータ型には注意が必要です。pd.factorize()も、デフォルトではint64型になるようですので、必要以上のメモリを確保しがちになるかと思います。pd.factorize()に限らず、新しい整数型、小数型のカラムは全てint64, float64になるようです

試しに、サンプルデータのEngineVersionを参考に確認してみます。

EngineVersionは70個のユニークな値を持つobjectです。カテゴリカル変数への変換後のカラム「factorized_EV」のデータ型はint64となっており、変換前と同様のメモリサイズが必要となっています。

実際に必要な値のrangeは0~69であるため、int8に変更してあげます。これにより、当該カラムは約8分の1に節約出来ます。

$ train.EngineVersion.head()                                                                                                 
0    1.1.15100.1
1    1.1.14600.4
2    1.1.15100.1
3    1.1.15100.1
4    1.1.15100.1
Name: EngineVersion, dtype: object

$ len(set(train.EngineVersion))                                                                                              
70

$ train.EngineVersion.memory_usage()                                                                                         
71371944

$ train["factorized_EV"], _ = pd.factorize(train.EngineVersion) 
$ train["factorized_EV"].dtypes
dtype('int64')

$ train["factorized_EV"].memory_usage()                                                                                      
71371944

$ set(train["factorized_EV"])                                                                                                
{0,
 1,
 2,
 3,
 4,
...
 67,
 68,
 69}

$ train["factorized_EV"] = train["factorized_EV"].astype('int8')
$ train["factorized_EV"].memory_usage() 
8921563

gc.collect()で不要なデータを回収する

これは、多くの方がすでに実践されているかと思います。不要なデータはGCに回収させ、使い終わったデータは解放してメモリを節約します。

$ import gc

$ del train
$ gc.collect()  
1843

まとめ

会社の環境は贅沢なのであまり気にしていなかったが、自分の開発環境では少し気を遣うことにした。のメモ。

【書籍メモ】Eelastic leadership - 自己組織化チームの育て方

自分がとても勉強になった書籍の1つに、『Eelastic leadership - 自己組織化チームの育て方』があります。個人的にO'Reilly出版の中で最も取っ付きやすい本と思っており、多くの方に読んでほしい内容です。

この書籍では、(ソフトウェア開発を中心に)チームのフェーズを3つに分けて考えており、各フェーズによってリーダーシップのとり方を柔軟に変えるべきと著者の経験から述べています。本ブログでは、各フェーズにおける具体的なテクニックについては書籍を読んで頂くこととし、その全体的な考えた方をシェアします。

www.oreilly.co.jp

なおこの本は、以前にTwitter上で自身が何度でも読み直したい本の1つとして紹介させていただきました。

今現在だと、上記書籍に加えて、エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリングデータサイエンティスト養成読本 ビジネス活用編の2つが新たに加わりました。

この書籍が良いと考える理由

私はスポーツも好きなので、ベテランサッカー選手や野球選手が口数少なくとも行動でチームに刺激を与える。または、ベンチメンバーに入れなくても裏方でチームをサポートし鼓舞する、という話はよく聞きます。

最も多く語られるリーダーシップは、リーダー自身の性格やポジションに起因するリーダーシップであり、当然、リーダーシップ像に最も影響を与える要素かと考えています。

一方で、チームは安定している時も炎上しているときも在ります。組織の中でのリーダーの振る舞い方はStaticなものではなく、チームの状態によってリーダーの振る舞い方って変わるよねというのが、自身の経験と照らし合わせたときに最もしっくりくる考えでした。

本書籍はソフトウェア開発というフィールドには立っていますが、より柔軟性をもったリーダーシップを持つ考え方として、チームの状態に合わせて、リーダーの振る舞い方を柔軟に変えていこう、という立ち位置にいる書籍であり、ある意味、チームを良い状態にするために自身の振る舞いを柔軟に演じ変えるという考え方に立っています。

私自身が読了したリーダーシップ関連の書籍量が少ないので申し訳ないのですが、体系的に柔軟なリーダーシップ論について語っている書籍として、非常に納得感があるものでした。

チームのリーダーの役割

本書籍では、チームのリーダーの役割は、優れた優秀な人材が育つのを助けることであると定義しています。つまりチームメンバーの成長を促進することを指針とし、スキルを身に付けるために新しい事へと挑戦させなくてはいけません。

これは、リーダー自身が問題解決を行うことをやめなければならないということであり、チームの問題をリーダーがすべて解決しているようであれば、ボトルネックはリーダー自身であるとしています。理由はもちろん、チームで新しいことを学ぶのがリーダーだけになってしまいますし、リーダーが不在になった途端に、チームの活動は停止します。

ただし、チームに新しいことを学ばせることが常に良いとは限らない。時にチャレンジは理にかなっていない、というのが著者が論じている内容です。

3つのチームフェーズ

本書籍では、下記図の3つのフェーズにチームを分割し、どのリーダーシップが必要かを定義します。

f:id:ishitonton:20181224153052p:plain
チームの3つのフェーズとリーダーの役割

チームのフェーズ

  • 学習モード
  • サバイバルモード
  • 自己組織化モード

リーダーシップのとり方

サバイバルモード

このモードは、チームに学習する時間が十分にない状態であり、この状態をサバイバルモードと定義しています。リーダーの目標はチームが成長するように指導することです。これを達成するためには学ぶ時間を作る必要があります。

このフェーズでの戦略は、ゆとり時間を作るために、指揮統制型のリーダーシップを発揮し、一刻も早くサバイバルフェーズからチームが抜け出すことです。

指揮統制型リーダー下では、メンバーは新しい方法を学んだり責任感を持ったり、ルールを逸脱してチャレンジしたりする余地はほとんどありません。チームは、火消しに追われている状態であり、現状に対処するための必要スキルを学ぶ時間が十分に持てません。この場合には、チームリーダーがチームに道筋を直接示し、一刻も早くこのフェーズから抜け出すことを目指します。

学習モード

十分なゆとり時間があり、その時間を使って学習や検証を行っている場合、チームは学習モードにいると言えます。ここでのリーダーの目標は、自分たちの問題を自力で解決できるように教え、挑戦させることによってチームを自己組織化チームへ育てることです。

このフェーズでは、リーダーはコーチ型のリーダーシップを発揮します、チームに意思決定の仕方を教え、仮に学ぶべき教訓がある限りには、チームが誤った決定を下すことも許容します。

ゆとり時間を利用して、新しいスキルを獲得したり、技術的負債を取り除くことを経験のないメンバーと一緒に取組むのがよいでしょう。誤った決定により、火消しが必要になれば、場合によっては柔軟に「指揮統制型」のリーダーに切り替えます。

自己組織化モード

このモードでは、自身がノートPCの電源を切って数日間仕事を放置できる状態であれば、自己組織化フェーズであると言っています。すなわち、チームがリーダーの助けなしに自分たちの問題を解決できるしていける優れた状態であります。

このモードでは、リーダーはファシリテーターとなりその状態を維持することと、現状を処理するチームの能力に注意を払います。コーチがメンバーを立ち止まらせて何かを学ばせるのに対して、ファシリテーターは現状の環境や条件、目的や制約といったものが、チームに適した状態になっているか気を配ります。

ファシリテーターはチームの問題を解決しないが、代わりにチームが自立的に問題解決してくれると信頼します。

チームがフェーズ間を移動するとき

チームが今どのようなリーダーシップを必要とするフェーズかを認識することが非常に重要です。そのために、「チームの問題とその問題解決に必要な知識とスキル」、「ゆとり時間の量」を適切に把握する必要があります。

まとめ

自身のリーダーシップのスタイルが、チームのニーズから外れていると認識できないようなら、リーダー失格である。という書籍内の言葉を、私自身肝に銘じておきます。

書ききれたいないことはたくさんあるので、ぜひ読んでみてください。

データアナリストがスクラムチームにアサインされてよかったこと

目次

自社のアドベントカレンダー18日目を担当させていただきます。

本記事では、ビジネスサイドで業務を遂行していたデータアナリストが、エンジニアで構成されるスクラムのチームにアサイン(派遣)された体験記を書かせていただきます。なお、私の経験は、弊社を代表する業務経験ではありません。

本記事で目指すもの

本記事では、例えば以下のようなことを日々考えている方のお役に立てればよいなと思います。

f:id:ishitonton:20181218173624p:plain

  • データアナリストの「エンジニアリング力*1」を育てたい、高めたい
  • データ分析の分析プロセスをいい感じに管理したい
  • データ分析組織のアナリストを事業部やプロジェクトに派遣したい
  • スクラムを取り入れたチーム運営を行いたい

現在、様々な形でデータアナリスト、データサイエンティストの皆様は活躍されていると思いますが、そのデータ分析チームやデータアナリストの仕事の例として、参考になればと思います。

また、これをキッカケに皆さんの会社がどのような体制でデータアナリスト業務に従事しているか、情報共有させていただけると幸いです。

まずは、スクラムについて少し話をさせてください。

スクラムは「チームで働くための問題解決のフレームワーク

私はエンジニアとともに、スクラムフレームワークで一緒に仕事を進めてまいりました。

スクラムを一言でいうと、メンバー各人の自主性を尊重しながら、計画と振り返りによりチームを成長させていくフレームワークです。

スクラムが前提とする考え方に経験主義があります。経験主義とは、未来を予見することなく、実際に経験を積み重ねることで知識を獲得していこうとする考え方です。これを漸進的に繰り返すことで、予測可能性を高め、リスクの低減を目指すのがスクラムです。

未来は不確実に富んでおり、起こりうる全てを予測し計画を立てることは難しいです。1つの大きなサイクルを回すのではなく、小さなPDCAを回すことで、チームで学習しながら、変化に柔軟に対応しながら、目標に向かっていくのがスクラムの考え方です。

スクラムの決まり事と業務の進め方

スクラムでは、短い一定の期間に区切って計画振り返りを繰り返し、より良い成果物を作っていきます。そのためにいくつかのイベント役割成果物が決まりごととして用意されています。逆に決まっているのはそれくらいです。

f:id:ishitonton:20181216182232p:plain
https://www.ogis-ri.co.jp/pickup/agile/agilescrum01.html

区切られた短い期間をスプリントと呼びます。1つのスプリントはだいたい2〜4週間です。そして以下を繰り返します。

1. スプリント開始時:スプリント計画

スプリント計画では、例えば以下を決めていきます。

  • タスクの見積りと優先度付け
  • 次のスプリントでチームで対応するタスクの決定(スプリントバックログ

f:id:ishitonton:20181218164810p:plain

2. スプリント期間中:デイリースクラム

スプリント期間中は、スプリントバックログのタスクを、チームメンバー全員で対応していきます。

スプリント期間中はデイリースクラムと呼ばれるMTGを15分ほど毎朝行います。デイリースクラムでは下記を共有することで、チームの透明性を図ります。

  • 昨日対応したこと
  • 今日対応すること
  • 障害となっていること

また、スピーディーかつコンパクトな運営を心がけるために、スタンドアップミーティングを行っています。

3. スプリント終了後:振り返り

スプリント期間後、チームのメンバー全員で振り返りを行い、次のスプリントへの知識として活かします。これを繰り返していきます。

利用していたITツール

スクラムを円滑に運営するために、ITのツールを利用しました。

  • Gitlab
  • Slack

Gitlabのissue機能を利用し、各タスクを定義しています。各issueの中に、タスクのプロセスのメモやメンバ間のコミュニケーションを行います。 また、かんばんボード機能を利用し、スプリントバックログの進捗を管理します。

f:id:ishitonton:20181217195731p:plain

かんばんのレーンは、下記を設定しています。

  • ToDo(=スプリントバックログ
  • Doing(=対応中)
  • Done(=完了)

前置きが長くなりましたが、まずは私が取り組んでいるスクラムの概要でした。 より詳細については下記記事を参考にしてください。私自身が愛読させていただいた書籍になります。

チームメンバー構成と自身への期待

私が所属するチームは、開発エンジニア(4名)、システム維持管理(2名)、データアナリスト(私)の7名前後で構成されます。

私自身はプロジェクト発足後1年以上経ってから、チームに無かったデータ分析の要素を取り入れるためにアサインされました。例えば、期待されていた内容は、下記のとおりです。

  • 既存システムに機械学習の仕組みを導入し、業務を効率化
  • 蓄積データを分析し、インテリジェンスを生成(レポート書く)

私のスキルにかかわらず、データ分析に関わることは大体期待されていた感じはします。データアナリストとデータサイエンティストと機械学習エンジニアの要素が少しずつ必要な感じでした。


では、実際にデータアナリストの立場でスクラムチームで働き、何が良かったか、書いていきます。

反復的なデータ分析プロセスを管理可能

データ分析のプロセスには、反復的な試行プロセスが存在します。特にこのフェーズにおいては、スクラムフレームワークとの相性が良いと考えています。

f:id:ishitonton:20181218171713p:plain

例えばモデリングや特徴量エンジニアリングにおいて、様々なアイデアが浮かんできて全てを試してみたくなると思います。これらのアイデアは適切に管理しないと無限に時間を浪費する一方、価値を生み出さない結果となります。

スクラムフレームワークを活用することで、各アイデア優先度稼働見込みをチームで決めることができます。チームにとってインパクトが低いアイデアは、優先度が高くなることはありません。また、Gitlabのかんばんボードを利用して、適切に進捗管理ができます。

完了定義と見積りをつける癖がつく

EDA(Exploratory Data Analysis)という言葉に代表されるように、データ分析には探索的にデータ分析を行うプロセスが存在します。データの理解にはEDAは必須です。しかし、このEDAも適切にゴール設定を行わないと、むやみに時間を浪費する結果を生むことがあります。

スクラムでは、スプリント計画時に各タスクに対して以下をチームで考えます。

f:id:ishitonton:20181218173028p:plain

  • 完了定義:何をもってこのタスクを完了とするか。サブタスクの洗い出し
  • 見積:完了定義をもとに、どれくらいコストがかかりそうか

これにより、EDAにおいてもゴール設定をしっかりした上でタスクを遂行でき、むやみやたらに探索し続けることを防ぎます。「意識の問題」といわれるかもしれませんが、しっかりとフレームワーク化されていることで、仕事の進め方としても、思考が整理され予実乖離も少なくなります。

個人活動に陥りがちな分析業務をオープン化

データ分析業務のプロセスにおいて、データ理解やビジネス業務を理解するフェーズにおいては、当然関係者とのコミュニケーションが発生します。一方で、EDAモデリング等のフェーズにおいては、時に個人活動に陥り、自分の世界に閉じこもることも少なくないのではないでしょうか。

個人でゾーン状態に入り集中することも大切ですが、適切なタイミングでチーム内に棚卸を行い、方向性等の意思統一を行うことも重要です。

スクラムでは、デイリースクラム(朝MTG)の中で簡潔にチームにタスクの進行状況を説明します。また、うやむやなことはスクラムマスターという役割が、チームに問いかけを行い、チームでの理解の深化を促し、業務の透明性を担保します。

エンジニアリング力の向上

これまでどちらかというとビジネスサイドで職務をこなしてきたために、エンジニアとは関与が多くありませんでした。初めて同じチームで業務を行うことで、自分だけでは成しえなかった小さな成功体験を積み重ねることができ、それが自分の血となり肉となりました。

データサイエンティスト協会では、「ビジネス力」「データサイエンス力」「データエンジニリング力」をスキルセットとして定義していますが、この「データエンジニアリング力」とだいたい同義と考えていただければと思います。

f:id:ishitonton:20181218190849p:plain
https://www.datascientist.or.jp/common/docs/skillcheck.pdf

アサイン当初、プログラミング言語Rしかコーディングできなかったのですが、チームの開発言語はPythonでした(じゃあ、なんでアサインされたんだよという話は、割愛)。

早期に機械学習システムの構築が求められた中で、私たちのチームは以下の方法を取りました。

  1. 機械学習アルゴリズムの部分はRで私が書く
  2. その他の部分は、Pythonで他のエンジニアが書く
  3. PypeRというPython上からRを呼び出すパッケージを利用し、RのコードをPythonで呼び出す

自分の強みを生かしつつも、エンジニアの全力サポートの恩恵を受け、チームの中で機能横断的にタスクを遂行することができました。自身も徐々にPythonを学び、スクラムイテレーションの中で少しずつRのコードをなくすようにリファクタリングしていくことができました。

なお、我々のチームでは、ペアプログラミングを行い,、機械学習システムのコードについてエンジニアと対話を行いながらリファクタリングをする機会がありました。

ペアプログラミングは、想像以上にコストが高く、精神も消費する取組みですが、個人の成長によりチームの機能横断性を高める手段となりました。

「データサイエンティストのコードは汚くてそのままデプロイできない」的な話はよくあると思います。私自身もそうでした(今でもそうかも。。。)。データアナリストとしての活躍の場を広げる手段は様々ですが、ビジネス寄りのポジションにいた私が、エンジニアとともに業務を行うことでエンジニアリングスキルを身に付け、機械学習エンジニアのスキルセットへと活躍の場を広げることができました。

メンタルモデルの拡大

当然個人差はありますが、職種が異なるだけでも、働き方や仕事に対する姿勢、文化は大きく異なることを知りました。スクラムチームでは様々な専門性をもつメンバーたちが、機能横断的に1つの方向に向かって取組みます。

スクラムチームへのアサインは、自身のメンタルモデルを大きく拡大することができたと感じています。個々人(特に職種)の文化や価値観を知ることで、コミュニケーションの衝突はなくなり、相手をリスペクトし自身も謙虚に働くことに繋がります。

いくつか例を書いておきます。

以前の職場ではエンジニアが周りにいなかったために、様々な業務に対する自動化の意識が低かったように感じます。これは、自動化したくないわけではなく、実現できること(可能性がある)ことを知らないだけでした。 エンジニアとともに仕事をすると、自動化再現性に対する意識が非常に高いと感じました。様々な業務のプロセスはGitlabで履歴が残っていますし、コードも当然バージョン管理がされています。

また、私たちのチームでは、シーーンと静まり返っている時間帯があります。ビジネスサイドの業務ではあまりないのではないでしょうか。そのような時間帯は、ゾーンに入っているエンジニアが多いので、直接話しかけずSlackでメッセージを飛ばしたりします。この経験もビジネス側ではありませんでした。

エンジニア側から「ビジネス側は××」。ビジネス側から「エンジニアは××」。正直、それぞれがお互いの立場や思考を理解せずに悪口を言う場面を多々目撃してきました。自身が両方の経験を積むことで、これらの議論の本質を見極め、コミュニケーションのきっかけを作れたら良いなと感じます。

また、データアナリストにとって需要なのは、ビジネスに興味を持ち、理解を深め、ビジネス成果までコミットすることです。立場が違う人間の思考を理解しようと努めることは、データアナリストにとって重要な要素になると思いますので、様々な価値観や文化を受け入れられる人間性を持てるように精進することが必要ではないでしょうか。

スクラムで働くと、とにかく仕事が楽しくなった

スクラムフレームワークで働くことで、とにかく仕事が楽しくなります。理由は2つに絞られます。

  • 創造性の発揮
  • PULL型の仕事の進め方

1点目として、スクラムでは創造性を発揮できるフレームワークです。 ウォーターフォールの場合、プロジェクト開始以降に発生するアイデアは全て廃棄されます。市場の変化に対応できずや自身の新たなアイデアは採用することはできません。一方で、スクラムではそれが歓迎され、自身の創造性を最大限に発揮でき、徐々に仕事が楽しくなります。

2点目として、スクラムではスプリント期間中のチームのタスクは、基本的には各メンバが自主的に対応することを宣言します。このPULL型の業務の進め方は自身のチャレンジ精神を最大限発揮できます。チャレンジした結果チームが前進することで、自己効力感が高まり、またチャレンジしたくなります

そうすると、だんだん、データ分析以外の業務も自ら率先してこなし始めるようになります。それが今度は業務の幅やエンジニアリングスキルの向上に繋がりました。

正直葛藤もある

業務の幅が広がった結果、データアナリストだった私は、スクラムマスターも兼任するようになりました。

スクラムマスターとは、スクラムで定義される役割の1つです。この役割は、スクラムプロセスに対して責任を持ち、チーム全体が自律的に協調できるように、場作りをするファシリテーター的な役割です。(詳しくは、上述の参考書をご覧ください。)

スクラムマスターは、チームの外部から訪れる障害に対して、率先して対応します。極端な話、忙しいチームの飲み会の幹事もします。

業務の幅が広がった反面、データ分析の業務以外の比率が増え、本来の自信の専門性を十二分に発揮できないもどかしさも、最近では正直感じています。ここらへんは、チームの段階や自身のキャリアの考え方によるかと思います。

今後自身はどうしたいか

スクラムアジャイル開発との混同から、開発手法の1つと考えられがちですが、実際には問題解決のフレームワークであり開発現場以外にも適用できます。そしてスクラムは、ただの枠組みに過ぎないので、この枠組みをもとに自分たちの組織に合ったフレームへと自律的に変容させていくことができます。

今後、スクラムでの経験をもとに、自己組織化を目指すデータ分析組織で、自律的に創造性と情熱を持って働くが私のテーマです。

まとめ

年末のこのタイミングで、自分のこれまでの経験を棚卸する良い機会となりました。ありがとうございます。心身ともにスーパーなエンジニアたちに出会えたことは、自分の社会人生活の大きな財産であります。

簡単ですが、以上です。

*1:ここでのエンジニアリング力とは、データサイエンティスト協会が定義するスキルセットに準拠します。

データアナリストの非技術的スキル「知的好奇心」を発見する

AIやデータサイエンス、アナリティクスの分野をカバーするブログメディアにKDnuggetsがありますが、先日2018年に最も人気だったブログを公開してます。

Top Stories of 2018: 9 Must-have skills you need to become a Data Scientist, updated; Python eats away at R: Top Software for Analytics, Data Science, Machine Learning

その中でも最も読まれたのが、データサイエンティストになるための必要なスキルに関する記事です。この種に関する記事が多くあり、既に読み飽きた感もありますが。

9 Must-have skills you need to become a Data Scientist, updated

その中では、「技術的スキル」と「非技術的スキル」について書かれていますが、今回は後者にフォーカスします。非技術的なスキルとしては、以下4つについて記されています。全部明らかに重要なのですが、本記事ではデータアナリスト&サイエンティストの知的好奇心について考えます。

  1. 知的好奇心
  2. ビジネスの洞察力
  3. コミュニケーションスキル
  4. チームワーク

なぜ知的好奇心が必要か

好奇心は、より多くの知識を習得したいという欲求と定義できます。では、なぜこの好奇心が必要になるのかというと大きく2つの理由があると考えます。

  1. データやビジネス、人に対する理解
  2. 分野の進化に対する追従

データアナリスト/データサイエンティストの業務を進めるためには、対象となるビジネスを深く理解し、データを深く理解する必要があります。またそこで働く人を知り、業務を理解し、ビジネス成果までコミットをして業務を推進することが求められます。これには知的好奇心が非常に重要です。自分にとって未知な部分を開拓し、データに関する質問を含め、理解を深める能力が求められるはずです。

また、(IT分野全てがそうですが)、この分野における技術の進化スピードは非常に速いのはご存知の通りです。これらに追従し続けるには、もはや一過性のやる気ではなく、知的好奇心から溢れ出るモチベーションなのではないかと考えます。私自身もTwitterを歩いていると膨大な情報量に圧倒されることがありますが、それを全て理解する方法を探さなければいけません。(全く追いつけておりません)

なお、ビジネス成果へのコミットなどに関する考え方には、以前読んだデータサイエンティスト養成読本に素敵な内容がたくさん記述されています。こちらを参照ください。

ishitonton.hatenablog.com

知的好奇心が高い人を発見しよう

自身がデータ組織の責任者の立場にいる場合、当然優秀な人材や成長する人材を確保したいと考えるはずです。優秀とは一括りで語れないものの、ここでは知的好奇心という観点から、自組織へのjoinしてほしい人を採用する方法について考えます。でも、知的好奇心っていわゆる無形資産なので、判断が難しかったりします。

ここでは、Frank Lo氏の下記ブログの内容をシェアします。 www.burtchworks.com

まず、Frank Lo氏もデータサイエンスの精神は発見と述べており、すなわち「発見≒知的好奇心」だと考えます。そして、自身のチームを募集するとき、質問に対する回答を観察するだけでなく、彼ら自身が質問をしたい人を探すということが書かれています。これが一種の知的好奇心のシグナルということです。例えばこんな人でしょうか。

  • 面談で「最後に質問ありますか。」みたいな質問に対して、何個も質問したくなる衝動に駆られる人
  • セミナー後に登壇者に対して、積極的に質問をしにいきたくなっちゃう人

また、多くの候補者の中から以下の質問を投げかけるのも、判断材料になるとのこと。

自身が学校や職場外で進めているデータサイエンスプロジェクトやリサーチについて教えてください

個人的には、決してデータサイエンスに関わる取組みに絞った質問にする必要はないと考えますが、私の身の回りでいうと、下記のような取り組みでしょうか。

  • KaggleやSIGNATEやったり
  • プロボノに参加したり
  • ブログ書いたり
  • LT登壇したり

そういった積み重ねが1つのシグナルになるのかもしれません。これらは学歴では測れない別ベクトルな要素なのかなと考えます。

簡単ですが、以上です。

textlintを利用した自動チェックで、ブログ原稿の校正をサポートする。

ブログを開始して2カ月が経過しました。お酒飲みながら書いたりしていると誤字脱字が多いです。そこで、textlintというオープンソースを利用して、ブログ原稿の校正をするプロセスを挟むことにします。

目次

思い至った経緯

先日Twitter上で、u++さんから下記コメントをいただきました。

内容云々以前の、最低限の品質を担保するために、せめて誤字脱字をチェックするようにしたいと思ったのが経緯です。

textlint

textlintは、JavaScriptで書かれたテキストをチェックするオープンソースのユーティリティです。自然言語は、言語や文脈などによって書き方の正解が変わってきますが、それらをプラグインのアプローチにより解決しています。プラグインで設定した様々なルールをもとに、文章の校正をサポート可能です。

textlint.github.io

textlintのメリット

インストールを行う前に、textlintを利用することのメリットについて考えます。

  1. 人間の負荷軽減
    • 原稿のチェックは、人間が行うには非常に負荷が高い作業。コンピュータがその作業の一部を補うことで、人間の負荷を軽減する
    • 人間の能力には限界があるため、見落としをすることがある。この見落としを抑制できる
  2. ばらつきの極小化
    • 複数人で原稿をチェックする場合、人によってばらつきが必ず生じます。そのばらつきの極小化に繋がる
  3. 一貫性の担保
    • チェックする人が入れ替わった場合でも、ルールは変わらないので、一貫性のある品質を維持できる

textlintはMarkdown形式のテキストにも対応していることが、非常にメリットが大きいです。

インストールしてみる

今回はブログ記事の校正用のため、手軽に利用する手段を検討しました。textlintの開発者本人が作成したwindowsMacで利用可能なアプリケーションがあり、それを採用しています。なお、ソースコードGithubに公開されているため、CIに組み込むことなども可能です。

インストール方法は下記を参照してください。 textlintのElectronアプリを作った | Web Scratch

インストール後、デスクトップにショートカットが作成されていましたので、アプリケーションを起動します。下記のような画面が起動したらインストールは完了しています。

f:id:ishitonton:20181202130850p:plain
textlint.app

画面中心部の「Edit with textlint」には、実際にチェックしたいテキストを入力します。そのチェックの結果は右側に表示されます。

また、チェック項目は、.textlintrcというファイルで設定する必要があり、画面左側の「Setting」より編集できるようになっています。

自分流の設定を行う。

.textlintrcを編集して、自分流の設定をします。技術書用のプリセットpreset-ja-technical-writingの中から、自分で必要なルールを採用しました。採用したルールは下記になります。

  • 冗長な表現をチェックする
  • 読点は1文中に2つまでとする
  • 連続できる最大の漢字長は6文字までとする
  • 本文は「ですます調」、箇条書きは「である調」とする
  • 文末の句点記号として「。」を使う
  • 二重否定は使用しない
  • ら抜き言葉を使用しない
  • 逆接の接続助詞「が」を連続して使用しない
  • 同じ接続詞を連続して使用しない
  • 同じ助詞を連続して使用しない
  • 同一の単語が連続している場合にチェックする
  • よくある日本語の誤用をチェックする
  • 冗長な表現をチェックする

.textlintrcは、下記のとおりです。

{
  "filters": {
    "comments": true
  },
  "rules": {
    "ja-no-redundant-expression": true,
    "period-in-list-item": {
      "periodMark": ""
    },
    "preset-ja-technical-writing": {
      "no-exclamation-question-mark": {
        "allowFullWidthQuestion": false
      },
      "sentence-length": {
        "max": 90
      },
      "max-ten": {
        "max": 3
      },
      "max-kanji-continuous-len": {
        "max": 6
      },
      "no-mix-dearu-desumasu": {
        "preferInHeader": "",
        "preferInBody": "ですます",
        "preferInList": "である",
        "strict": true
      },
      "ja-no-mixed-period": {
        "periodMark": "。"
      },
      "no-double-negative-ja": true,
      "no-dropping-the-ra": true,
      "no-doubled-conjunctive-particle-ga": true,
      "no-doubled-conjunction": true,
      "no-doubled-joshi": {
        "min_interval": 1
      },
      "ja-no-successive-word": true,
      "ja-no-abusage": true
    }
  }
}

たまにエラーになりますが、アプリケーションを再起動して実行するとうまくいったりします。

チェックして結果

今回のブログをチェックした結果、21件のエラーが検知されました。

f:id:ishitonton:20181202143917p:plain

エラーメッセージの一部です。

* 文章が”。”で終わっていません。
* "することが可能です"は冗長な表現です。”することが可能”を省き簡潔な表現にすると文章が明瞭になります。
* 箇条書き:”である調”と”ですます調”が混在
* should remove period maruk("。") at end of list item

少々基準が厳しすぎたようです。いくつか誤検知もありますが、それを無視すればよいです。

利用するプリセットによって、エラーメッセージに日本語や英語がありました。また、あまり長文を検査するとアプリケーションが重くなるので注意が必要です。

良かった点としては、自分の癖がよくわかることです。例えば私の場合、箇条書きに「ですます調」と「である調」が混在していました。また句点を付けるかどうかもルールが統一されていないことに気づきました。

無視したい部分は、フィルタができるはずですが、まだうまくできていないので宿題とします。そして、もともと指摘されたSkip-Granの誤字はいまだ検知できないのであります。

DataRobotは想像以上に凄かった。ハンズオンで実機を触ってみて。

AI Experience 2018 Tokyoというイベントに遅れて参加。DataRobot社が主催するイベントで、恵比寿のウェスティン東京で開催されました(お金持ち)。その中でハンズオンセッションがあり、機械学習自動化プラットフォームDataRobotを初めて触ってみました。

結論的には、自分の想像以上にDataRobotは凄かったです。写真撮影などはできなかったので、文章だけで悪しからず(伝わらんかも)。

ai-experience.jp

目次

AIの民主化とは

DataRobotは「AIの民主化」を促進すると謳われているので、まず「AIの民主化」について定義したいと思います。既に色々な人が定義してくれていて、例えばトランス・コスモスの東さんの講演では、

AIの民主化とは、データ分析をやってこなかった人が、データ分析ができるように育てていく。シチズンデータサイエンティストを育てていく。育った状態が民主化ができた状態

と定義しています。

また、リクルートテクノロジーの野川さんの講演では、

AIを自由かつ適切に活用している状態。価値が出る場所で自由かつ適切にAIが活用されること

と定義しています。いずれにしても、誰でもAIを自由に活用できるという認識は過度な期待です。

DataRobotとは

DataRobotについては、下記をご覧ください。とにかく容易に高速にモデルを構築でき活用できる。リクルート・テクノロジーさんは、これまでに社内の100人以上がDataRobotを活用してモデル構築を行っており、その数44万モデル! 凄い。。。

www.datarobot.com

ここが凄かったDataRobot

DataRobotは、AIの民主化の促進が可能なソフトウェアであると感じました。理由を下記に示します。

前処理とか基本統計量などが自動化

DataRobotにテーブル形式のデータを投入すると、分析が開始するわけなのですが、データインポートしたタイミングで、各特徴量の欠損値処理や基本統計を行い、データの傾向をグラフで確認することができます。コード書けばできることですが、それをいい感じのvisualizeで直ぐに描写してくれるので、データの全体像理解を促します

1つの予測に自動で数十個のモデルが試される

1つの予測の実行で数十個のモデルがキューに自動投入され、学習を開始します。トップのデータサイエンティストであれば、こういうの自動化していると思いますが、私レベルだとそんなに何十個もアルゴリズム試せないので、それがワンクリックで実行してくれます。非常に簡易的であり、超高速化が可能だと思いました。

なお、一般的なアルゴリズムDataRobotが独自に開発したアルゴリズムの両方がキューに入ります。LGBやXGBなども含まれていましたし、自分でモデルを定義してインポートすることも可能だそう。

少しインポートデータと学習の間の処理はブラックボックスな部分はありますが、Top Kagglerが設立した会社なので、その前処理の知見が詰まっているようです。

優先順位をつけ、リソースを有効活用

上記の40個の学習モデル。全てを並列に扱いません。DataRobotのUIは、学習が完了した精度が高いモデルから降順にソートされるので、分析者も精度の悪いモデルに意識を取られることがないです。また、ソフトウェア自体も精度が高いモデルを優先度が高いモデルとし、モデルの評価や解釈性部分の計算にリソースを投下してくれる。

評価や解釈性も担保されている

たくさんのモデルの中から、どのモデルを選ぶのかは分析者です。そのためのROC曲線や混同行列(Confusion Matrix)、特徴量重要度(feature importance)、部分従属プロット(partial dependency plot)など、評価や解釈のための様々な情報が用意されています。ソフトウェアの簡易性が上昇するほど、解釈性などはブラックボックス化されることを想像していたが、そうなっていないのがDataRobotの素晴らしいところです。カーソルを合わせると動的にパラメータを変動させて確認したりもできました。

DataRobotでどう進むの世の中は?

DataRobotによって、確実にビジネスサイドの人材がデータサイエンス側の業務に取組んでいく敷居が下がったと感じます。また民主化の促進により、データサイエンティストに求められる部分も変わってくると思います。データ前処理スト。特徴量エンジニア。。。so on

Embeddingについてまとめた。

下記の日本OR学会の論文を参考に、Embeddingについて整理しました。

Word Embeddingモデル再訪 オペレーション・リサーチ学会 2017年11月号

20190621追記 こちらの記事もご覧ください。

ishitonton.hatenablog.com

目次

Embeddingとは何か

自然言語処理におけるEmbedding(埋め込み)とは、「文や単語、文字など自然言語の構成要素に対して、何らかの空間におけるベクトルを与えること」を指す。

例えば、Word Embedddingでは、各単語に対して固有のベクトルを与えることを指している。

Embedding では、同じ階層の要素すべて(Word Embeddingなら単語すべて)が同じ空間内に配置され、常に同じ次元数のベクトルで表現される。このため,機械学習に特徴量として容易に投入可能。

例えば文を分類したい場合、単語ではなく文をベクトル化し埋め込む必要がある。しかし、文や文書は単語の系列として存在するため、単語より大きい要素の Embedding は単語or単語以下の Embedding を用いて表現することが多い。

Embeddingの各種アルゴリズム

One-hot表現

一番シンプルなEmbedding手法。まず表現したい語彙リストを作成し、各単語を表現する次元を準備する。表現したい文に含まれている単語に対応する次元を1に、それ以外を0にする方法。文のベクトルを作るBag-of-words(BoW)表現に利用される。

BoW表現では文のベクトルは各単語の One-hot 表現のベクトル和として表現され、文書分類の特徴量として利用される。

One-hot表現の欠点は下記。

  1. 未知語を扱うことができない。
  2. 次元数が膨大となる。->メモリ使用量が増大。

共起関係の利用

単語間の類似性を図る方法としては、単語同士の共起関係を利用する。これは、意味が似ている単語は類似した文脈で出現するだろうという分散仮説を前提としている。分散仮説に関連して開発された手法には、Count-basedpredictiveな方法がある。

count-basedな手法は、さまざま文脈の中で登場する単語の頻度を算出し共起行列を作成する。文脈とは、例えばWikipediaであれば各記事など、何か意味ある単語の集合を指す。count-basedな情報はスパースで扱いづらいものが多く、何らかの手法で情報集約して次元を減らしたりするのが一般的である。

predictiveな手法は、前後の文脈の単語のベクトルから目的の単語ベクトルを予測する(またはその逆を予測する)というタスクを通して、単語ベクトルを学習する手法。単語ベクトルの次元数は予測のアルゴリズム内で自由に決めることができる。

これらの方法は、次元圧縮された潜在変数の空間に単語がマッピングされる。One-hot 表現のように一つの要素(≒次元)が一つの概念(≒単語)に対応しているような表現ではなく、複数要素が一つの概念を構成し、一つの要素が複数概念を構成する“manyto-many”な表現 となる。

LSILatent Semantic Indexing

これは、count-basedな手法のうち代表的なもの。潜在意味インデックスと呼ばれたりする。Googleが取得している特許のひとつで単語同士の関連性に着目してコンテンツの内容を読み解くための技術である。

abicky.net

情報検索のために考えられた手法であり、各文書を潜在変数空間の点として表し,関連度を検索クエリ文書との近さで計測することを目指している。Latent Dirichlet Allocation(LDA) は、LSIの発展形である。

Word2vec

predictive な手法で実用上現在最も広く用いられている。word2vecは、大量のテキストデータを解析し、各単語の意味をベクトル表現化する手法。単語をベクトル化することで、単語同士の意味の近さを計算したり、単語同士の意味を足したり引いたりすることが可能。

Word2vecには下記2つの方法が存在。

  1. CBOW

  2. Skip-Gramモデル

今回は後者のSkip-Gramモデルについて簡単に説明。(こっちの方がわかりやすいらしい) Skip-Gramは、ある単語の前後に出現する単語の出現確率を計算することでベクトル化をする方法。これは、意味が近い(≒単語ベクトルの距離が近い)単語は、周辺の単語も似ているはずという仮説に基づきます。

Skip-Gramでは、入力単語を元に周辺語を出力する、入力層・隠れ層・出力層のみのNeural Networkを考える。すなわち、ある単語を入力データに、その周辺語を教師データにして、重みを学習していく。周辺5単語位が一般的らしい。

Skip-Gramについては、下記記事が非常にわかりやすいです。

www.randpy.tokyo

以下は、自社の勉強会資料です。

speakerdeck.com

Glove

Word2vec翌年の2014年に発表されたアルゴリズム。Glove はグローバルな情報を用いる count-basedな手法とローカルな文脈の情報を用いる predictive な手法を組み合わせたもの。いわゆる良いとこどりをした手法らしい。学習が速い、精度が高い、そして小さいコーパスでも動作可能とのこと。

fastText

2016年にFacebookが発表した手法。これまでの手法は単語をベースとするため、未知語に対応するのが難しい。これを克服するためのアイデアとして、単語より小さな単位でEmbedding を行う。

文字レベルのN-gram (Character N-gram) であるsub-wordを用いる。 Word2Vecでは、活用形が考慮されない(goとgoes、going、これらは全て「go」だが、字面的には異なるので別々の単語として扱う)。これに対してfastTextでは、単語を構成要素に分解(goesならgoとes)し、字面の近しい単語同士により意味のまとまりをもたせる。 f:id:ishitonton:20181125193220p:plain 下記記事がわかりやすい。

word2vec, fasttextの差と実践的な使い方 - にほんごのれんしゅう

FacebookのfastTextでFastに単語の分散表現を獲得する - Qiita

Character-based Embedding

sub-wordよりも小さい単位である文字ベースでのEmbedding (Character-based Embedding) も存在している。近年は特に RNNを用いた文章生成などで用いられている。

日本語や中国語のような漢字文化圏では、文字種数のオーダーが2 桁以上異なるために個々の文字がより複雑な単語的意味をもっており,文字レベルでの Embedding が研究されている。漢字の場合は、その字形自体も意味をエンコードしていると。まぁ、言われてみれば本当にその通りです。字形を画像として捉え、Convolutional Neural Networkを用いて視覚的特徴のEmbeddingを作成している例もあるとのこと。

Word Embedding モデルのアンサンブル

これまで見てきたEmbeddingは、それぞれ異なる特徴を持っているので、当然これらの情報をもとにアンサンブル学習するのも必然的な流れの一つ。異なるWord Embeddingモデルを複数用いたMeta Embeddingは発表されている。

また、人手で作られた言葉の概念ツリーデータベースWordNetとWord2Vecのモデルを組み合わせ、WordNetの抽象概念にベクトルを付与したAutoExtendなどもある。

日本語環境下でのEmbedding

日本語のコーパスで大規模でフリーなものは少ない。日本語におけるEmbeddingモデルの公開言語資源は英語圏と比べるとまだまだ少ないのが現状。 日本語では形態素解析が必要となる。MeCabが有名だが、近年はneologdが用いられる。MeCabとは、形態素解析をするためのライブラリであり、NEologdはWeb上から得た新語に対応しており、毎週更新されるMeCab用のシステム辞書。この二つで最新の単語に対応した形態素解析が可能。

ファインチューニング

ファインチューニングとは、機械学習タスクでまず一般的なデータで学習して得られたパラメータを初期値として、特定のタスクのデータや目的関数で再度学習することで、そのタスクにおける精度を向上させる手法。

Embedding モデルを利用する際、試験的に利用する範囲では既存の公開モデルをそのまま使うだけでも十分だが、タスクの精度を向上させるにはやはりEmbeddingモデルのファインチューニングは有力な選択肢の一つ。

一から学習し直してもよいが、学習データが少ない場合などもある。実用上はWikipediaデータのような大規模なデータセットで学習したEmbeddingモデルを、対象のタスクの精度を向上するように再学習するという形式がとられることが多い。