はじめに
前回行ったExcelでの簡易集計と可視化を、Azure Notebooksでやってみます。
連載目次
Azureデータ分析入門 #1 【はじめに】
Azureデータ分析入門 #2 【ツール比較 Excel編】
Azureデータ分析入門 #3 【ツール比較 Azure Notebook編】 → 本記事はこちら
Azureデータ分析入門 #4 【ツール比較 Databricks編】
Azureデータ分析入門 #5 【Databricks → Power BI Desktop】
Azureデータ分析入門 #6 【CSVデータ → Power BI サービス】
Azureデータ分析入門 #7 【AutoML でタイタニック号の生存者予測】
Azure Notebooksとは?
概要
データ分析プラットフォームのデファクトスタンダード、Jupyter Notebookをクラウド環境で起動できるAzureサービスです。他にはGoogle Colaboratoryが有名ですね。
ローカルでJupyter Notebookを使う場合、環境構築でつまづくこともしばしば。クラウドであればそのあたりほんと楽です。
- 数ステップでAzure上に環境設定可能
- クラウド上で共同作業可能
- メモリ4GB, ストレージ1GBまで無償
Notebookはデータサイエンティストやアナリスト専用のものではありません。
分析に都合のいいプラットフォームがそろってて、メモ書きが残せて、みんなとシェアできる、いい感じに使いやすい "ノート" だと考えて、身構えずに触ってみましょう。
インストール
まずはAzure Notebookをセットアップします。 手順はこちら。Microsoftアカウントがあればすぐに数ステップでできます。
操作のきほん
初めてNotebookに触れる人のために、基本操作とショートカットをご紹介します。
セルを選択、コード入力後、Shift + Enter
でそのセルのコードを実行できます。
セルの中を選択すると、枠が緑色になりEdit Modeに、セルの外を選択すると、枠が水色になりCommand Modeになります。
モード切り替えは、esc
とenter
でも可能。
Command Modeで、m
を押すとセルをMarkdown
モードに、y
を押すとcode
モードにできます。
Command Modeでa
を押せば上に、b
を押せば下にセルを追加可能。x
で削除。
Command Mode時に、上下カーソルでセルを移動できます。
編集したいセルでenter
を押せば、対象セルのEdit Modeに遷移。
作業をチェックポイントとして保存したいときは、ctrl + s
を押します。これでいつでもそのポイントに戻れます。
特定のセルだけ実行されないようにしておきたいな、という時はctrl + /
でコメントアウトしておきます。
他にもショートカットはたくさんあります。一覧表はHelpを参照しましょう。
あとは触りながら覚えていけばOK。
手順
使用するデータのインポート
Brazilian E-Commerce Public Dataset by Olistから、データをダウンロード、解凍しておきます。
Azure Notebook を立ち上げ、作成した Notebook と同じディレクトリで、Upload
タブのFrom Computer
を選択
以下の画面に遷移するので、解凍先のフォルダにあるCSVデータを、ドラッグアンドドロップ。
Uploadを押して、しばらく待ちます。Notebookと同じディレクトリにCSVファイルがアップロードされてれば完了です。
データの操作の定番といえば Pandas ですが、興味本位で Databricksとの比較してみたいので、並列分散処理フレームワークである PySpark を用いて中間テーブルを作成します。そこからSQLで必要な集計処理を行い、最後に可視化のためのライブラリを使って、グラフを描画する、という流れで集計・可視化を行います。
PySpark の準備
まずはPySpark関連のライブラリをインポート。
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のコンストラクタの作成。
正直言ってこのコードが何をしているのか良くわかっていないのですが、このコンストラクタが後述のスクリプトを良しなに処理してくれるようです。
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ファイル名を変数に放り込んでおきます。
order_item = "olist_order_items_dataset.csv"
products = "olist_products_dataset.csv"
translation = "product_category_name_translation.csv"
CSVファイルをSparkに読み込ませます。上から、売上データ、製品データ、翻訳データ。ちょっと時間がかかります。
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 型に変更します。また、キーとなるカラム名は、別名を設定しておきます。
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フレームのスキーマを表示させ、列名を確認。
t1.printSchema()
t2.printSchema()
t3.printSchema()
フレームの結合と可視化用テーブル作成
三つのSparkフレームを結合して、一時的な中間テーブルを作成します。
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)
この中間テーブルに対して、以下のようにクエリを発行できます。
spark.sql('''
SELECT * FROM sql_tbl limit 10
''').show()
集計用のクエリで集計し、その結果を可視化しますが、クエリ自体がちょっと長くなり、見通しが悪くなるので、変数に入れておきます。
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 のデータフレームに入れなおし、平均単価の高い順に並べ替えます。
df = spark.sql(query).toPandas().sort_values('price_ave', ascending=False)
matplotlib で可視化
可視化のためのライブラリ群をインポート。
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import seaborn as sns
グラフを描画します。
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)
まとめ
pros
-
ビジネスロジックが埋もれにくい
- どの処理をどんな順番で行うのか明確になる
- Markdownでメモ書きも残せて第三者にもフレンドリー
-
意外と習得コストが低い
- 今回はPySparkを使ったので参考資料は少ないものの、pandasであれば、たくさんの参考資料あり
- SQLも然り
-
環境構築が簡単
- クラウドのNotebookの最大の利点
- 違うPCでもアカウントにログインさえできれば同じように動作する
cons
-
バージョン管理が大変
- チェックポイントを設けることはできますが、コードを書きたいときにわざわざこれをやるか、というと私はやりません。ちょっと面倒ですがコメントアウトで対応することが多いです。
-
可視化に要する工数が大きい
- グラフの成型には結構な手間がかかります。今回はカテゴリの選定なので本来はそこまで凝ったグラフは必要ないのですが、ついいろいろ手を出してしまい、時間を費やしてしまいました(自戒)
おわりに
Azure Notebooksはすごく便利ですが、Jupyter Notebookをそのままクラウドに持ってきたというコンセプトなので、運用という意味では課題がいくつかあるように感じられます。次回はDatabricksでやってみます。お楽しみに!
参考サイト
Kaggle.com
Brazilian E-Commerce Public Dataset by Olist
Class SparkContext