Google Colaboratory からKaggle API を叩く
過去にQiitaに書いたことがありますが、
こちらにもメモとして再度検証、記録に残します。
Kaggle APIの公式リファレンスはこちら
Kaggle json のダウンロード
My Accountから、API Tokenを作成、kaggle.jsonをダウンロードします。
以下、google drive上に先ほどのjsonを格納
Colaboratory
以下、pipからkaggleモジュールをインポート
!pip install kaggle
google driveにマウント、必要があれば適当にカレントディレクトリを設定します。
import os from google.colab import drive drive.mount('/content/drive') os.chdir("/content/drive/My Drive/hoge/hogehoge")
先ほど読み込んだjsonファイルからusernameとkeyを環境変数に読み込みます。
import os import json f = open("/content/drive/My Drive/kaggle.json", 'r') json_data = json.load(f) os.environ['KAGGLE_USERNAME'] = json_data['username'] os.environ['KAGGLE_KEY'] = json_data['key']
以上で準備は終わりです。簡単でした。
api
上記処理で、あとはapiを叩くだけです。
現在開催されているコンペティションリストはこれ。
!kaggle competitions list
試しに現在開催されている以下コンペのデータをカレントディレクトリにダウンロードしてみます。
Dataタブに表記されているapiを、colaboratoryにコピペするだけです。
!kaggle competitions download -c m5-forecasting-uncertainty
無事全ファイルダウンロードされていました。
また、この例ではデータはzip形式になっていますが、
pandas.read_csv
はzipのまま読み込むことが可能です。
import pandas as pd train = pd.read_csv("sales_train_validation.csv.zip") print(train.shape) display(train.head())
無事、ちゃんと読み込めていそうな感じでした。
appendix
過去から記事を漁るといろいろでてきますので、お好きな方法で実装すればよろしいかと思います。
【Pythonメモ】Google ColaboratoryでKaggle APIを使うおまじないコード&作法 - Qiita
Easy way to use Kaggle datasets in Google Colab | Data Science and Machine Learning
Ternary plot をTableauで実現する
Ternary Plot、3次元プロット?をTableauで実装してみます。
Tearnary Plotは3次元の構成要素を正三角形内にプロットするVizです。
Tableau Public に Tearnary Plot のサンプルが多々 Publish されているので、
それを見ていただくとイメージがつかめます。
僕もこれらを参考に、以下設計していきます。
データ
e-statから市区町村の年齢3階級別人口を取得しました。
この3カテゴリの構成比データを2次元座標データに加工し、 Tableau上でTernary Plotとして描写するのが本記事のゴールです。
上記e-statでデータを加工し、以下のデータを取得します。
余計な情報はcsv上で処理し、Tableauへ渡します。
Tableau上での描写
Tableauに渡した段階のデータはこちらになります。
ここから、以下のとおり構成比のメジャーを作成します。
このデータをどう2次元座標データにするかという問題には、wikipediaに答えがあります。
以下計算式により、3次元のa,b,cデータをデカルト座標にプロットできます。*1
TableauでX, Yのメジャーを以下のとおり作成します。
/// X (1/2) * ( (2*[B:15-64]+[C:65]) / ([A:-15]+[B:15-64]+[C:65]) )
///Y (SQRT(3)/2) * ( [C:65] / ([A:-15]+[B:15-64]+[C:65]) )
あとはX, Yのメジャーを行列に配置し、 詳細に市町村名を配置、適当に都道府県等のディメンションで色分け、pointの大きさを人口にしてみます。
X,Yの軸の範囲は0~1に固定しておきましょう。 また、レポートの背景色・罫線などの情報は削除しておきます。
別にダッシュボードを作成、 背景に上記wikipediaで公開されているTernary Plotの画像を適当に拝借しましょう。
設置した背景の上に作成したレポートを浮動オブジェクトで合わせます。
これで完成、全国市区町村の年齢3階級別構成比を2次元のTernary Plotで表現できました。
Public Garrary上の動かせるデータはこちらです。
appendix
正直、市区町村年齢構成の大勢はそこまで変わりませんので、
DataViz作品としては微妙でしたね。
もう少し時系列データで遷移を見たりすると面白いかもしれません。
3次元かつ、それぞれの軸が百分率で表現できる指標にすると、こちらのVizで表現できます。
機会があったら他の例もつくってみたいと思います。
商品購買のアソシエーションルールをネットワークで可視化する
アソシエーション分析の概略
アソシエーション分析は、商品の何と何が一緒に買われやすいのか?を示すための分析手法です。
「アソシエーション分析」とか「アソシエーションルール」とかをググると大量の記事が出てきますので、詳細はそちらの記事を参考にしてください。*1
以下、本記事中で重要になる点だけ記載します。
支持度(support)
総購買ユーザーNのうち、商品Aと商品Bを同時に買っている人の割合です。
信頼度(confidence)
商品Aを買った人のうち、商品Bを購入した人の割合です。
リフト(lift)
商品Aを買った人のうち商品Bを購入する人の割合(信頼度)が、
そもそも総購買ユーザーNにおける商品Bの購入率より高いか低いか、を表します。
一般的には、ある程度の支持度がある購入パターンのみで線引きし、リフト値を見て商品ごとの連関強弱を計ります。
今回の目的は、アソシエーションルールをネットワークで可視化し、商品ごとの連関を分かりやすく表現できるか検証します。
ネットワークは、Pythonのnetworkxを利用し、Tableauで描写することにします。
SQLによるデータ抽出
自身のお仕事にも活かせるよう購買データを使います。
postgresqlが提供してくれているDVDレンタルのサンプルデータを使用することにします。
ただし、バスケット(同レシート内購買)単位での分析は難しいので、ユーザー単位で集計することとします。
サンプルデータとER図はここで確認できます。
これを自身のDB環境に入れます。
以下、SQLで上記指標に必要なA∩B
, A
, B
, N
を集計します。*2
with item as ( select inventory_id , title , name from --- 中略------------------------------------------ inner join( select tran.title , count (distinct customer_id) as "B" from tran group by tran.title ) as target_table on fromto.target_item = target_table.title ;
※正直汚いSQLです。すみません。
気になる方は以下GitHubをご確認いただければと思います。
こんな感じのテーブルに仕上がりました。
ここから、support, confidence, liftの算出とネットワーク座標の生成はPythonに渡します。
Python・networkxによる node座標データの作成
ここは、先般のブログどおり、netowrokxでTableauに取り込むテーブルデータを準備します。
まず、support , confidence , lift を計算します。
さらにAandB
の出現UUが少ない組み合わせは除外してしまいましょう。
import pandas as pd edge_df = pd.read_csv("output.csv") # 以下、support , confidence , liftを計算します。 edge_df["support"] = edge_df["AandB"] / edge_df["N"] edge_df["confidence"] = edge_df["AandB"] / edge_df["A"] edge_df["lift"] = edge_df["confidence"] / ( edge_df["B"] / edge_df["N"] ) # supportが低い組み合わせを除外します。 edge_df = edge_df[edge_df["AandB"]>3] display(edge_df) print(edge_df.shape)
本来はconfidenceとliftの両方を考察すべきですが、
一旦liftだけをweightとしてみました。
edge_df_lift = edge_df[["source_item","target_item","confidence"]] col_name = ["source", "target","weight"] edge_df_lift.columns = col_name import networkx as nx def make_network(df): G = nx.from_pandas_edgelist(df,edge_attr=True) pos = nx.spring_layout(G) edges = G.edges() weights = [G[u][v]['weight'] for u,v in edges] nx.draw(G, pos, edges=edges, width=weights, node_size=10, node_color="c",with_labels=False) node = [] x = [] y = [] for k,v in pos.items(): node.append(k) x.append(v[0]) y.append(v[1]) node_df=pd.DataFrame({ "item":node, "X":x, "Y":y }) return node_df node_df = make_network(edge_df_lift)
・・・一応netowrokxでの画像出力していますが、完全に意味不明な感じになっています。
結果が見える戦いをするのはつらいですが、Tableau化まで以前と同じ手順で進めます。
result_df_1 = pd.merge(edge_df_lift,node_df,how="left",left_on="source",right_on="item") result_df_2 = pd.merge(edge_df_lift,node_df,how="left",left_on="target",right_on="item") result_df = pd.concat([result_df_1, result_df_2]) result_df["edge_name"] = result_df["source"] + "_" + result_df["target"]
Tableau上での可視化
手順は上にあげた過去記事とおりですので省略します。
なんとなく、lift(weight)が明らかに高い組み合わせもありますが、全体のネットワークの傾向としては解釈が難しいですね。
networkx側でもう少し手を加えるべきなのでしょうか・・・?
そもそも購買データをネットワークグラフにするのが適切ではない・・・?
あるいはサンプルデータだからランダマイズされてるとか・・・?
技術・知識的な未熟さが原因か、そもそもデータの話かは検証する余地がありそうですが、 面白い試みだったかなぁと思います。
【随時更新】誰にも教えたくないBIダッシュボードデザインに便利なサイト集を晒す
デザイン・分析アイデア
From data to Viz | Find the graphic you need
デザイン素材
配色ツール
https://color.adobe.com/ja/create/color-wheel/color.adobe.com
データ
https://archive.ics.uci.edu/ml/index.phparchive.ics.uci.edu
appendix
気になったものなど、随時更新していきます。
ネットワークグラフをつくるためのTableauとPython
Tableauでネットワークグラフを可視化しようとすると、座標データをどう用意するかが一番ネックになると思います。
現状、Tableau内でネットワークグラフを自動生成する機能は無さそうです。
ので、この辺の処理はPythonを噛ませると楽にできるので、ちゃんとできるか試行します。
networkxによる処理
そもそもnetworkxを使って完結しちゃえばいいじゃん、という話ではありますが、
TableauはじめBIプラットフォーム上で表現できれば色々使用用途が高いです。
まずはリファレンスに従い、乱数を固定しておいたほうが良さそうです。
import random random.seed(246) import numpy numpy.random.seed(4812)
pandas.DataFrame
で以下のようなサンプルデータを用意。
import pandas as pd edge_df = pd.DataFrame({ "source":["A","B","B","C","A","C","C","A","B","F","E","A","H"], "target":["B","C","D","D","E","E","F","G","G","G","H","I","I"], "weight":[0.6,0.1,0.2,0.9,0.8,0.7,0.5,0.3,0.8,0.1,0.7,0.4,0.8] })
networkx
を使用して、任意のアルゴリズムによるノードの座標を取得しておきます。
import networkx as nx G = nx.from_pandas_edgelist(edge_df,edge_attr=True) pos = nx.spring_layout(G)
この座標情報をテーブル化してTableauに読ませることになります。
なお、普通に描写するとこんな感じ。
edges = G.edges() weights = [G[u][v]['weight'] for u,v in edges] nx.draw(G, pos, edges=edges, width=weights, node_size=400, node_color="c",with_labels=True,font_weight="bold")
エッジのweight以外も属性をつけることが可能です。
その場合、上記の例ではinput_dfに別カラムをつけ、edge_attr=True
をしておけばOK。
これと同じネットワークグラフをTableauで描写するのが目的です。
pos
はdict型なので、テーブル化しておきます。
print(type(pos)) print(pos) >>> <class 'dict'> >>> {'A': array([ 0.05494571, -0.43277963]), 'B': array([0.38390294, 0.05184413]), 'C': array([-0.08115845, 0.52158239]), 'D': array([-0.08585107, 0.92455717]), 'E': array([-0.38630969, -0.13289213]), 'F': array([0.5411944 , 0.85869962]), 'G': array([ 0.75986786, -0.13710168]), 'H': array([-0.73922077, -0.65390988]), 'I': array([-0.44737093, -1. ])}
import pandas as pd node = [] x = [] y = [] for k,v in nodePos.items(): node.append(k) x.append(v[0]) y.append(v[1]) node_df=pd.DataFrame({ "item":node, "X":x, "Y":y })
作成したノードの座標情報データnode_df
と、
最初につくったエッジの情報データedge_df
をTableauへ送り込む用に加工します。
result_df_1 = pd.merge(edge_df,node_df,how="left",left_on="source",right_on="item") result_df_2 = pd.merge(edge_df,node_df,how="left",left_on="target",right_on="item") result_df = pd.concat([result_df_1, result_df_2]) result_df["edge_name"] = result_df["source"] + "_" + result_df["target"]
edge_df
を縦積みにして、source
,target
それぞれのX座標,Y座標をjoinします。
おまけにfrom-toを表すedge_name
をつけておきます。
よーし、準備OK!
result_df
をTableauに持っていくぞー。
Tableauによる表現
まずはX,Y座標によるscatter plotにして二重軸にします。
X,Y座標のメジャーを「合計」にしないように注意。
「平均」とか「最大」とかを選びましょう。
1つめの軸はディメンションのedge_name
を詳細にドラッグ(item
よりも上の階層)してマークの種類は「線」、
edgeの太さや色はweight
でお好きに加工。
edgeの完成です。
2つめの軸のマークは「点」、詳細はitem
だけでOKで、適当にラベルとか大きさを調整します。
これでnodeの完成。
あとは二重軸を同期して完成です~
無事、networkxと同じ描写ができましたね。
BIに載せることができると、表示範囲のフィルタリング等がしやすいので重宝しそうです。
データも最低限source, targetの情報さえあれば描写できちゃいますしね。
Python の progress bar いろいろ
プログレスバーなんてtqdm一択じゃね?
という結論で落ち着く話ではありそうですが、
なんとなく、「もっとライブラリの種類あるのかなぁ?」と思って調べてみました。
環境はgoogle colabです。
tqdm
たぶん誰もが使ったことがあるおなじみtqdm
from tqdm import tqdm for i in tqdm(range(100)): time.sleep(0.1)
※たまにこんな感じで改行されるケースがあり、イラっとします。
改行コードの関係みたいですけど。
stackoverflowにて解決済みではありますが、jupyterでは
tqdm.notebook
で回避することができるようです。
from tqdm.notebook import tqdm for i in tqdm(range(100)): time.sleep(0.1)
ちょっとデザイン変わっちゃいますね。
fastprogress
fastprogress
っていうライブラリもあるみたいです。
from fastprogress.fastprogress import progress_bar for i in progress_bar(range(100)): time.sleep(0.1)
tqdm.notebookとほとんど一緒な件。 目盛り線がオシャレポイントか。
progressbar2
progressbar2 。
デフォルトはいたってシンプルですな。
import progressbar for i in progressbar.progressbar(range(100)): time.sleep(0.1)
結論
好きなのを使えばよろしいいかな、と思います。
見た目もいろいろ設定できそうだし。
おまけ
※ tqdm_gui
を使ってみたかったけどcolab環境だとうまくいかず。
きっとテクニックがあるんだろうな。
IFTTTでGoogleスプレッドシートに接続、Tableau Publicで可視化、自動更新する
タイトルのとおり、今回のアーキテクチャはこんな感じです。
超シンプル!
自分のandroidの電源プラグ抜き差しの情報を IFTTT 経由で Googleスプレッドシート に流し、
さらに Tableau Public の Googleスプレッドシートコネクタで情報取得、Publicギャラリー上で更新・可視化できるようにするものです。
なぜ充電状況なのか
便利なIFTTTのAppletsがあったから(後述)。
メインの目的はTableau PublicのGoogleスプレッドシートの接続確認です。
無料でデータ自動更新できるの、めちゃくちゃいいよね、という話。
IFTTT
たぶん3年ぶりぐらいに使いました。
Power Automateが間違いないんですが、お手軽なのはこっちかな、と思ったので。
久々の訪問、UIもだいぶ変わっていて(?*1)ワクワクします。
とりあえずandroidにアプリをインストール。
で、使うのは定型フォーマットがあるこのApplets
Plug in と Unpluggedをそれぞれポチる。
Google Driveの認証とかをくぐりますが、基本は定型のまま何もいじらなくて大丈夫なはずです。 Googleスプレッドシートも用意不要(もしない場合、勝手に作ってくれるので優秀)
2つのAppletが無事Connectedになれば準備完了。
(Appletが走るまで数分まつ)
で、電源抜き差しすると・・・
完璧!
ここまで約10分、IFTTTまだまだオワコンじゃないぞ!
Tableau
今回の主目的はIFTTTではなくこちらです。 Tableau Public の Googleスプレッドシートコネクタが運用できそうか試します。
Tableau Public 開いて さっきのGoogleスプレッドシートを選択。
適当にいろいろ認証くぐると無事にデータ接続できました。
※なぜかデータソースのテーブルは更新されないなど、挙動がイマイチ理解できていない部分もあります。今後いろいろ調べる。
普通にPublishしてもちゃんとGoogleスプレッドシートに接続されて、更新されてます。
やったぜ!
Vizは気が向いたらちゃんとデザインするかもしれませんがとりあえずこれでいいやー。
Tableau Public & Google スプレッドシートはかなり利用価値が高そうでした。
*1:覚えてないだけかも