itertools でリストの部分集合をリストアップする

Pythonの標準ライブラリである、itertools を使うと、リストや集合(set)の部分集合を手軽にリストアップすることができます。
ドキュメントはこちら。
itertools — 効率的なループ実行のためのイテレータ生成関数

欲しい部分集合の性質(重複の可否や、ソートの有無)に応じて、次の3種つの関数が用意されています。

itertools.permutations(iterable, r=None)
長さrのタプル列、重複なしのあらゆる並び

itertools.combinations(iterable, r)
長さrのタプル列、ソートされた順で重複なし

itertools.combinations_with_replacement(iterable, r)
長さrのタプル列、ソートされた順で重複あり

試しに要素が5個のリストを用意して、 r=3 でソートされた順番で重複無しの
部分集合をリストアップしてみましょう。
$_5\mathrm{C}_3=\frac{5\cdot4\cdot3}{3\cdot2\cdot1}=10$なので、10組みの結果が得られるはずです。


import itertools
data = list("ABCDE")

for subset in itertools.combinations(data, 3):
    print(subset)

# 以下出力
('A', 'B', 'C')
('A', 'B', 'D')
('A', 'B', 'E')
('A', 'C', 'D')
('A', 'C', 'E')
('A', 'D', 'E')
('B', 'C', 'D')
('B', 'C', 'E')
('B', 'D', 'E')
('C', 'D', 'E')

想定通りの組み合わせが出ました。
また、結果はsetやlistではなく、タプルで返されることも確認できます。

MySQLのテーブルをDB内でコピーする2つの方法

先日、諸事情あってMySQLのテーブルをコピーしておきたいことがありました。

SELECT以外の操作は滅多にやらないので、少し調べて出てきたのがこちらの方法です。
1つ目のクエリで元のテーブルと同じ構造のテーブルを作り、
2つ目のクエリでデータを移しています。


CREATE TABLE new_table_name LIKE table_name;
INSERT INTO new_table_name SELECT * FROM table_name;

今回必要だった要件は、これで満たせたのですが、一個のクエリでコピーする方法があったはず、
というおぼろげな記憶があったのでもう少し探して見つけたのがこちら。


CREATE TABLE new_table_name SELECT * FROM table_name;

これなら1行で中のテーブルをコピーできます。

なんで一行で済む2番目の方法よりも、クエリを二つ使う1番目の方法の方がよく使われているのか気になったので、後日実験してみました。

結果わかったのは、データはどちらの方法でも同じようにコピーされるのですが、
2番目の方法では、テーブルの設定の一部がコピーされないことです。

試したのがこちら。
まず、元のテーブル。


mysql> desc sample1;
+------------+--------------+------+-----+-------------------+-----------------------------+
| Field      | Type         | Null | Key | Default           | Extra                       |
+------------+--------------+------+-----+-------------------+-----------------------------+
| id         | int(11)      | NO   | PRI | NULL              | auto_increment              |
| name       | varchar(255) | YES  |     | NULL              |                             |
| created_at | datetime     | NO   |     | CURRENT_TIMESTAMP |                             |
| updated_at | datetime     | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+------------+--------------+------+-----+-------------------+-----------------------------+

1番目の方法でコピーしたテーブル。こちらは元のテーブルと同じです。


mysql> desc sample2;
+------------+--------------+------+-----+-------------------+-----------------------------+
| Field      | Type         | Null | Key | Default           | Extra                       |
+------------+--------------+------+-----+-------------------+-----------------------------+
| id         | int(11)      | NO   | PRI | NULL              | auto_increment              |
| name       | varchar(255) | YES  |     | NULL              |                             |
| created_at | datetime     | NO   |     | CURRENT_TIMESTAMP |                             |
| updated_at | datetime     | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+------------+--------------+------+-----+-------------------+-----------------------------+

2番目の方法でコピーしたテーブル。
auto_incrementやDefaultの値の一部、主キー属性などがコピーされていません。


mysql> desc sample2;
+------------+--------------+------+-----+-------------------+-----------------------------+
| Field      | Type         | Null | Key | Default           | Extra                       |
+------------+--------------+------+-----+-------------------+-----------------------------+
| id         | int(11)      | NO   |     | 0                 |                             |
| name       | varchar(255) | YES  |     | NULL              |                             |
| created_at | datetime     | NO   |     | CURRENT_TIMESTAMP |                             |
| updated_at | datetime     | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+------------+--------------+------+-----+-------------------+-----------------------------+

値はどちらの方法でもコピーされるのですが、
見落としがちな部分に差異があるので注意が必要ですね。

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の方使っちゃいます。
この辺りはいつかしっかり勉強したい。