people analytics tokyo #1に参加しました

少し前になりますが、6月28日にYahoo!のコワーキングスペースのLODGEで開催されたpeople analytics tokyo #1 に参加してきました。
イベントのページ

3つのトークと3つのLT全て資料が公開されていてありがたい。

Talk

Drive Business Performance by People Analytics – 国内外の最新トレンドと事例を添えて – -BtoA株式会社 代表取締役 石原史章さん
Rによるemailコミュニケーションの可視化 – ソフトバンク株式会社 御園生銀平さん
感謝ネットワークからみる組織のコミュニケーションの形 – People Analyst 大成弘子さん

LT

People Analyticsと社会ネットワーク分析 – フリーランス 祖山寿雄さん
組織の「価値観」ネットワークの可視化と「評価」の関係性 – 株式会社トランス 代表取締役 塚本鋭さん
群衆の知恵・集団的知性 〜 会社で集まる意味あんの?〜 – 株式会社シンギュレイト 代表取締役 鹿内学 さん

感想

自分は人材系のサービスの会社でデータサイエンティストをやっているのに、
なかなかこの分野の分析には取り組めていない反省もあって参加を決めました。
結果的には参加して大正解でした。

1. ネットワーク分析が持つポテンシャルの高さを実感した

ネットワーク分析についてはそういうものがあるということだけは知っていましたが、
サンプルコード等を動かしてみても、それをどう使えば業務に役立つ(=利益が出る)のかわからず、学習が進んでいませんでした。
しかし、今回の発表では多くのテーマの中でネットワーク分析が使われており、
そのネットワークも、メールやりとり、価値観の近さ、上司と部下などの組織体制、会話中の単語の共起など、様々な種類のものでした。
そしてそのいずれでも興味深い知見が得られおり、この手法が持つ可能性の高さを実感しました。

2. 分析から得られた知見が面白い

退職者の予測と対策や従業員の不正の予防、価値観と仕事におけるパフォーマンスの関係、
上司の語彙と部下のエンゲージメントの関係など、組織で働く人なら誰でも興味をもちそうな結果が紹介され、
結果だけを取ってみても面白いものばかりでした。

3. 会場全体の一体感が心地よかった

普段はそれぞれ別々の分野の分析をしている人が、各自自分の好きなことを話すタイプのMeetUpが好きでよく参加しているのですが、
今回の会はそれとは逆に、非常に全体の統一感の高い会でした。
しかし、全体に一体感があり会場の雰囲気の良さもあり、とても心地の良い時間を過ごせました。
ネットワークの種類は違っても多くの人がネットワーク分析の手法を使い、人に関する分析を行うという、
共通のテーマを持って集まっているからこそだと思います。
大成さんの発表の中で、ピープルアナリティクスとは、働く人々を幸福にする分析である、という言葉がありましたが、
そこに取り組む人たちの集まりだったということも大きく影響していると思います。

4. おまけ

Yahoo LODGE に興味があり、いつか行きたいと思ってたので行けてよかった。

まとめ

全然知識を持ってない分野のミートアップでしたが、思い切って参加してみてよかったと思います。
ネットワーク分析という新しいおもちゃを手に入れて日々の勉強がまた楽しくなりそうです。
自分の職場のデータでも何かやってみたい。

ピープルアナリティクスについて、日本語で具体的な例を学べる場が少ないということで今回の会を開催されたそうですが、
僕に取って非常にありがたいきっかけになりました。
会の準備も当日の運絵も大変だったと思いますが、主催者・発表者の皆様、本当にありがとうございました。

2019年第2四半期によく読まれた記事

ブログを開設から半年になりました。
ありがたいことに訪問者も増え、週に400人以上の方が訪問してくださっています。
開設から3ヶ月経過した時点でよく読まれている記事を紹介させていただいた後、
再び3ヶ月たちましたのでこの辺で最近の人気記事を紹介させていただこうと思います。

