はじめに
前回の記事で総務省統計局から取得したデータを加工し、扱いやすくしました
加工結果はこちら
今回はこの加工したデータを使って、完全にバレンタインに遅れていますがチョコレートの分析を行います
例によって Livebook を使います
実装したノートブックはこちら
出典
以下のデータを加工して作成
総務省統計局ホームページ
家計調査(家計収支編) 時系列データ(二人以上の世帯)
https://www.stat.go.jp/data/kakei/longtime/index.html#time
- 月 全品目(2015年改定)
- 月 全品目(2020年改定)
(2023年2月20日に利用)
セットアップ
必要なモジュールをインストールします
Mix.install([
{:explorer, "~> 0.5"},
{:kino, "~> 0.8"},
{:kino_vega_lite, "~> 0.1"},
{:req, "~> 0.3"}
])
- Explorer: データ分析
- Kino: 強力な UI/UX
- Kino VegaLite: グラフ描画
- Req: HTTP通信(データダウンロード)
準備
Explorer を使うための準備をします
alias Explorer.DataFrame
alias Explorer.Series
require Explorer.DataFrame
alias
によって Explorer.
を省略できるようになります
require Explorer.DataFrame
によって、データ解析時にクエリが使えるようになります
詳細は以下の記事を参照してください
データ取得
加工済データをダウンロードし、データフレームに読み込みます
household_df =
"https://raw.githubusercontent.com/RyoWakabayashi/elixir-learning/main/livebooks/explorer/%E5%AE%B6%E8%A8%88%E6%94%AF%E5%87%BA%E7%B5%B1%E8%A8%88_%E5%93%81%E7%9B%AE%E5%B9%B4%E6%9C%88%E5%88%A5.csv"
|> Req.get!()
|> then(&DataFrame.load_csv!(&1.body))
Kino.DataTable.new(household_df)
データは品目分類毎、年月毎に世帯平均の支出金額を持っています
月次推移
符号 == "352"
でチョコレートのデータだけを抽出します
choco_df = DataFrame.filter(household_df, 符号 == "352")
Kino.DataTable.new(choco_df)
月次推移を VegaLite でグラフ化します
month = Series.to_list(choco_df["年月"])
expenses = Series.to_list(choco_df["支出金額"])
VegaLite.new(width: 700, title: "チョコレート支出金額推移")
|> VegaLite.data_from_values(x: month, y: expenses)
|> VegaLite.mark(:line, tooltip: true)
|> VegaLite.encode_field(:x, "x", type: :temporal, title: "年月")
|> VegaLite.encode_field(:y, "y", type: :quantitative, title: "支出金額")
かなり規則的な周期が見えます
各年に分けて、何月が毎年ピークになっているのか見てみましょう(見なくても分かるとは思いますが)
2015..2022
|> Enum.map(fn year ->
df = DataFrame.filter(choco_df, 年 == ^year)
month = Series.to_list(df["月"])
expenses = Series.to_list(df["支出金額"])
graph =
VegaLite.new(width: 700, title: "チョコレート支出金額推移")
|> VegaLite.data_from_values(x: month, y: expenses)
|> VegaLite.mark(:line, tooltip: true)
|> VegaLite.encode_field(:x, "x", type: :ordinal, title: "月")
|> VegaLite.encode_field(:y, "y",
type: :quantitative,
title: "支出金額",
scale: [domain: [0, 1500]]
)
{year, graph}
end)
|> Kino.Layout.tabs()
毎年2月にピークを迎え、暑くなると落ち込んでいます
日本のチョコレート市場は明確にバレンタインに依存しています
また、新型コロナウィルスの影響が僅かに見て取れます
WHOのパンデミック宣言が2020年3月11日なので、2020年までのバレンタインに比べて、2021年、2022年のバレンタインの盛り上がりは控えめになっています
年次推移
では年次推移を見てみましょう
支出金額を年単位で集約します
year_choco_df =
choco_df
|> DataFrame.group_by("年")
|> DataFrame.summarise(
最小: min(支出金額),
最大: max(支出金額),
平均: mean(支出金額),
合計: sum(支出金額)
)
Kino.DataTable.new(year_choco_df)
直観的に分かるようにグラフ化してみます
まず合計の年次推移を見ます
year = Series.to_list(year_choco_df["年"])
expenses = Series.to_list(year_choco_df["合計"])
VegaLite.new(width: 700, title: "チョコレート年間支出金額推移")
|> VegaLite.data_from_values(x: year, y: expenses)
|> VegaLite.mark(:line)
|> VegaLite.encode_field(:x, "x", type: :ordinal, title: "年")
|> VegaLite.encode_field(:y, "y", type: :quantitative, title: "合計支出金額")
合計支出金額は 2015年から2019年に上昇し、その後停滞もしくは微減しています
最小、最大、平均の推移も見てみましょう
各統計項目を重ねてグラフ化したいので、 DataFrame.pivot_longer
でデータフレームの形を変えます
pivot_table =
DataFrame.pivot_longer(
year_choco_df,
["最小", "最大", "平均"],
names_to: "統計項目",
values_to: "統計値"
)
Kino.DataTable.new(pivot_table)
統計項目を色として、3種類の統計値を重ねて表示します
year = Series.to_list(pivot_table["年"])
items = Series.to_list(pivot_table["統計項目"])
values = Series.to_list(pivot_table["統計値"])
VegaLite.new(width: 700, title: "チョコレート年間支出金額推移")
|> VegaLite.data_from_values(x: year, items: items, values: values)
|> VegaLite.mark(:line)
|> VegaLite.encode_field(:x, "x", type: :ordinal, title: "年")
|> VegaLite.encode_field(:y, "values", type: :quantitative, title: "支出金額")
|> VegaLite.encode_field(:color, "items")
これを見ると、2021年に最大がガクッと下がったのに対して、最小や平均は下がっていないことが分かります
つまり、バレンタインのようなイベントに集中して消費されていたのが、近年では年間通して食べられるようになったわけです
「チョコレート効果」や「GABA」のような健康志向の商品の売れ行きが好調のようです
菓子類内訳
では、菓子類全体の中でチョコレートはどれくらいの割合を占めているのでしょうか
大分類1、中分類8の菓子類データを抽出します
snack_df =
DataFrame.filter(
household_df,
大分類 == "1" and
中分類 == "8" and
符号 != "-"
)
Kino.DataTable.new(snack_df)
2022年12月時点の菓子類の各品目を支出金額の高い順に並べてみましょう
latest_snack_df = DataFrame.filter(snack_df, 年 == 2022 and 月 == 12)
items = Series.to_list(latest_snack_df["品目分類"])
expenses = Series.to_list(latest_snack_df["支出金額"])
VegaLite.new(width: 700, title: "菓子類支出金額")
|> VegaLite.data_from_values(x: items, y: expenses)
|> VegaLite.mark(:bar, tooltip: true)
|> VegaLite.encode_field(:x, "x", type: :nominal, title: "品目分類", sort: "-y")
|> VegaLite.encode_field(:y, "y", type: :quantitative, title: "支出金額")
他の菓子が圧倒的に多いですが、品目単体として見ると以下の順になっています
- 1位: ケーキ
- 2位: チョコレート
- 3位: せんべい
支出金額で見ているため、単価の高いケーキが1位なのは納得です
そういった中、2位につけているチョコレートは素晴らしいと言えます
円グラフでも見てみましょう
VegaLite.new(title: "菓子類支出金額")
|> VegaLite.data_from_values(x: items, y: expenses)
|> VegaLite.mark(:arc, inner_radius: 50, tooltip: true)
|> VegaLite.encode_field(:color, "x", type: :nominal, title: "品目分類")
|> VegaLite.encode_field(:theta, "y", type: :quantitative, title: "支出金額")
ケーキの割合がかなり高いことが分かります
しかし、チョコレートもチョコレート菓子を合わせれば中々のものです
「チョコレート」と「チョコレート菓子」の違いはグリコが教えてくれます
例を挙げると、以下のように分かれています
-
チョコレート
- 明治ミルクチョコレート
- 森永ミルクチョコレート
- ガーナチョコレート
- ルックチョコレート
- DARS
- 紗々
-
チョコレート菓子
- きのこの山
- たけのこの里
- コアラのマーチ
- トッポ
- ポッキー
- チョコボール
菓子類全体の支出金額推移を見てみましょう
total_snack_df =
DataFrame.filter(
household_df,
大分類 == "1" and
中分類 == "8" and
符号 == "-"
)
Kino.DataTable.new(total_snack_df)
month = Series.to_list(total_snack_df["年月"])
expenses = Series.to_list(total_snack_df["支出金額"])
VegaLite.new(width: 700, title: "菓子類支出金額推移")
|> VegaLite.data_from_values(x: month, y: expenses)
|> VegaLite.mark(:line, tooltip: true)
|> VegaLite.encode_field(:x, "x", type: :temporal, title: "年月")
|> VegaLite.encode_field(:y, "y", type: :quantitative, title: "支出金額")
周期的に突出しているのは12月で、ケーキのクリスマス特需です
何となく、菓子類全体では上昇傾向になっていそうですね
では、菓子類全体に占めるチョコレートの割合=チョコレート率を見てみましょう
ついでにチョコレート菓子率と、チョコレートとの合計でチョコレート類率も算出します
choco_snack_df = DataFrame.filter(household_df, 符号 == "353")
ratio_df =
total_snack_df[["年月", "支出金額"]]
|> DataFrame.join(
choco_df[["年月", "支出金額"]],
on: ["年月"]
)
|> DataFrame.rename(["年月", "菓子類合計", "チョコレート"])
|> DataFrame.join(
choco_snack_df[["年月", "支出金額"]],
on: ["年月"]
)
|> DataFrame.rename(["年月", "菓子類合計", "チョコレート", "チョコレート菓子"])
|> DataFrame.mutate(
チョコレート率: チョコレート / 菓子類合計,
チョコレート菓子率: チョコレート菓子 / 菓子類合計
)
|> DataFrame.mutate(チョコレート類率: チョコレート率 + チョコレート菓子率)
|> DataFrame.pivot_longer(
&String.ends_with?(&1, "率"),
names_to: "品目",
values_to: "占有率"
)
Kino.DataTable.new(ratio_df)
チョコレート率の推移をグラフ化します
month = Series.to_list(ratio_df["年月"])
items = Series.to_list(ratio_df["品目"])
ratio = Series.to_list(ratio_df["占有率"])
VegaLite.new(width: 600, title: "占有率推移")
|> VegaLite.data_from_values(x: month, y: ratio, color: items)
|> VegaLite.mark(:line, tooltip: true)
|> VegaLite.encode_field(:x, "x", type: :temporal, title: "年月")
|> VegaLite.encode_field(:y, "y", type: :quantitative, title: "占有率")
|> VegaLite.encode_field(:color, "color")
チョコレート菓子はそこまでバレンタインに依存していないことが分かります
チョコレート類率の最大値は2017年2月の 23.2% でした
こうして見ると、チョコレート類率はコロナ以前、2018年から減少傾向にありそうです
では菓子類全体の年次推移を見てみましょう
year_total_snack_df =
total_snack_df
|> DataFrame.group_by("年")
|> DataFrame.summarise(合計: sum(支出金額))
Kino.DataTable.new(year_total_snack_df)
year = Series.to_list(year_total_snack_df["年"])
expenses = Series.to_list(year_total_snack_df["合計"])
VegaLite.new(width: 700, title: "菓子類年間支出金額推移")
|> VegaLite.data_from_values(x: year, y: expenses)
|> VegaLite.mark(:line, tooltip: true)
|> VegaLite.encode_field(:x, "x", type: :ordinal, title: "年")
|> VegaLite.encode_field(:y, "y", type: :quantitative, title: "合計支出金額")
なんと、菓子類全体はコロナで下がるどころか上がっています
巣篭もり需要と値上げが要因でしょうか
チョコレート率の年次推移を見てみます
year_choco_snack_df =
choco_snack_df
|> DataFrame.group_by("年")
|> DataFrame.summarise(合計: sum(支出金額))
year_ratio_df =
year_total_snack_df[["年", "合計"]]
|> DataFrame.join(
year_choco_df[["年", "合計"]],
on: ["年"]
)
|> DataFrame.rename(["年", "菓子類合計", "チョコレート"])
|> DataFrame.join(
year_choco_snack_df[["年", "合計"]],
on: ["年"]
)
|> DataFrame.rename(["年", "菓子類合計", "チョコレート", "チョコレート菓子"])
|> DataFrame.mutate(
チョコレート率: チョコレート / 菓子類合計,
チョコレート菓子率: チョコレート菓子 / 菓子類合計
)
|> DataFrame.mutate(チョコレート類率: チョコレート率 + チョコレート菓子率)
|> DataFrame.pivot_longer(
&String.ends_with?(&1, "率"),
names_to: "品目",
values_to: "占有率"
)
Kino.DataTable.new(year_ratio_df)
year = Series.to_list(year_ratio_df["年"])
items = Series.to_list(year_ratio_df["品目"])
ratio = Series.to_list(year_ratio_df["占有率"])
VegaLite.new(width: 600, title: "占有率推移")
|> VegaLite.data_from_values(x: year, y: ratio, color: items)
|> VegaLite.mark(:line, tooltip: true)
|> VegaLite.encode_field(:x, "x", type: :ordinal, title: "年")
|> VegaLite.encode_field(:y, "y", type: :quantitative, title: "占有率")
|> VegaLite.encode_field(:color, "color")
チョコレート率はやはりコロナの影響が大きく、菓子類全般の伸びには追従できていないようですが、チョコレート菓子率が伸びています
チョコレート菓子は元からバレンタインの影響が少なく、焼きチョコなどの夏でも食べやすい商品もあります
ただし、支出金額なので値上げの影響も考えられます
元から安かったチョコレート菓子の場合、数円の値上げが大きく影響します
多少値上げしてもブラックサンダー愛好家は買い続けますが、ちょっと贅沢なチョコレートは買い控えるようになったのかもしれません
まとめ
総務省統計局のデータを見ることで、チョコレートに関して様々な視点で分析することができました
とりあえずチョコレートが食べたくなりました