分析結果イメージ
実際に取得したデータをplotしたものが以下の画像となる。
分析結果イメージ:ブランド別の月度売上台数分布
関数作成編
URLからデータフレームを取得する
def generateDataFrame(url):#get DataFrame from url
df = pd.io.html.read_html(url)
return df
変数はurlのみ。このurlは後ほど言及するがhtmlファイルの保存ディレクトリを指定する。
Webページの仕様上、各年度のデータごとにurlが定義されていないため。
データ整形①:不要な行を削除する
def dropunnecessaryRow(df,colList_tmp,dropColumns):#change columns name and drop unnecessary row
df.columns = colList_tmp#一時的なカラム名を定義
df = df.drop(0)#不要な行が1行目に含まれているため削除
df = df.drop(1)#不要な行が2行目に含まれているため削除
df = df.drop(dropColumns,axis=1)#削除したいカラム名を予め定義していた"dropColumns"というリストでカラムを削除する
return df
実はそのままデータフレームを生成すると以下のようにNaNを含んだり”3月”や”4〜3月”のように使いづらいカラム名が設定されている。一つずつ作り直すのも手間なので行丸ごと新たなものに入れ替える。加えてデータフレーム内に2つの時系列データが含まれている(1月と2月のように)のでそれらを別々のデータフレームに分離する。そのためにここからの処理ではdf1/2と分けてdropColumns1/2のようにそれぞれのデータフレームに対応したデータを後々用意することになる。
ちなみに以下はこちらのリンク先データを抜き出したもの。0-1行目に不要なカラム名が設定されているのがわかる。
0 月 3月 NaN 月 4~3月 NaN NaN NaN NaN NaN
1 順位 ブランド通称名 ブランド名 台数 前年比 NaN 順位 ブランド通称名 ブランド名 台数
2 1 ノート 日産 24383 178.2 NaN 1 プリウス トヨタ 225066
3 2 プリウス トヨタ 22447 71.4 NaN 2 アクア トヨタ 155566
4 3 アクア トヨタ 17798 76.3 NaN 3 シエンタ トヨタ 127392
5 4 C-HR トヨタ 16816 (28-12) NaN 4 ノート 日産 123938
6 5 フリード ホンダ 14799 319.5 NaN 5 フィット ホンダ 98923
7 6 セレナ 日産 14577 192.7 NaN 6 ヴォクシー トヨタ 92421
8 7 シエンタ トヨタ 13336 103.5 NaN 7 セレナ 日産 90369
9 8 ヴィッツ トヨタ 12654 128.9 NaN 8 カローラ トヨタ 81391
10 9 フィット ホンダ 11629 74.8 NaN 9 ヴィッツ トヨタ 78634
11 10 ヴォクシー トヨタ 10831 100.6 NaN 10 フリード ホンダ 75384
12 11 インプレッサ スバル 9969 223.0 NaN 11 パッソ トヨタ 74707
13 12 CX-5 マツダ 9669 323.3 NaN 12 ヴェゼル ホンダ 73583
14 13 カローラ トヨタ 9409 83.1 NaN 13 ノア トヨタ 55061
15 14 ヴェゼル ホンダ 8976 100.1 NaN 14 ヴェルファイア トヨタ 53799
16 15 ルーミー トヨタ 8253 (28-11) NaN 15 デミオ マツダ 53321
17 16 タンク トヨタ 7614 (28-11) NaN 16 エクストレイル 日産 52948
18 17 ハリアー トヨタ 7360 152.6 NaN 17 インプレッサ スバル 52756
19 18 エクストレイル 日産 7289 86.3 NaN 18 ハリアー トヨタ 48366
20 19 デミオ マツダ 7082 93.2 NaN 19 ステップワゴン ホンダ 48110
21 20 パッソ トヨタ 7053 133.8 NaN 20 ソリオ スズキ 47795
22 21 ヴェルファイア トヨタ 6538 130.6 NaN 21 エスクァイア トヨタ 44136
23 22 ノア トヨタ 5934 88.4 NaN 22 C-HR トヨタ 43600
24 23 ステップワゴン ホンダ 5884 82.0 NaN 23 アルファード トヨタ 39243
25 24 スイフト スズキ 5465 195.0 NaN 24 シャトル ホンダ 38367
26 25 エスクァイア トヨタ 5317 86.0 NaN 25 クラウン トヨタ 36483
27 26 ソリオ スズキ 5244 103.4 NaN 26 ルーミー トヨタ 30058
28 27 アルファード トヨタ 4978 123.7 NaN 27 アクセラ マツダ 28770
29 28 アクセラ マツダ 4105 132.8 NaN 28 オデッセイ ホンダ 28584
30 29 シャトル ホンダ 3935 75.1 NaN 29 タンク トヨタ 27537
31 30 クラウン トヨタ 3692 69.5 NaN 30 CX-5 マツダ 27193
0 月 3月 NaN 月 4~3月 NaN NaN NaN NaN NaN
1 順位 ブランド通称名 ブランド名 台数 前年比 NaN 順位 ブランド通称名 ブランド名 台数
2 1 ノート 日産 24383 178.2 NaN 1 プリウス トヨタ 225066
3 2 プリウス トヨタ 22447 71.4 NaN 2 アクア トヨタ 155566
4 3 アクア トヨタ 17798 76.3 NaN 3 シエンタ トヨタ 127392
5 4 C-HR トヨタ 16816 (28-12) NaN 4 ノート 日産 123938
6 5 フリード ホンダ 14799 319.5 NaN 5 フィット ホンダ 98923
7 6 セレナ 日産 14577 192.7 NaN 6 ヴォクシー トヨタ 92421
8 7 シエンタ トヨタ 13336 103.5 NaN 7 セレナ 日産 90369
9 8 ヴィッツ トヨタ 12654 128.9 NaN 8 カローラ トヨタ 81391
10 9 フィット ホンダ 11629 74.8 NaN 9 ヴィッツ トヨタ 78634
11 10 ヴォクシー トヨタ 10831 100.6 NaN 10 フリード ホンダ 75384
12 11 インプレッサ スバル 9969 223.0 NaN 11 パッソ トヨタ 74707
13 12 CX-5 マツダ 9669 323.3 NaN 12 ヴェゼル ホンダ 73583
14 13 カローラ トヨタ 9409 83.1 NaN 13 ノア トヨタ 55061
15 14 ヴェゼル ホンダ 8976 100.1 NaN 14 ヴェルファイア トヨタ 53799
16 15 ルーミー トヨタ 8253 (28-11) NaN 15 デミオ マツダ 53321
17 16 タンク トヨタ 7614 (28-11) NaN 16 エクストレイル 日産 52948
18 17 ハリアー トヨタ 7360 152.6 NaN 17 インプレッサ スバル 52756
19 18 エクストレイル 日産 7289 86.3 NaN 18 ハリアー トヨタ 48366
20 19 デミオ マツダ 7082 93.2 NaN 19 ステップワゴン ホンダ 48110
21 20 パッソ トヨタ 7053 133.8 NaN 20 ソリオ スズキ 47795
22 21 ヴェルファイア トヨタ 6538 130.6 NaN 21 エスクァイア トヨタ 44136
23 22 ノア トヨタ 5934 88.4 NaN 22 C-HR トヨタ 43600
24 23 ステップワゴン ホンダ 5884 82.0 NaN 23 アルファード トヨタ 39243
25 24 スイフト スズキ 5465 195.0 NaN 24 シャトル ホンダ 38367
26 25 エスクァイア トヨタ 5317 86.0 NaN 25 クラウン トヨタ 36483
27 26 ソリオ スズキ 5244 103.4 NaN 26 ルーミー トヨタ 30058
28 27 アルファード トヨタ 4978 123.7 NaN 27 アクセラ マツダ 28770
29 28 アクセラ マツダ 4105 132.8 NaN 28 オデッセイ ホンダ 28584
30 29 シャトル ホンダ 3935 75.1 NaN 29 タンク トヨタ 27537
31 30 クラウン トヨタ 3692 69.5 NaN 30 CX-5 マツダ 27193 データ整形②:新たなカラムを追加する
def addDatetoDataFrame(df,dateList,date):#ex)df以外のそれぞれの変数はdate:2017/1,dateList=[]のように定義される
for i in range(0,len(df.index)):#空のdateListにdateで指定した日付をデータフレームに含まれるデータ数分追加する
dateList.append(date)
df['date'] = dateList#dateListを'date'カラムとして追加する
return df
先ほどは不要なカラムを削除した。次は新たに必要なカラムを追加する。
時系列でデータを眺めたいのだがその日付データがない。
そのためdateで追加したい日付を定義する。
データ整形③:新たにカラム名を定義する
def convertColumns(df,colList):#colList1 or 2
df.columns = colList
return df
このままではデータフレームのカラム名が歯抜けの状態なので事前に定義しているcolListをカラム名として追加する。
データ整形④:データフレームを結合する
def connectDataFrame(df1,df2):
df = pd.concat([df1,df2])
return df
先ほども述べたように一つのデータフレームを二つに分けたのでそれを再び一つにする。
これで時系列でデータを見られるようになる。
データ整形⑤:インデックスを新たに定義する
def resetIx(df):
df = df.reset_index(drop=True)
return df
2つのデータフレームを一つにしただけではインデックスがごちゃごちゃしていて何かと都合が悪いのでインデックスを振り直す。
データ整形⑥:文字列を数値に変換する
def convertStringtoInt(df):#replace string to int value and Japanease to English
for i in range(0,len(df.index)):
df['volume'][i] = int(df['volume'][i])
return df
売上台数などのデータが全てstring型なのでint型に変換する。
データ整形⑦:日本語を英語表記にする
def convertJaptoEng(df):#replace Japanease to English
df['model'] = df['model'].replace(u'ノート',u'note')
df['model'] = df['model'].replace(u'セレナ',u'serena')
df['model'] = df['model'].replace(u'プリウス',u'prius')
df['model'] = df['model'].replace(u'C-HR',u'C-HR')
df['model'] = df['model'].replace(u'シエンタ',u'sienta')
df['model'] = df['model'].replace(u'フリード',u'freed')
df['model'] = df['model'].replace(u'アクア',u'aqua')
df['model'] = df['model'].replace(u'ヴォクシー',u'voxy')
df['model'] = df['model'].replace(u'ルーミー',u'roomy')
df['model'] = df['model'].replace(u'フィット',u'fit')
df['model'] = df['model'].replace(u'インプレッサ',u'impreza')
df['model'] = df['model'].replace(u'ヴェゼル',u'vezel')
df['model'] = df['model'].replace(u'タンク',u'tank')
df['model'] = df['model'].replace(u'ヴィッツ',u'vitz')
df['model'] = df['model'].replace(u'ハリアー',u'hurrier')
df['model'] = df['model'].replace(u'エクストレイル',u'xtrail')
df['model'] = df['model'].replace(u'ヴェルファイア',u'velfire')
df['model'] = df['model'].replace(u'カローラ',u'carolla')
df['model'] = df['model'].replace(u'デミオ',u'demio')
df['model'] = df['model'].replace(u'ノア',u'noah')
df['model'] = df['model'].replace(u'スイフト',u'swift')
df['model'] = df['model'].replace(u'ソリオ',u'solio')
df['model'] = df['model'].replace(u'パッソ',u'passo')
df['model'] = df['model'].replace(u'ステップワゴン',u'stepwgn')
df['model'] = df['model'].replace(u'アクセラ',u'axela')
df['model'] = df['model'].replace(u'アルファード',u'alfard')
df['model'] = df['model'].replace(u'エスクァイア',u'esquire')
df['model'] = df['model'].replace(u'シャトル',u'shuttle')
df['model'] = df['model'].replace(u'クラウン',u'crown')
df['model'] = df['model'].replace(u'フォレスター',u'forester')
df['model'] = df['model'].replace(u'CX-5',u'CX-5')
df['model'] = df['model'].replace(u'ランドクルーザーW',u'landcruiser-w')
df['model'] = df['model'].replace(u'オデッセイ',u'odyssey')
df['model'] = df['model'].replace(u'リーフ',u'leaf')
df['model'] = df['model'].replace(u'レヴォーグ',u'levorg')
df['model'] = df['model'].replace(u'プレミオ',u'premio')
df['model'] = df['model'].replace(u'スペイド',u'spaid')
df['model'] = df['model'].replace(u'エスティマ',u'estima')
df['model'] = df['model'].replace(u'イグニス',u'igunis')
df['model'] = df['model'].replace(u'オーリス',u'auris')
df['brand'] = df['brand'].replace(u'トヨタ',u'toyota')
df['brand'] = df['brand'].replace(u'ホンダ',u'honda')
df['brand'] = df['brand'].replace(u'日産',u'nissan')
df['brand'] = df['brand'].replace(u'マツダ',u'mazda')
df['brand'] = df['brand'].replace(u'スバル',u'subaru')
df['brand'] = df['brand'].replace(u'スズキ',u'suzuki')
return df
plot時に文字列が日本語だと文字化けするので全てローマ字表記に変換する。
ブランド名とモデル名を全て変換する。何を変換するかは手作業で洗い出すしかない。
処理実行編
モジュールのインポート
import pandas as pd
import matplotlib.pyplot as plt
import htmltable_mod as hl
先ほどの関数編で作成したスクリプトファイルをhtmltable_mod.pyで同じディレクトリに保存したのでモジュールとしてインポート
先ほどの関数編で作成したスクリプトファイルをhtmltable_mod.pyで同じディレクトリに保存したのでモジュールとしてインポート
事前データの定義
colList1 = ['rank','model','brand','volume','compare','NaN','date']
colList2 = ['NaN','rank','model','brand','volume','compare','date']
colList_tmp = ['rank01','model01','brand01','volume01','compare01','NaN','rank02','model02','brand02','volume02','compare02']
dropColumns1 = ['rank02','model02','brand02','volume02','compare02']
dropColumns2 = ['rank01','model01','brand01','volume01','compare01']
date1 = '2016/01'
date2 = '2016/02'
date3 = '2016/03'
date4 = '2016/04'
date5 = '2016/05'
date6 = '2016/06'
date7 = '2016/07'
date8 = '2016/08'
date9 = '2016/09'
date10 = '2016/10'
date11 = '2016/11'
date12 = '2016/12'
url = 'file:///Users/xxx/Downloads/2016.htm'
$HOME/xxx/Documents/mymod
関数編でそれぞれの関数の変数としていたデータを処理前に事前定義しておく。
同じ名前の番号違いは元データの都合上データフレームを2つに分けざるを得ないので
それぞれに対するデータを定義する。
dateは一年間の各月分作る。また、urlはhtmlファイルの保存先を指定している。
処理パターン①:単月データ(ex:1月、2月)のみがデータフレームに含まれている場合
def main1(df,colList_tmp,dropColumns1,dropColumns2,date1,date2):
dateList1 = []
dateList2 = []
colList1 = ['rank','model','brand','volume','compare','NaN','date']
colList2 = ['NaN','rank','model','brand','volume','compare','date']
df1 = hl.dropunnecessaryRow(df,colList_tmp,dropColumns1)#データ整形①:不要な行を削除する
df2 = hl.dropunnecessaryRow(df,colList_tmp,dropColumns2)#データ整形①:不要な行を削除する
df1 = hl.addDatetoDataFrame(df1,dateList1,date1)#データ整形②:新たなカラムを追加する
df2 = hl.addDatetoDataFrame(df2,dateList2,date2)#データ整形②:新たなカラムを追加する
df1 = hl.convertColumns(df1,colList1)#データ整形③:新たなカラム名を定義する
df2 = hl.convertColumns(df2,colList2)#データ整形③:新たなカラム名を定義する
df = hl.connectDataFrame(df1,df2)#データ整形④:データフレームを結合する
df = hl.resetIx(df)#データ整形⑤:インデックスを新たに定義する
df = hl.convertStringtoInt(df)#データ整形⑥:文字列を数値に変換する
df = hl.convertJaptoEng(df)#データ整形⑦:日本語を英語表記にする
return df
単月データのみが含まれているデータフレーム用に関数を組み合わせた処理を定義する。
二つのデータフレームに対して重複した処理を行っていく。
処理パターン②:複数月データ(ex:3月、3~4月)がデータフレームに含まれている場合
def main2(df,colList_tmp,dropColumns,date):
dateList = []
colList = ['rank','model','brand','volume','compare','NaN','date']
df = hl.dropunnecessaryRow(df,colList_tmp,dropColumns)
df = hl.addDatetoDataFrame(df,dateList,date)
df = hl.convertColumns(df,colList)
df = hl.resetIx(df)
df = hl.convertStringtoInt(df)
df = hl.convertJaptoEng(df)
return df
先ほどと同じ処理、複数月データは除外するので全ての処理は一つずつ行う。
データフレームの結合はなしとする。
データフレームの生成
df = hl.generateDataFrame(url)
#select dataframe from list object
df1 = df[1]
df2 = df[2]
df3 = df[3]
df4 = df[4]
df5 = df[5]
df6 = df[6]
df7 = df[7]
df8 = df[8]
df1 = main1(df1,colList_tmp,dropColumns1,dropColumns2,date1,date2)
df2 = main2(df2,colList_tmp,dropColumns1,date3)
df3 = main1(df3,colList_tmp,dropColumns1,dropColumns2,date4,date5)
df4 = main2(df4,colList_tmp,dropColumns1,date6)
df5 = main1(df5,colList_tmp,dropColumns1,dropColumns2,date7,date8)
df6 = main2(df6,colList_tmp,dropColumns1,date9)
df7 = main1(df7,colList_tmp,dropColumns1,dropColumns2,date10,date11)
df8 = main2(df8,colList_tmp,dropColumns1,date12)
元データで対象とするのは8つのデータフレーム。それぞれに対して先ほど定義したmain関数で処理をしていく。奇数番号のデータフレームでは一つのデータフレームを2つに分けてまた一つに結合する、という処理を行う。
データフレームの結合
df = pd.concat([df1,df2,df3,df4,df5,df6,df7,df8])
先ほど生成した8つのデータフレームを一つに結合する。これでほとんど目的は達成した。
プロット
pt = pd.pivot_table(df, index=['brand','model'],columns='date',values='volume',aggfunc='sum') pt.plot.bar(cmap='rainbow') plt.legend(loc=4,bbox_to_anchor=(0,0),fontsize=5) plt.tick_params(labelsize=6) #legend location ##upper right:1,upper left:2,lower left:3,lower right:4,right:5 ##center left:6,center right:7,lower center:8,upper center:9,center:10 plt.show()
おまけ。最終的にプロットしたい形にデータフレームを変えるためにピボットテーブルで整形する。この形が適しているのかどうかは別としてとりあえずプロットしてみたのが冒頭の画像である。

0 件のコメント:
コメントを投稿