昨今データの重要性が増しており、分析にグラフは欠かせないものとなっていますが
エクセルで打ち込んでグラフを作成するのもあまりかっこよくないですし、
実際の運用者がエンジニアではないことが多く、データ活用が進んでいないように感じます。
今回はCSVから入力されたデータからRuby on Railsのライブラリを利用して綺麗なグラフを出力してデータ分析する方法を考えて行きたいと思います。 将来的にどんなデータにも対応しうることを想定し、SQLに頼らないように作ってみたいと思います。
Gemを選択する
Railsではgemを利用することでグラフを簡単に出すことができます。 グラフを出力するGemはいくつかあるので、比較して行きたいと思います。
lazy_high_charts
Gemfileに以下を記載します。
gem 'lazy_high_charts'
bundle installします。
bundle install --path=vendor/bundle
application.js に以下を追加します。
//= require highcharts/highcharts //= require highcharts/highcharts-more
公式のRead.meには下記の記載もありますが、こちらを入れると Highcharts Error #16が発生します。 特に支障はないため外します。 highchartsはグラフにアニメーション効果を追加してくれます。*1
//= require highcharts/highstock
class HomeController < ApplicationController def index category = [1,3,5,7] current_quantity = [1000,20000,1500,18000] @graph = LazyHighCharts::HighChart.new('graph') do |f| f.title(text: '売上') f.xAxis(categories: category) f.series(name: '売上', data: current_quantity) end end end
chartkick
application.js に以下を追加します。
//= require chartkick
Controllerに追記します。
class HomeController < ApplicationController def index category = [1,3,5,7] current_quantity = [1000,20000,1500,18000] # Lazy_High_chart @lazegraph = LazyHighCharts::HighChart.new('graph') do |f| f.title(text: '売上') f.xAxis(categories: category) f.series(name: '売上', data: current_quantity) end # Chartkick @chartkickgraph = {"1": 1000,"3": 20000,"5": 1500,"7": 18000} end end
Viewは以下のように記載します。
<%= line_chart(@chartkickgraph, curve: false, label: "売り上げ", xtitle: "月", ytitle: "個数" ) %>
出力した結果です。
LazyHighChartsはデフォルトでHighChartsが使えますが、 Chartkickは別途インストールする必要があります。
微妙な差はありますが、個人的にChartkickが気に入ったので、 こちらを使って行くことにします。
CSVインポート
続いてCSVインポートを実装していきます。
Viewの実装
<%= line_chart @chartkickgraph , curve: false, label: "売り上げ", xtitle: "月", ytitle: "個数" %>
route.rb
post "/", to: 'home#index'
コントローラーの実装
class HomeController < ApplicationController require 'csv' def index file = params[:file] datas = [] unless file.nil? ActiveRecord::Base.transaction do CSV.foreach(file.path, headers: true) do |row| datas.append(Hash[row]) end end end @chartkickgraph = datas[0] end end
テスト用CSVを用意します。
カラム1, カラム2, カラム3, カラム4 1, 2, 3, 4
出力結果
簡単にかつ動きのあるグラフが作れましたが、 グラフを見てみると、ヘッダがそのまま下のメモリになっているようです。 これだとあまり実用性がないので、実用性ある形にしたいです。 そこで、日付ごとに金額を合計してグラフを出力することを目指します。
class HomeController < ApplicationController require 'csv' def index file = params[:file] datas = {} unless file.nil? ActiveRecord::Base.transaction do CSV.foreach(file.path, headers: true, encoding: "UTF-8", col_sep:",", quote_char: '"') do |row| aggregate(datas, row["集計日"] , row["売上"]) end end end @chartkickgraph = datas end private def aggregate(datas, key , value) if datas.has_key?(key) datas[key] = datas[key].to_i + value.to_i else datas[key] = value.to_i end return datas end end
それっぽいテスト用CSVを用意します。
"商品名","カテゴリー","集計日","売上" "商品A","マンガ","2018/10/1","1000000" "商品A","マンガ","2018/10/2","1200000" "商品B","マンガ","2018/10/1","500000" "商品C","DVD","2018/10/1","600000"
出力して見ます。
X軸のラベルがおかしいですが、出力できました。
日付が直せない
X軸の日付ラベルがおかしくなってしまったのが直せず、2時間ほど悪戦苦闘しました。 結論を言うとこれで解決です。
<%= line_chart @chartkickgraph, discrete: true, curve: false, label: "売り上げ", xtitle: "月", ytitle: "個数" %>
Viewに以下の設定を追加するだけでした。。。
discrete: true
データ分析っぽいことをする
CSVからいい感じのグラフは作れましたがこれだけではただグラフができただけでビジネスに全く活用できていません。 販売した商品のうちどれが売れているのかを分析できるようにします。
以下のような形式のオブジェクトを渡せば作成できます。
[{name:"商品A", data: {"2018/10/01": "10000000", ...}}, {name:"商品B", data: {"2018/10/01": "20000000", ...}} ... ]
コントローラーを実装します。
商品名をname:
、同じ商品名のデータだけを抽出し、日付ごとに集計した結果をdata:
とします。
class HomeController < ApplicationController require 'csv' def index file = params[:file] data_groups = [] unless file.nil? logger.info("開始") ActiveRecord::Base.transaction do CSV.foreach(file.path, headers: true, encoding: "UTF-8", col_sep:",", quote_char: '"') do |row| datas = {} datas[:name] = row["商品名"] data = data_groups.find{|h|h[:name] == row["商品名"]} if data.nil? aggregate(datas[:data]={}, row["集計日"] , row["売上"]) data_groups << datas else aggregate(data[:data], row["集計日"] , row["売上"]) end end end end @chartkickgraph = data_groups end private def aggregate(datas, key , value) if datas.has_key?(key) datas[key] = datas[key].to_i + value.to_i else datas[key] = value.to_i end return datas end end
テストデータ
"商品名","カテゴリー","集計日","売上" "商品A","マンガ","2018/10/01","1000000" "商品B","マンガ","2018/10/01","500000" "商品C","DVD","2018/10/01","600000" "商品A","マンガ","2018/10/02","800000" "商品B","マンガ","2018/10/02","1500000" "商品C","DVD","2018/10/02","1600000" "商品A","マンガ","2018/10/03","6000000" "商品B","マンガ","2018/10/03","400000" "商品C","DVD","2018/10/03","300000" "商品A","マンガ","2018/10/04","1700000" "商品B","マンガ","2018/10/04","600000" "商品C","DVD","2018/10/04","700000" "商品A","マンガ","2018/10/05","2000000" "商品B","マンガ","2018/10/05","400000" "商品C","DVD","2018/10/05","900000"
出力したいグラフが出力できました。 CSVデータをプログラム上で集計したのでかなり大変でした。 今回はDBを使わずにグラフを生成しましたが、 DBに格納してからデータを抽出する方が圧倒的に楽です(泣)
まとめ
今回はRailsでグラフを出すまでが課題なのでここまでですが、 作業をしているうちに課題ができたので、今後のために列挙しておきます。
- MongoDBやRedisを利用したNoSQLな分析ツールを作る。
- 分析したい内容を画面から選択できるようにする。
上記は今後実装していきたいと思います。
今回ご紹介したChartkickはRails以外でも利用できるようなので、 ぜひ使って見てください。
*1:highchartsを商用で利用する場合は有償となります。ご注意ください。http://www.altech-ads.com/Others/Highcharts.htm?gclid=CLOoiPif1MMCFRUGvAodPAEA0g#highcharts