ごはんと飲み物は紙一重

このブログはモチベーションアップのために情報工学関連について記事を更新していこうと思います。三日坊主にならないよう頑張ります。

matplotlibのsubplotsで文字が重なるのをどうにかきれいにしたい

連続投稿することになりそうなりました。

というわけで、前回の記事でいい感じにsubplotsしたいのはいいものの、その他titleだったりxlabelとかをつけていると、重なっちゃってうまく出力できない問題があるわけです。

これを解消する関数に

plt.tight_layout()

なんて関数があるんですね。すばらしい。コレを使うとxlabelとtitleがかぶらなかったり、グラフにかぶらなかったりでいい感じに出力できるようです。やったね。

matplotlibのsubplotsでグラフをいい感じにjupyterに出力したい

いつも可視化のときに位置に拘ってしまう悪い癖が働いてしまい・・・備忘録代わりに。

jupyter notebookを使ってデータ分析しているとmatplotlibで可視化するのは日常茶飯事だと思うのですが、

あるフォルダから全てのcsvファイルを読み込み!!

そのデータをすべてヒストグラムにしたい!!

それもいい感じに2列n行の形で!!

とはみなさん思いませんか?そのために結局色々悩んだので、悩んでる方の参考になればと。
(本当はseabornとかもっと方法が色々あるとは思うのですが・・・)

私が触ったのは、

あるフォルダから全てのcsvファイルを読み込み!!os.walk

そのデータをすべてヒストグラムにしたい!!plt.hist

それもいい感じに2列n行の形で!!内包表記で配置位置のリストを生成

な感じです。今回はmatplotlib関連が主題なのでos.walk内包表記で配置位置のリストを生成あたりのお話をしようかと。

os.walk をつかったファイル参照

import osして使用するメソッドで、使用するときにフォルダの位置を指定することで、3つの返り値を取得することができ、

をrtを含むrt以降のフォルダすべてで検索した結果を返してくれます。シェル的にいうls -Rみたいな感じですね。

たとえばls -R

main/    test.txt

./main: main.py

と出た場合、

os.walkすると

./
["main"]
["test.txt", ".DS_Store"](隠しファイルまで探します)
./main
[]
["main.py"]

のように返ってきます。このファイルのリストを使ってfor文を回せばうまい具合にcsvの入ったフォルダを参照させることができます。詳しく条件をつけて検索したい場合とかはimport reとかして正規表現とかを使ったりすると幸せになれる???

2列n行でsubplotsする

一番話したかったところですね。とりあえず形にはしてるので、もっといい方法があればコメントしていただけると。 どういうことをするかというと、