前回:2019年第1四半期によく読まれた記事

ベスト5はこちらです。

  1. macにgraphvizをインストールする
  2. pythonで編集距離(レーベンシュタイン距離)を求める
  3. pythonでARモデルの推定
  4. pandasでgroupbyした時に複数の集計関数を同時に適用する
  5. Mac(Mojave) に pip で mecab-python3をインストールする時にはまった

前回1位のmecab-python3のインストール時エラーの話題は5位になり、
代わりに前回2位のgraphvizのインストールの話がトップになりました。

前回、ほぼ読まれてないとぼやいていた時系列解析系の話から、ARモデルの話が3位に入ったのは少し嬉しいです。
ただ、自己回帰ではなく拡張現実のARと勘違いして訪問された方もいらっしゃるような気がしています。

まだまだブログに書きたいことはいろいろあるのですが、
1日1記事のペースで書けるようなネタ(以前検証した時のコードが手元にあるものや、ちょっとした小ネタ的なもの)は
流石に180記事も書いていると枯渇気味で、もうちょっと1記事1記事に時間かけた方が良さそうという思いは強くなっています。
ということで、今後は1週間あたりの記事数を少し落としながら継続していこうと思います。

MySQLで自分に付与されている権限を確認する

分析を仕事にしているので、普段DBを触るときは SELECT しかしませんが、
諸事情ありまして、テーブルの作成やテーブル定義の変更を試す必要が発生しました。
なお、DBはMySQL。管理者は別チームです。

問題になるのが、自分のユーザーでCREATE TABLEやALTER TABLEの権限を持っているかどうかです。

調べたところ次のクエリで現在のユーザーの権限を確認できました。


SHOW GRANTS;
-- 結果は省略

ドキュメントはこちら:13.7.5.22 SHOW GRANTS 構文
FOR で指定すれば他のユーザーの権限を確認する事もできるようです。

CREATEもALTERもできることがわかりましたが、権限付与されていたら何をやってもいいというわけでもないので、
一応DBを管理しているチームに一声かけて作業を進めました。

LightGBMを動かしてみる

今回はほぼ動作確認だけです。
(前回の記事の最後に書いた通り、僕の環境ではimport 時にWarningが出るのでそもそも動くかどうかが不安だったので。)

LightGBMには scikit-learn形式のAPIが実装されていて、ほぼ同じように使う事もできます。
Scikit-learn API

とりあえずbostonのデータセットを使って、回帰問題を解いてみましょう。
動作確認なのでパラメーターはデフォルトです。
最後の評価は平方二乗誤差で行なってます。


import lightgbm
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# データの準備
boston = load_boston()
X = boston.data
y = boston.target
X_train, X_test, y_train, y_test = train_test_split(
                                    X, y, test_size=0.2, random_state=0
                                )
# デフォルトパラメーターでオブジェクト生成
lgbm = lightgbm.LGBMRegressor()
# 学習
lgbm.fit(X_train, y_train)
# 評価
y_predict = lgbm.predict(X_test)
print(mean_squared_error(y_test, y_predict))
# 24.34062206680735

無事に動いたようです。

Mac に LightGBMをインストールする

手順のメモです。

公式ドキュメントにイストールガイドがありますが、実は使うのはこちらではありません。
Installation Guide

僕はpythonから使う予定なので、Githubのリポジトリの方を読んで作業します。
LightGBM Python-package

次のコマンドを順番に実行します。


brew install libomp
pip install wheel
pip install lightgbm

自分の環境では wheel はすでにインストールされているという趣旨のメッセージが出ました。


$ pip install wheel
Requirement already satisfied: wheel in ./.pyenv/versions/anaconda3-5.2.0/lib/python3.6/site-packages (0.31.1)

これでインストールできたはずなのですが、インポートしてみると次の警告がでます。


