Azureデータ分析入門 #3 【ツール比較  Azure Notebook編】

## はじめに
前回行ったExcelでの簡易集計と可視化を、**Azure Notebooks**でやってみます。

#### 連載目次
[Azureデータ分析入門 #1 【はじめに】](https://qiita.com/Catetin0310/items/a7ab83069fec5352b535)
[Azureデータ分析入門 #2 【ツール比較 Excel編】](https://qiita.com/Catetin0310/items/d32c53305ab579d47950)
[Azureデータ分析入門 #3 【ツール比較 Azure Notebook編】](https://qiita.com/Catetin0310/items/ae3c5f3dca5b3315896d) → 本記事はこちら
[Azureデータ分析入門 #4 【ツール比較 Databricks編】](https://qiita.com/Catetin0310/items/b6030d3ad0fde16e57ab)
[Azureデータ分析入門 #5 【Databricks → Power BI Desktop】](https://qiita.com/Catetin0310/items/eb8431f38a51641b0db1)
[Azureデータ分析入門 #6 【CSVデータ → Power BI サービス】](https://qiita.com/Catetin0310/items/4af00df1f0af5feda1bb)
Azureデータ分析入門 #7 【AutoML でタイタニック号の生存者予測】


## Azure Notebooksとは？
### 概要
データ分析プラットフォームのデファクトスタンダード、**Jupyter Notebook**をクラウド環境で起動できる**Azure**サービスです。他にはGoogle Colaboratoryが有名ですね。

ローカルでJupyter Notebookを使う場合、環境構築でつまづくこともしばしば。クラウドであればそのあたりほんと楽です。

- 数ステップでAzure上に環境設定可能
- クラウド上で共同作業可能
- メモリ4GB, ストレージ1GBまで無償

Notebookはデータサイエンティストやアナリスト専用のものではありません。

分析に都合のいいプラットフォームがそろってて、メモ書きが残せて、みんなとシェアできる、いい感じに使いやすい **"ノート"** だと考えて、身構えずに触ってみましょう。

### インストール
まずはAzure Notebookをセットアップします。 手順は[**こちら**](https://qiita.com/Catetin0310/items/2f07e10f056e88e25f5b)。Microsoftアカウントがあればすぐに数ステップでできます。

### 操作のきほん
初めてNotebookに触れる人のために、基本操作とショートカットをご紹介します。

セルを選択、コード入力後、```Shift + Enter```でそのセルのコードを実行できます。

![00.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/b6c05dff-46b1-c272-c558-9041ac59c22c.gif)

セルの中を選択すると、枠が<font color='limegreen'>緑色</font>になり<font color='limegreen'>Edit Mode</font>に、セルの外を選択すると、枠が<font color='DodgerBlue'>水色</font>になり<font color='DodgerBlue'>Command Mode</font>になります。

![01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/1fb9610c-d104-0272-30de-993f390aa06d.gif)


モード切り替えは、```esc```と```enter```でも可能。

![02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/c50bee66-4e64-2caf-5461-510aa9982a1f.gif)


<font color='DodgerBlue'>Command Mode</font>で、```m```を押すとセルを```Markdown```モードに、```y```を押すと```code```モードにできます。

![03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/34b2b610-1611-7a18-a298-aec6b4b1c5be.gif)


これでMarkdownのメモが残せます。
![04.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/762f24d4-7b7b-474d-4d3f-12faa60f0422.gif)


<font color='DodgerBlue'>Command Mode</font>で```a```を押せば上に、```b```を押せば下にセルを追加可能。```x```で削除。
![05.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/4fb57616-f86e-4b40-0278-e7f255d8baf0.gif)



<font color='DodgerBlue'>Command Mode</font>時に、上下カーソルでセルを移動できます。
編集したいセルで```enter```を押せば、対象セルの<font color='limegreen'>Edit Mode</font>に遷移。
![06.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/27906343-9581-1199-15fd-c8f90a7c5fb1.gif)


作業をチェックポイントとして保存したいときは、```ctrl + s```を押します。これでいつでもそのポイントに戻れます。
![07.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/63179702-b4a8-c394-f719-aba753c3beaa.gif)



特定のセルだけ実行されないようにしておきたいな、という時は```ctrl + /``` でコメントアウトしておきます。
![08.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/74f1dd30-4efd-0d65-b93a-5ddcd4fa14d2.gif)


他にもショートカットはたくさんあります。一覧表はHelpを参照しましょう。
![09.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/d15ad9d4-6834-95bb-c892-557a08e5a9b1.gif)

あとは触りながら覚えていけばOK。

## 手順
#### 使用するデータのインポート
[Brazilian E-Commerce Public Dataset by Olist](https://www.kaggle.com/olistbr/brazilian-ecommerce)から、データをダウンロード、解凍しておきます。![2019-09-11_15h08_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/4d13c7c5-8e5d-0459-7733-621ca86d615a.png)

Azure Notebook を立ち上げ、作成した Notebook と同じディレクトリで、```Upload```タブの```From Computer```を選択
![2019-09-11_15h11_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/c73f125a-36df-1474-0a36-dbda3dd0b755.png)

以下の画面に遷移するので、解凍先のフォルダにあるCSVデータを、ドラッグアンドドロップ。
![2019-09-11_15h23_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/ffada5eb-a7ee-f6ad-28be-6b1f3dedd563.png)

Uploadを押して、しばらく待ちます。Notebookと同じディレクトリにCSVファイルがアップロードされてれば完了です。
![2019-09-11_15h23_58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/ab37e6f9-1937-2c9d-6e7b-d0bae101eeaa.png)



データの操作の定番といえば Pandas ですが、~~興味本位で~~ **Databricks**との比較してみたいので、並列分散処理フレームワークである **PySpark** を用いて中間テーブルを作成します。そこからSQLで必要な集計処理を行い、最後に可視化のためのライブラリを使って、グラフを描画する、という流れで集計・可視化を行います。

#### PySpark の準備
まずはPySpark関連のライブラリをインポート。

```python
from pyspark.sql import SparkSession, SQLContext
from pyspark.sql.functions import col, desc, to_timestamp, month, year, dayofweek, hour
from pyspark.sql.types import DoubleType
import pyspark
```

次に、Sparkのコンストラクタの作成。
正直言ってこのコードが何をしているのか良くわかっていないのですが、このコンストラクタが後述のスクリプトを良しなに処理してくれるようです。


```python
sc = pyspark.SparkContext.getOrCreate()
sql = SQLContext(sc)

spark = SparkSession \
    .builder \
    .appName("Python Spark SQL basic example") \
    .config("spark.some.config.option", "some-value") \
    .getOrCreate()
```

#### CSV ファイルの読み込み
アップロードしたCSVファイル名を変数に放り込んでおきます。

```python
order_item = "olist_order_items_dataset.csv"
products = "olist_products_dataset.csv"
translation = "product_category_name_translation.csv"
```

CSVファイルをSparkに読み込ませます。上から、売上データ、製品データ、翻訳データ。ちょっと時間がかかります。

```python
t1 = spark.read\
    .format("com.databricks.spark.csv")\
    .option("header", "true")\
    .load(order_item)\

t2 = spark.read\
    .format("com.databricks.spark.csv")\
    .option("header", "true")\
    .load(products)\

t3 = spark.read\
    .format("com.databricks.spark.csv")\
    .option("header", "true")\
    .load(translation)\
```

よみこんだCSVの情報は、列名 ```<Sparkフレーム名>.printSchema()``` で確認できます。時系列データが文字列になっているので、timestamp 型に変更します。また、キーとなるカラム名は、別名を設定しておきます。

```python
t1 = t1.withColumn('time', to_timestamp(t1.shipping_limit_date, 'yyyy/MM/dd HH:mm'))
t2 = t2.withColumnRenamed('product_id', 'product_id2')
t3 = t3.withColumnRenamed('product_category_name', 'product_category_name2')
```

各Sparkフレームのスキーマを表示させ、列名を確認。

```python
t1.printSchema()
t2.printSchema()
t3.printSchema()
```


#### フレームの結合と可視化用テーブル作成
三つのSparkフレームを結合して、一時的な中間テーブルを作成します。

```python
table_name = 'sql_tbl'

t1.join(t2, t1.product_id == t2.product_id2, 'inner')\
.join(t3, t2.product_category_name == t3.product_category_name2, 'inner')\
.withColumn('time', to_timestamp(t1.shipping_limit_date, 'yyyy/MM/dd HH:mm'))\
.withColumn('price', t1['price'].cast('double'))\
.withColumn('freight_value', t1['freight_value'].cast('double'))\
.createOrReplaceTempView(table_name)
```
この中間テーブルに対して、以下のようにクエリを発行できます。

```python
spark.sql('''
SELECT * FROM sql_tbl limit 10
''').show()
```

集計用のクエリで集計し、その結果を可視化しますが、クエリ自体がちょっと長くなり、見通しが悪くなるので、変数に入れておきます。

```python
query = '''
SELECT
    product_category_name_english as cat_name
    , count(order_id) as cnt
    , sum(price) as price_ttl
    , sum(freight_value)/(sum(freight_value) + sum(price)) as frt_comp_ratio
    , avg(price) as price_ave
FROM
    sql_tbl
GROUP BY
    product_category_name_english
ORDER BY
    price_ttl
DESC
LIMIT 10
'''
```

クエリの結果を pandas のデータフレームに入れなおし、平均単価の高い順に並べ替えます。

```python
df = spark.sql(query).toPandas().sort_values('price_ave', ascending=False)
```

#### matplotlib で可視化
可視化のためのライブラリ群をインポート。

```python
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import seaborn as sns
```

グラフを描画します。

```python
graph_name = 'Average Unit Price and Freight Cost Ratio of Top 10 Category'

# グラフの軸指定
x = df['cat_name']
y2 = df['frt_comp_ratio']
y1 = df['price_ave']

# グラフの見た目スタイル
plt.style.use('ggplot')

# グラフ形式
fig, ax2 = plt.subplots(figsize=(5, 5))
plt.xticks(rotation='90', fontsize=8)
plt.yticks(fontsize=8)
ax1 = ax2.twinx()
plt.yticks(fontsize=8)

ax1.plot(x, y2, linewidth=2, color="orange", linestyle="solid", marker="o", markersize=4, label='Freight Cost / (Freight Cost + Unit Price)')
ax2.bar(x, y1, label='Average Unit Price', color='blue', width=0.4)
 
#y軸範囲
ax1.set_ylim([0,0.3])
ax2.set_ylim([0,300])
 
#凡例
ax1.legend(bbox_to_anchor=(0, 1.00), loc='upper left', borderaxespad=0.5, fontsize=8)
ax2.legend(bbox_to_anchor=(0, 0.93), loc='upper left', borderaxespad=0.5, fontsize=8)
 
#グリッド
ax2.grid(True)
 
#軸ラベルを表示
plt.xlabel('X-Axis')
ax1.set_ylabel('frt_comp_ratio', fontsize=8)
ax2.set_ylabel('price_ave', fontsize=8)

plt.title(graph_name, fontsize=8)
plt.savefig(graph_name, bbox_inches='tight', dpi=300)
```

このようなグラフが出力できました。
![Average Unit Price and Freight Cost Ratio of Top 10 Category.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/ad47e67b-fd55-71d0-4d97-ab8ca2185a3c.png)



## まとめ
#### pros
- ビジネスロジックが埋もれにくい
    - どの処理をどんな順番で行うのか明確になる
    - Markdownでメモ書きも残せて第三者にもフレンドリー

- 意外と習得コストが低い
    - 今回はPySparkを使ったので参考資料は少ないものの、pandasであれば、たくさんの参考資料あり
    - SQLも然り
 
- 環境構築が簡単
    - クラウドのNotebookの最大の利点
    - 違うPCでもアカウントにログインさえできれば同じように動作する


#### cons
- **バージョン管理が大変**
    - チェックポイントを設けることはできますが、コードを書きたいときにわざわざこれをやるか、というと私はやりません。ちょっと面倒ですがコメントアウトで対応することが多いです。

- **可視化に要する工数が大きい**
    - グラフの成型には結構な手間がかかります。今回はカテゴリの選定なので本来はそこまで凝ったグラフは必要ないのですが、ついいろいろ手を出してしまい、時間を費やしてしまいました(自戒)

#### おわりに
Azure Notebooksはすごく便利ですが、Jupyter Notebookをそのままクラウドに持ってきたというコンセプトなので、運用という意味では課題がいくつかあるように感じられます。次回は**Databricks**でやってみます。お楽しみに！

## 参考サイト
[Kaggle.com](https://www.kaggle.com/)
[Brazilian E-Commerce Public Dataset by Olist](https://www.kaggle.com/olistbr/brazilian-ecommerce)
[Class SparkContext](
https://spark.apache.org/docs/2.3.0/api/java/org/apache/spark/SparkContext.html)