for rt, dirs, fnames in os.walk(csvがあるフォルダ):
  fig, ax = plt.subplots(ncols=2, nrows = len(fnames)//2)
  row = [_%(len(fnames)//2) for _ in range(len(fnames))]
  col = [_//(len(fnames)//2) for _ in range(len(fnames))]
  for i, fname in enumerate(fnames):
    # なんやかんや前処理
    ax[row[i], col[i]].hist(ヒストグラムにするデータ)
    # その他出力オプション

subplotsで配置する位置を先にリストで作ってしまう方法を取りました。
こうすれば検索したファイル数を問わず2列n行でsubplotすることができると思います。スマートに汎用性高いプログラムにしたくなってしまって時間が取られてしまうの非常に辛い。

もっとこれよりもスマートに見た目でわかりやすいコードとかあれば更新しようかと思います。 (そこまでめんどくさいことしなくてもcellわけて一つずつplt.plotすればよk)

追記 11/17(金)

上記のように配置場所をリストにせずともうまく出力する方法が優秀な大学の先輩から提案されたのでこちらも参考にしていただけると。

for root, dirs, fnames in os.walk("./data/"):
    col = 2
    row = len(fnames)//2    
    fig = plt.figure(figsize=(16, 10))
    
    for i, fname in enumerate(fnames):
        fig.add_subplot(row, col, i+1)
        df = pd.read_csv(root + fname, header=None)
        plt.hist(df)

こちらはfigに対してadd_subplotを使用している形ですね。うまく出力行と列がfor文で回っててこちらの方がしっくりきてます(個人談)。これならdfにかぎらず画像もできそう。

f:id:ST_ha1cyon:20171117113434p:plain

それ以外にもpandasのdfから直接histを出してしまう方法もあり、こちらはグラフ毎に色を自動で変えてくれたり気を利かせてくれるのでとてもいい感じに可視化してくれますし、コードもかなりスッキリしていていい感じですね。一つ一つ読み込むのではなくcsvを一度にまとめてDataFrameに入れているので、データ分析をするときにはこちらを使用するほうが幸せになれそうです。

for root, dirs, fnames in os.walk("./data/"):
    row = 2
    col = len(fnames)
    
    datasets = [np.loadtxt(root + fname, delimiter=",") for fname in fnames]
    dataframe = pd.DataFrame(datasets)
    dataframe.T.plot(kind="hist", subplots=True, layout=(col, row), sharex=False, legend=False, bins=20, figsize=(16,10))

f:id:ST_ha1cyon:20171117114210p:plain

CTRデータをヒストグラムで眺めたい

CTR(Click Through Rate)のことで、日本語ではクリック率とか言います。広告関係のやつですね。Kaggleにも似たような内容があったような。

https://www.kaggle.com/c/avazu-ctr-prediction

これを各ユーザがどれだけクリックしてくれているかの分布を見てみたいというわけで、

仮に、広告を掲載したページが10000回表示され、そのうち100回だけ当該の広告がクリックされたとするならば、CTRは  100÷10000= 0.01 = 1% となるわけです。

今回の場合は

  • user_id (ユーザID)
  • click (クリックの有無)
  • 全体数

を使うような感じです。

x1 = df[df.click == True].groupby("user_id")["ある列"].count()
x2 = df.groupby("user_id")["ある列"].count()

で x1/x2 してそれを plt.histで出力することで大まかな分布を見ることができるみたいです。

コレを書きながら上記の書き方ではなく

x1 = df[df.click == True]["user_id"].value_counts()
x2 = df["user_id"].value_counts()

と書いたほうがソース的にぱっとみ理解しやすいような感じがした。と言う感じで自分の中でしっくり来た感じです。前者の方は教えてもらったほうなので、python特有の自分のよく使う関数メソッドや方法がソースにでてしまうという現象を自分の中で受けました。

いやぁ、いろんな書き方があるんだなぁ。

MacBook Proのカバー(ハードケース)を買い替えたお話

f:id:ST_ha1cyon:20171105153548j:plain

じゃん。

ということで2年ほどお世話になったカバーはだいぶボロボロになってしまったので買い替えをしました。買い替えと言ってもの同じ商品を買い替えてて、

http://amzn.asia/7x55LbM

NEXARY の ハードケースです。値段が2000円超えないにもかかわらず、想像を上回るくらいのコスパでいろいろと助けていただきました。

んで、そもそもなぜハードケースをつけているのかというと、上の写真にある通り、macにステッカーを貼りたいからですね。

直接張ってしまうのは汚れてしまって気が引けたので、初めのうちからカバーを買ってその上からステッカーを貼っておいてしまおうということでした。(学内にはretina持ちが100名以上いるとなると間違って持って帰るとか普通にあるので)

わりとおすすめでなおかつ色も豊富に揃えているので、悩んでいる方はぜひ。

さぁ、カバーを変えたのはいいけど、ステッカーどうしようかなぁ・・・また作るか・・・

アルファブレンディングを列方向の画像の位置ごとに処理したい

とある授業の課題でアルファブレンディングを画像の列方向の位置ごとに処理をかけていかなきゃいけなくなって色々試行錯誤していたのですが、とりあえず気づいたことをメモ。

  • 列ごとへの画像への処理
    これは普通にスライスで行けそうです。img[:, i]みたいな形でfor文回してやればなんとかなりそう
out = a1 + a2 * (1 - a1)
img_ab_chg.append((img_1[:,i] * a1 + img_2[:,i] * a2) / out) 

わざわざリスト処理してるけど正直なところを言うとnumpyで完結させたかった感じはある。

  • 列処理後の画像の転換

んで上の方法で列ごとに処理をしてやると画像が反転するのでもとにもどさないといけなくなるので、それを処理するためにnumpyのtransposeを使用することに。画像の場合通常カラーで有ることがほとんどなので普通に.Tとかしてしまうと、(114,514,3)が(3,514,114)みたいになってしまう。そのために詳しく設定するtransposeを採用。

img_ab_chg = np.array(img_ab_chg).transpose(1,0,2)

順番を指定してやることで望んだ方向に転換してくれる寸法。本当はcv2のアフィン変換を使ったり様々な方法はあったけど、できるだけnumpyで簡潔したかったっていう個人的なプライドです。はい。

  • matplotlibのplt.imshowについて

それとmatplotlibで出力する時、普通にnumpyのarrayを投げちゃうと色がとんでもないことに。調べてみるとどうやら画像を読み込んでplt.imshowするときには自動的に正規化する仕様らしい。コレに気づかずに何回コードを書き直したことか・・・・

なので手動で正規化することに。これで一応目標は達成。

f:id:ST_ha1cyon:20171104182231p:plain

本当はもっときれいに書きたいし、なるべくnumpyだけですべて処理したいけど他にも有るので一旦は次に進もうかと思います。

課題自体は3週間後だけど、できれば今週でなんとかしたい。でも明日は流石にゼミに向けて資料まとめなあかんな。いそがC。

matplotlibで大きい順にソートしてグラフにする方法【plt.xticks】

わりと悩んでしまったので備忘録代わりに。

何が言いたいのかというと、

id_x1 = val_counts[0][0:5].index.astype(str)
id_y1 = val_counts[0][0:5].values
plt.bar(id_x1, id_y1)

f:id:ST_ha1cyon:20171025194302p:plain

このx軸のlabelが意図せずソートされてしまう現象をなんとかしたいわけですよ。
別に無理してやる必要はないのかもしれないけど、可視化の美学を求めてしまうのは、データ分析界隈にいるが故の病。

というわけでこれを改善しようというお話。

上記のソースは出力したいSeriesから単純にindexを取り出してastypeでstringに変換しただけ。それでもソートしてくるので、xticksで上書きしてしまおうという魂胆。

改善後のコードはこちら。

id_x1 = range(0,5)
id_y1 = val_counts[0][0:5].values
plt.xticks(range(0,5), val_counts[0][0:5].index)
plt.bar(id_x1, id_y1)

具体的に何をしたのかというと、x軸についてはrangeで通常出力してしまって、xticksでlabelを書き換えてます。そうすることで大きい順に並んだグラフができるようです(もっときれいな書き方ありそうだから分かる人はコメントしていただけると泣いて喜びます)。

f:id:ST_ha1cyon:20171025194848p:plain

同じようなことが起きないようにブログに残したけど、同じようにやり方忘れてしまってぐぐったら自分のブログがヒットするとかそういうことがないようにしたいなぁ・・・頑張ろ・・・

GitlabのPushをslackに通知するまで【2017年10月18日時点】

気がつけば前回の更新化から2週間すぎていた・・・更新する記事は色々あったのにいいい

ところで、バイト先の方でGitlabのpush通知を設定するとのことだったので、

qiita.com

をみながら作業を進めようと思ったのですが、

「UIぜんぜん違うからスムーズに進まねぇ」

ということで備忘録代わりに書いていこうかと。

Slack側操作

  1. slackのAPIのサイトにアクセス

api.slack.com

今のUIには「Apps & Custom Integrations」がないので、
直接APIのサイトにアクセスする。

  1. 画面左メニューバーのLegacy custom integrations をクリック

f:id:ST_ha1cyon:20171018150903p:plain

  1. Post notifications to Slack の記事から「Set up an Incoming webhook」をクリック

f:id:ST_ha1cyon:20171018151048p:plain

  1. 「add configuration」から 設定を追加していく

追加したいチャンネルを選択して、

f:id:ST_ha1cyon:20171018151305p:plain

追加すると「Webhook URL」が出てくるのでURLをコピーしてSlack側の設定はおしまい。

GitLab側操作

  1. 連携したいプロジェクトからsetting→integration→ページ下部の「Slack notifications」を選択

f:id:ST_ha1cyon:20171018151839p:plain

  1. Activeにチェックを入れて、Webhookをペースト。

細かい通知の設定はここでやっておくといい感じになる。

  1. test settings and save configurationをクリックして、slackにテスト通知が来たら設定完了。

って感じです。簡単に設定できるのは非常にありがたいですが、UIがちょこちょこ変わるとこういうときに不便だなと思いつつ、最新の変化に対応するのがIT界隈にいる上での必須スキルなんじゃないかと。

もしまた更新があったらそのときは誰かが更新してくれるかコメントを残してくれるはず。githubとかでも同じことできそうだな。