$ python
>>> import lightgbm
/Users/xxxxxx/.pyenv/versions/anaconda3-5.2.0/lib/python3.6/site-packages/lightgbm/__init__.py:46: UserWarning: Starting from version 2.2.1, the library file in distribution wheels for macOS is built by the Apple Clang (Xcode_8.3.3) compiler.
This means that in case of installing LightGBM from PyPI via the ``pip install lightgbm`` command, you don't need to install the gcc compiler anymore.
Instead of that, you need to install the OpenMP library, which is required for running LightGBM on the system with the Apple Clang compiler.
You can install the OpenMP library by the following command: ``brew install libomp``.
  "You can install the OpenMP library by the following command: ``brew install libomp``.", UserWarning)

Warningは出るものの、動作に問題はなさそうなので一旦はこのまま使うおうと思っています。
とはいえ気持ち悪いのでいつか直したいです。
brew install libomp は実行してるし、 brew list すると、libompは出てくるのですけどね。

Xcodeがどうのこうのと書かれているので、以下の記事で行なったcommand Line Toolsのインストールが影響してるような気もします。

Mac(Mojave) に pip で mecab-python3をインストールする時にはまった

複数のDataFarameを1つのExcelファイルに書き出す

pandasのDataFrameを保存したい時、to_excel()関数を使うと手軽にExcelファイルに書き出せます。
ただ、 df.to_excel(“ファイルパス”) というやり方だと、1ファイルに1個のデータフレームしか書き出せません。

複数のデータフレームをシートを分けてエクセルファイルに保存するときは、
ExcelWriter というのを使います。
ドキュメント: pandas.ExcelWriter

実際に使ってみましょう。
with を使うと便利です。 (使わない方法もあります)


import numpy as np
import pandas as pd
dataframe_list = [
    pd.DataFrame(np.random.randn(100, 10)) for _ in range(3)
]
with pd.ExcelWriter("./3sheets.xlsx") as writer:
    for i, df in enumerate(dataframe_list):
        df.to_excel(writer, sheet_name=f"シート_{i}")

sheet_name は指定しておかないと、同じシートに上書きされてしまい、
最後のDataFrameしか残らないので注意です。

フォーマット済み文字列リテラル

Pythonの3.6からの新機能で、フォーマット済み文字列リテラルというのがあることを知りました。
ドキュメント:2.4.3. フォーマット済み文字列リテラル

要は、文字列を定義する時にfかFを頭につけておくと、
その文字列の中で{}で囲んだ変数がその値に置換されるというものです。


name = "Fred"
print(f"He said his name is {name}.")
# He said his name is Fred.

これまでformat()を使うことが多かったのですが、それよりも便利そうです。
ちなみに、format()を使うなら次のように書きます。少し長いですね。


print("He said his name is {name}.".format(name=name))
# He said his name is Fred.

{, }の文字を使いたい時は{{, }}のようにそれぞれ2重に書いておけば使えます。


print(f"{{He said his name is {name}.}}")
# {He said his name is Fred.}

この他、文字列をクオーテーションで囲んだり、数値の桁数の指定など様々なオプションが使えるようです。
ほぼコピペですが、ドキュメントに乗っていたサンプルコードを一通り動かしてみました。


import decimal
from datetime import datetime

name = "Fred"
print(f"He said his name is {name!r}.")
# "He said his name is 'Fred'."
print(f"He said his name is {repr(name)}.")  # repr() is equivalent to !r
# "He said his name is 'Fred'."
width = 10
precision = 4
value = decimal.Decimal("12.34567")
# : を使って表示桁数を指定
print(f"result: {value:{width}.{precision}}")
# 'result:      12.35'
today = datetime(year=2017, month=1, day=27)
# 日付の書式指定
print(f"{today:%B %d, %Y}")
# 'January 27, 2017'
number = 1024
# 16進法表記
print(f"{number:#0x}")
# '0x400'

pyenvで作成した環境を消す

