データの可視化の準備
データの種類には,以下のものがある.
- 連続数値データ
- カテゴリカルデータ
- 順序データ(ordinal data): 順序づけが可能なもの.離散数値データもこれに含まれる.
- 名義データ (nominal data): 順序がつけられないもの.たとえば,性別(男女)や色など.
- 時刻データ(の組)
- 緯度・経度データ
データの種類を考えて、適切なグラフで描画する必要がある。
時刻データが1つの場合には,時系列データとして線グラフで描画する.
時刻データが2つ以上の場合には
- ガントチャート(開始時刻と終了時刻)
- 時空間ネットワーク(さらにモノの移動を考慮した場合) が考えられる.
また, 緯度・経度データがあるなら,地図上に描画できる.
以下のサイトFrom Data to Vizの決定木を参照.
ここでは,以下の例題のデータをpandasで読み込み、Plotly Expressで描画する。
https://github.com/holtzy/data_to_viz/tree/master/Example_dataset
import pandas as pd
import plotly.express as px
# Google Colab.でプロットするためには,以下を実行する.
# import plotly.io as pio
# pio.renderers.default = "colab"
ヒストグラム histgram
まずはヒストグラム(histgram, 度数分布表)を描画してみる.
ヒストグラムは数値データの分布の概要を知る際に便利である.
plotly.express (以下px)のhistgramを用いる.
主な引数
- data_frame: データフレーム
- x: $x$ 軸に用いる列名
- color: 色に用いる列名
- nbins: ビンの数($x$ 軸の区分数)
- marginal: 上部に表示する付加グラフの種類.'rug'(絨毯プロット), 'box'(箱ひげ図), 'violin'(バイオリン図), 'histogram'(ヒストグラム)から選択する.
- opacity: 透過度
- range_x: $x$ 軸の表示範囲
- facet_row: 行に複数のグラフを表示させるときのカテゴリカルデータが入っている列名
- facet_column: 列に複数のグラフを表示させるときのカテゴリカルデータが入っている列名
marginal で表示するグラフの使い分け
- データそのものを見たい場合には絨毯プロット (rug)
- データの大まかな値を見たい場合には箱ひげ図 (box)
- 分布を見たい場合にはバイオリン図 (violin)
df1 = pd.read_csv(
"https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/1_OneNum.csv"
)
df1.head()
fig = px.histogram(
df1, x="price", range_x=(0, 3000), nbins=1000, opacity=0.5, marginal="rug"
)
plotly.offline.plot(fig)
iris = px.data.iris()
iris.head()
問題 (SAT,GPA)
http://logopt.com/data/SATGPA.csv からデータを読み込み,2種類のSATの成績とGPAのヒストグラムを描画せよ.
pokemon = pd.read_csv("http://logopt.com/data/poke.csv", encoding="utf-8")
pokemon.head()
散布図 scatter
散布図(scatter plot)は,2つの数値データの関係を知る際に便利である.
Plotly Expressのpx.scatterを用いる.
主な引数
- data_frame: データフレーム
- x: $x$ 軸に用いる列名
- y: $y$ 軸に用いる列名
- color: 色に用いる列名
- marginal_x: $x$ 軸データを上部に表示させるグラフの種類. "rug", "box", "violin", "histogram" から選択する.
- marginal_y: $y$ 軸データを右部に表示させるグラフの種類. "rug", "box", "violin", "histogram" から選択する.
- animation_frame: 列の数値を元にアニメーションフレームを作成
- animation_group: 列の要素ごとにアニメーションをグループ化
- opacity: 透過度
- range_x: $x$ 軸の表示範囲
- facet_row: 行に複数のグラフを表示させるときのカテゴリカルデータが入っている列名
- facet_column: 列に複数のグラフを表示させるときのカテゴリカルデータが入っている列名
df2 = pd.read_csv(
"https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/2_TwoNum.csv"
)
df2.head()
fig = px.scatter(
df2, x="GrLivArea", y="SalePrice", marginal_y="rug", marginal_x="histogram"
)
plotly.offline.plot(fig);
問題(ダイヤモンド)
http://logopt.com/data/Diamond.csv からダイアモンドの価格データを読み込み,カラット carat と価格 price の散布図を描け.
問題 (SAT,GPA)
http://logopt.com/data/SATGPA.csv からデータを読み込み,MathSATとGPAの関係を描画せよ。
pokemon = pd.read_csv("http://logopt.com/data/poke.csv", encoding="utf-8")
pokemon.head()
import seaborn as sns
titanic = sns.load_dataset("titanic")
titanic.head()
tips = sns.load_dataset("tips")
tips.head()
例題 EVOLUTION OF THE BITCOIN PRICE
ビットコインの価格の推移を例として用いる.
https://www.data-to-viz.com/story/TwoNumOrdered.html
線グラフは px.line で描画できる. 引数は散布図とほぼ同じであるので,省略する.
df3 = pd.read_csv(
"https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/3_TwoNumOrdered.csv",
sep=" ",
)
df3.head()
fig = px.line(df3, x="date", y="value")
plotly.offline.plot(fig)
問題(航空機の乗客数)
http://logopt.com/data/AirPassengers.csv からデータを読み込み、横軸にMonth、縦軸に#Passengersを設定して線グラフで描画せよ。
passengers = pd.read_csv("http://logopt.com/data/AirPassengers.csv")
passengers.head()
print(px.data.gapminder.__doc__)
df4 = px.data.gapminder()
df4.head()
fig = px.scatter(
df4,
x="gdpPercap",
y="lifeExp",
size="pop",
color="continent",
hover_name="country",
animation_frame="year",
)
plotly.offline.plot(fig)
pokemon = pd.read_csv("http://logopt.com/data/poke.csv", encoding="utf-8")
pokemon.head()
df5 = pd.read_csv(
"https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/6_SeveralNum.csv"
)
df5.head()
fig = px.scatter_matrix(
df5, dimensions=["mpg", "disp", "drat", "hp", "qsec", "wt"], color="gear"
)
plotly.offline.plot(fig);
問題 (SAT,GPA)
http://logopt.com/data/SATGPA.csv からデータを読み込み,MathSAT, VerbalSAT, GPAの相互関係を描画せよ.
df6 = pd.read_csv(
"https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/7_OneCatOneNum.csv"
)
df6.head()
fig = px.bar(df6, x="Country", y="Value")
plotly.offline.plot(fig);
例題 THE GENDER WAGE GAP
以下の例題では、国別、年代別の男女の賃金格差を表示する。
https://www.data-to-viz.com/story/OneNumSevCatSubgroupOneObsPerGroup.html
df7 = pd.read_csv(
"https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/9_OneNumSevCatSubgroupOneObs.csv"
)
df7.head()
fig = px.bar(df7, x="Country", y="Value", color="TIME")
plotly.offline.plot(fig);
例題 THE BIGGEST UK CITIES
以下の例では、英国の主要都市の人口を点の大きさに表示して描画する。
https://www.data-to-viz.com/story/GPSCoordWithValue.html
地図の描画には、mapboxのtokenが必要になる。以下のサイトで登録し、tokenを得てから"mapbox_token.txt"というテキストファイルを作成し、そこに保管しておく。
以下では、tokenがファイルに保管されていると仮定し、読み込んでから地図を描画する。また、引数zoomで地図上での拡大を設定できる。
なお,レイアウトでスタイルに"open-street-map"を使用すれば,tokenなしでも描画できる.
df8 = pd.read_csv(
"https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/18_ListGPSCoordinatesWithValue.csv",
sep=" ",
)
df8.head()
# px.set_mapbox_access_token(open("mapbox_token.txt").read())
fig = px.scatter_mapbox(
df8, lat="lat", lon="long", size="pop", hover_name="name", zoom=5
)
# tokenがない場合には以下の行を生かす.
# fig.update_layout(mapbox_style="open-street-map")
plotly.offline.plot(fig);
carshare = px.data.carshare()
carshare.head()
df4 = px.data.gapminder()
df4.head()
fig = px.choropleth(
df4,
locations="iso_alpha",
locationmode="ISO-3",
color="lifeExp",
hover_name="country",
animation_frame="year",
)
plotly.offline.plot(fig);
問題(アルコール摂取量)
世界のアルコール摂取量のデータを http://logopt.com/data/drinks.csv から読み込み、コロプレス図で各国のワイン摂取量 (wine_servings) を描画せよ (ヒント:国の略称のかわりに国名を使うには, locationmode引数に"country names"を入れる).
drinks = pd.read_csv("http://logopt.com/data/drinks.csv")
drinks.head()
iris = px.data.iris()
fig = px.parallel_coordinates(iris, color="species_id")
plotly.offline.plot(fig);
カテゴリカルデータに対する平行座標図を描画するには、parallel_categoriesを用いる。
以下では、tipsデータセットに対して、来客人数 (size) で色分けして描画する。
tips = px.data.tips()
tips.head()
fig = px.parallel_categories(tips, color="size")
plotly.offline.plot(fig);
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
cancer_df = pd.DataFrame(cancer.data, columns=cancer.feature_names)
cancer_df.head()
car = pd.read_csv(
"https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/6_SeveralNum.csv"
)
car.head()
df = px.data.gapminder().query("year == 2007").query("continent == 'Europe'")
fig = px.pie(df, values='pop', names='country', title='Population of European continent')
plotly.offline.plot(fig);
df = px.data.gapminder()
fig = px.area(df, x="year", y="pop", color="continent", line_group="country")
plotly.offline.plot(fig);
df = pd.DataFrame([
dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28', Resource="Alex"),
dict(Task="Job B", Start='2009-03-05', Finish='2009-04-15', Resource="Alex"),
dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30', Resource="Max")
])
fig = px.timeline(df, x_start="Start", x_end="Finish", y="Resource", color="Resource")
plotly.offline.plot(fig);
data = dict(
character=["Eve", "Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"],
parent=["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve" ],
value=[10, 14, 12, 10, 2, 6, 6, 4, 4])
fig = px.sunburst(
data,
names='character',
parents='parent',
values='value',
)
plotly.offline.plot(fig);
import numpy as np
df = px.data.gapminder().query("year == 2007")
fig = px.treemap(df, path=[px.Constant("world"), 'continent', 'country'], values='pop',
color='lifeExp', hover_data=['iso_alpha'],
color_continuous_scale='RdBu',
color_continuous_midpoint=np.average(df['lifeExp'], weights=df['pop']))
plotly.offline.plot(fig);
data = dict(
number=[39, 27.4, 20.6, 11, 2],
stage=["Website visit", "Downloads", "Potential customers", "Requested price", "invoice sent"])
fig = px.funnel(data, x='number', y='stage')
plotly.offline.plot(fig);
まとめ問題
以下のポケモンデータに対して,「自分なりに考えて,興味深い結論を得られるような」分析を行い,その結論を導くために用いた図を示せ.また,図の種類を選んだ理由を説明せよ.
ポケモンデータ豆知識
- 最初の♯の列の整数はポケモンの通し番号である.
- ポケモンの英語名はName列,日本語名はJapanese列に入っている.
- ポケモンはタイプをもつ.Type 1列に主要な種類(草タイプポケモンならGrass),Type 2に副次的な種類(毒タイプならPoisson)が入る.
- ポケモンの能力は体力(HP)から速度(Speed)までの列に数値として入っている.その合計がTotal列に入っている.
- Generationの列は,世代が入っており,初代は1で始まる整数である.
- Legendaryの列がTrueのポケモンは,伝説のポケモンといって珍しい.
- 同種のポケモンが,進化,メガ進化する.たとえばフシギダネは,フシギソウ,フシギバナと進化し,さらにメガ進化する.これらは,連続した行に入っている.
pokemon = pd.read_csv("http://logopt.com/data/poke.csv", encoding="utf-8")
pokemon.head()
fig = px.histogram(pokemon, x="Attack", marginal="violin")
plotly.offline.plot(fig);