pandas×plotlyで楽々可視化

# はじめに
```py
import pandas as pd
pd.options.plotting.backend = "plotly"
```
とするだけで

```py
# データ読み込み
df = pd.read_csv("file_path")

df.plot.hist(...) # ヒストグラム
# df.plot.bar(...)
# df.plot.scatter(...)
# df.plot.line(...)
```
など様々なグラフが綺麗にサクッと書ける！ というお話です。
[Pandas Plotting Backend in Python](https://plotly.com/python/pandas-backend/)


各種グラフの書き方の紹介になるため、
分析として無意味なグラフがあることもご容赦くださいませ。


# 使用ライブラリ
google colabの環境を想定しております。
!pip install -U plotly pandas => ランタイム再起動が必須です

```py
import numpy as np
import pandas as pd
pd.options.display.max_rows = 100
pd.options.display.max_colwidth = 100
pd.options.display.max_columns = 50
pd.options.display.unicode.east_asian_width = True
pd.options.display.float_format = "{:.2f}".format # 小数点第2位まで
pd.options.plotting.backend = "plotly"

# 対応してないチャートの際に使います
# import plotly.express as px
# import plotly.figure_factory as ff
```

# 使用データセット
[UCI Bike Sharing Dataset Data Set](http://archive.ics.uci.edu/ml/datasets/Bike+Sharing+Dataset)
バイクシェアリングサービスの日次集計データ

```bash
# サイトからデータセットダウンロード
!wget http://archive.ics.uci.edu/ml/machine-learning-databases/00275/Bike-Sharing-Dataset.zip
!unzip Bike-Sharing-Dataset.zip
```

```py
df = pd.read_csv("./day.csv", parse_dates=["dteday"])
df.drop(columns=["yr", "month"], inplace=True)
df["season"] = df.season.map({1: "冬", 2: "春", 3: "夏", 4: "秋"})
df["holiday"] = df.holiday.map({0: "平日", 1: "休日"})
df["weekday"] = df.weekday.map({0: "月曜日", 1: "火曜日", 2: "水曜日", 3: "木曜日", 4: "金曜日", 5: "土曜日", 6: "日曜日"})
df["weathersit"] = df.weathersit.map({1: "晴れ", 2: "曇り", 3: "小雨", 4: "大雨"})
df.head()
```
![スクリーンショット 2021-10-19 13.15.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/86072d6a-3222-ccdc-4c11-be9bd38170be.png)

私も自転車シェアリング使ったことありますが結構便利なんですよね。 
100円~200円で2駅先ぐらいまで行けちゃいます！　


# 各種チャート
[plotly Tutorial](https://plotly.com/python/) 各チャートのサンプルコードなど載ってます
[plotly Documentation](https://plotly.github.io/plotly.py-docs/generated/plotly.express.html#module-plotly.express) 各チャートの引数などが載ってます
## ヒストグラム
```python
df.plot.hist(x="cnt")
# df.cnt.plot.hist() も同じ
# df.plot(x="cnt", kind="hist") も同じ
```
![newplot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/972414fa-f09c-c49d-b92a-0f05ae0cb403.png)

カテゴリでも可能です

```py
df.weathersit.plot.hist()
# df.weathersit.value_counts().plot.bar() 同じ
```
![newplot (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/c1f55029-3bdd-a12d-760f-83b22d1d5ca0.png)

カテゴリごとに色分けできます

```py
# barmodeにはstack, overlayなども指定可能
df.plot.hist(x="cnt", color="weathersit", barmode="group")
```
![newplot (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/bd12d08b-e412-0d03-948f-bb11dd493e7c.png)

## 棒グラフ
```py
df.plot.bar(x="dteday", y="cnt")
# ↓でも同じ。indexは自動的にx軸へ
# df.set_index("dteday").plot.bar(y="cnt")
```
![newplot (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/f0309197-63f3-2b31-f145-61be4e42dd07.png)

集計した後にそのまま可視化できます

```py
df.set_index("dteday").resample("M").cnt.sum().plot.bar()
```
![newplot (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/f3e4b33f-982f-a9a9-e0e0-fef46a6abc68.png)

集計した後に色分けできます(季節で色付けする意味はないですが)

```py
df.set_index("dteday").resample("M").agg({"cnt": "sum", "season": "max"})\
.plot.bar(y="cnt", color="season")
```
![スクリーンショット 2021-10-19 13.19.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/81c5ae22-cfab-c653-6b73-10ec6be036c2.png)

横持ちだと楽です

```py
# 新規ユーザー, 既存ユーザーごと
df.set_index("dteday").resample("M")[["casual", "registered"]].sum()\
.plot.bar(barmode="group") # y=["casual", "registered"]は無くてもOK!
```

![スクリーンショット 2021-10-19 11.15.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/6af30488-0531-4ec2-7a80-a3f97698d281.png)

縦持ちの場合少し面倒です

```py
df_tate = df.melt(
    id_vars=['instant','dteday', 'season', 'holiday', 'weekday',
                'workingday', 'weathersit', 'temp', 'atemp', 'hum', 'windspeed'],
    value_vars=["casual", "registered"],
    var_name="userkind",
    value_name="count").sort_values(by=["dteday", "userkind"])

df_tate.head()
```
![スクリーンショット 2021-10-19 11.16.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/a1817b08-d1ac-03f2-a08e-8d874f435924.png)

```py
# 他に良い方法ありそうです。
df_tate.groupby("userkind").apply(lambda g: g.set_index("dteday").resample("M").agg({"count": "mean"})) \
.reset_index("userkind").plot.bar(color="userkind", barmode="group")
```
![スクリーンショット 2021-10-19 13.28.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/8c0b5c92-f2b2-c836-4336-19b23e79728f.png)

水平にしたい場合(変数重要度でよくみるチャート)

```py
df.season.value_counts().plot.barh()
```
![スクリーンショット 2021-10-19 12.34.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/4c6fea2d-ea17-3b0b-fde1-bb074b9b4860.png)

## 散布図
```py
df.plot.scatter(x="temp", y="cnt")
# 濃淡を見たい場合はopacityを設定
# df.plot.scatter(x="temp", y="cnt", opacity=0.2)
```
![スクリーンショット 2021-10-19 11.36.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/7cdd1c69-afad-2125-5340-767f272e2a29.png)

カテゴリごとに色分けできます

```py
df.plot.scatter(x="temp", y="cnt", color="season")
```
![スクリーンショット 2021-10-19 11.44.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/334255fc-3574-72d9-fd68-61b872819e2e.png)

## ヒートマップ
```py
# 相関行列
df.corr().round(3).plot(kind="imshow")
```
![スクリーンショット 2021-10-25 8.08.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/80af2c04-261e-265f-6acb-daeabad2908f.png)

アノテーションが欲しい場合は`df.plot()`が使えないため, plotlyのライブラリを直接使います。


```py
import plotly.figure_factory as ff
# 相関行列
corr_df = df.corr().round(3)
x_cols = corr_df.index.to_list()
y_cols = corr_df.columns.to_list()
ff.create_annotated_heatmap(corr_df.values, x=x_cols, y=y_cols, colorscale='Greys')
```
![スクリーンショット 2021-10-25 7.58.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/4199f8a1-49b8-05ca-1925-04ba8da9f84b.png)


## 箱ひげ図
```py
df.cnt.plot.box()
```
![スクリーンショット 2021-10-19 11.46.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/16fd8fa8-8fce-298b-bd09-34365507b51c.png)

カテゴリごとに分けれます

```py
df.plot.box(x="season", y="cnt")
```
![スクリーンショット 2021-10-19 11.47.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/be3e1e98-92ef-8138-a439-10885fa8b604.png)

## バイオリンプロット
df.plot.violinが無いのでdf.plot(kind="種類")で指定します

```py
df.plot(x="season", y="cnt", kind="violin", color="season")
```
![スクリーンショット 2021-10-25 7.38.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/3bd923a0-32b2-c02b-01ad-93ed31265280.png)


## 線グラフ
```py
df.plot.line(x="dteday", y="cnt")
```
![スクリーンショット 2021-10-19 11.48.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/34bf35d2-7db6-89ca-08b9-173b35257d54.png)

横持ちなら楽に分けれます

```py
df.set_index("dteday").plot.line(y=["casual", "registered"])
```
![スクリーンショット 2021-10-19 11.48.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/12dd1ec0-3284-7a12-8569-f3faaadf2e96.png)

30日移動平均を計算後そのまま可視化できます

```py
df.set_index("dteday")[["casual", "registered"]].rolling(window=30, center=True).mean().plot.line()
```
![スクリーンショット 2021-10-19 12.09.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/66eb6a48-4ef7-84dc-973e-e62ca73bd3e6.png)

## 円グラフ
`df.plot.pie(x="weekday", y="cnt")`がまだ対応して無いです。。(使用頻度少ないので大丈夫そうですが)

```py
import plotly.express as px
px.pie(df, values="cnt", names="weekday")
```
![スクリーンショット 2021-10-25 8.28.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/bbec6397-e0dd-b56d-1406-3d75978426d1.png)

## 少し綺麗に見せたい
```py
df.groupby("weekday").cnt.sum().sort_values().plot.barh()
```
![スクリーンショット 2021-10-26 11.34.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/03c8440f-7cd9-c121-99e7-e1ba58b94357.png)

タイトルやラベルを変えたり、値をアノテーションできます

```py
df.groupby("weekday").cnt.sum().sort_values().plot.barh(
    title="曜日ごとのレンタル合計数",
    labels={"value": "レンタル数", "weekday": "曜日"},
    text="value")
```
![スクリーンショット 2021-10-26 11.36.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225073/c9b8bce5-fa76-4de0-811d-6676c6207f75.png)

# さいごに
他のチャートも次第随時更新していきたいと思います。
「こういう書き方あるよ！」「こういうグラフもあるよ！」などアドバイス頂けるととても嬉しいです！！

見ていただきありがとうございました！