うまくインストールできないライブラリがあり、
pipで入れたり消したり、condaで入れたり消したりとやっていたら何やら全体的に環境がおかしくなってしまいました。
(またかよという感じですが。)

しかたがないので、その環境は消して作り直すことにしました。
pyenv uninstall で環境は消せます。
参考 : pyenv uninstall


# 確認
$ pyenv versions
  system
* anaconda3-5.2.0 (set by /Users/******/.pyenv/version)

# 利用するpythonの環境をsystemのものに戻す。
$ pyenv global system
$ python --version
Python 2.7.10

# 不要になった環境を消す
$ pyenv uninstall anaconda3-5.2.0
# もう一度入れ直し
$ pyenv install anaconda3-5.2.0
$ pyenv global anaconda3-5.2.0
$ python --version
Python 3.6.5 :: Anaconda, Inc.

あとはこのブログで pip で検索して、うまくインストールできていたものを順に入れていけば元に戻るはず。
そもそも、anacondaで作った環境でcondaではなくpipを使ってるのがトラブルの原因でもあるのですが、
condaとpipの違いとか使い分けとか十分理解できてないので、どうしてもpipの方使っちゃいます。
この辺りはいつかしっかり勉強したい。

DataFrameの変化率の計算

前回の記事が差分だったので次は変化率です。
ファイナンス系のデータをはじめとして変化量よりも変化率の方が着目される例は多々あります。

pandasのDataFrameにおいては、pct_changeというメソッドで算出することができます。
pandas.DataFrame.pct_change

とりあえず使ってみましょう。


import pandas as pd
df = pd.DataFrame(
        {
            'a': [1, 2, 3, 4, 5],
            'b': [1, 4, 9, 16, 25],
            'c': [1, 8, 27, 64, 125],
        }
    )
print(df.pct_change())
'''
          a         b         c
0       NaN       NaN       NaN
1  1.000000  3.000000  7.000000
2  0.500000  1.250000  2.375000
3  0.333333  0.777778  1.370370
4  0.250000  0.562500  0.953125
'''

結果を見てわかる通り、1から4への変化は 4/1 = 4 と計算されるのではなく、 (4-1)/1 = 3 になります。
その点だけ注意です。

Dataframeの差分を取る

pandasの累積和をとったり、特定のwindowごとの和をとったりする方法はこれまで紹介してきたので、
次はDataFrameの差分を取る関数の紹介です。
元のデータが単位根過程の時に差分をとって定常化するなど、結構頻繁に使います。

さて、その方法ですが、DataFrameのdiffというメソッドを使います。

pandas.DataFrame.diff

引数には periods と axis を指定できますが、大抵はどちらもデフォルトでいけるでしょう。
periods(デフォルト:1)を指定することで、いくつ前の値との差分を取るかを指定でき、
axis(デフォルト:0) に1を指定すると隣の行との差分をれます。


import pandas as pd
df = pd.DataFrame(
        {
            'a': [1, 2, 3, 4, 5],
            'b': [1, 4, 9, 16, 25],
            'c': [1, 8, 27, 64, 125],
        }
    )
print(df.diff())
'''
     a    b     c
0  NaN  NaN   NaN
1  1.0  3.0   7.0
2  1.0  5.0  19.0
3  1.0  7.0  37.0
4  1.0  9.0  61.0
'''

print(df.diff(periods=2))
'''
     a     b     c
0  NaN   NaN   NaN
1  NaN   NaN   NaN
2  2.0   8.0  26.0
3  2.0  12.0  56.0
4  2.0  16.0  98.0
'''

print(df.diff(axis=1))
'''
    a     b      c
0 NaN   0.0    0.0
1 NaN   2.0    4.0
2 NaN   6.0   18.0
3 NaN  12.0   48.0
4 NaN  20.0  100.0
'''

なお、それぞれ次のようにshiftして値をずらしたものとの差分を取るのと結果は同じです。


df - df.shift()
df - df.shift(periods=2)
df - df.shift(axis=1)