3  第3回 売上の時系列データ分析

3.1 はじめに

パッケージとデータを準備する。

第3回ファイルで使うデータはchp3.xlsxです。

  • chp3.xlsx

パッケージを読み込みます。

pacman::p_load(tidyverse, readxl, ggthemes, gt, gtExtras)

「いつものPOSデータ」を読み込みます。 ついでに文字列をカテゴリー変数として因子型に変換しておきます。

df <- readxl::read_excel("data/chp3.xlsx")
df <- df |>
    mutate(
        曜日 = factor(曜日, levels = c("月", "火", "水", "木", "金", "土", "日"), ordered = TRUE),
        性別 = factor(性別, levels = c("男性", "女性"), ordered = TRUE),
        年代 = factor(年代, levels = c("20歳未満", "20代", "30代", "40代", "50代", "60歳以上"), ordered = TRUE),
        メーカー = as.factor(メーカー),
        商品名 = as.factor(商品名)
    )
head(df) # 先頭6行を表示
レシート番号 日付 曜日 時間 性別 年代 メーカー 商品名 単価 個数 金額
R000001 2023-01-02 10 女性 30代 競合A おいしい緑茶 160 2 320
R000001 2023-01-02 10 女性 30代 競合B 静岡の緑茶 170 2 340
R000002 2023-01-02 10 男性 60歳以上 競合B 静岡の緑茶 170 4 680
R000002 2023-01-02 10 男性 60歳以上 競合A おいしい濃茶 160 2 320
R000003 2023-01-02 10 男性 50代 競合C ほうじ茶 140 1 140
R000004 2023-01-02 10 女性 50代 競合D ウーロン茶 140 2 280

3.2 商品と月ごとの売上個数

df <- df |>
    mutate(
        分類 = paste0(メーカー, 商品名),
= lubridate::month(日付),
= factor(月, levels = unique(月)),
        月日 = paste0(month(日付), "月", day(日付), "日"),
    )

df_month_item <- df |>
    summarise(
        .by = c(分類, 月),
        売上個数 = sum(個数)
    )

df_month_item |>
    pivot_wider(
        names_from = 分類,
        values_from = 売上個数
    ) |>
    gt()|>
    fmt_number(columns = 2:8, decimals = 0)
競合Aおいしい緑茶 競合B静岡の緑茶 競合Aおいしい濃茶 競合Cほうじ茶 競合Dウーロン茶 自社緑茶 自社濃い茶
1 8,344 4,264 5,569 3,397 2,740 6,332 4,183
2 7,119 3,528 4,881 2,892 2,409 5,251 3,535
3 9,776 4,928 6,447 4,005 3,264 7,343 4,719
4 11,761 5,854 7,753 5,009 3,849 8,893 6,032
5 13,588 6,428 8,987 5,571 4,526 10,106 6,601
6 12,072 6,319 8,158 4,989 4,086 9,199 6,058
7 20,222 10,119 13,690 8,583 6,890 15,222 10,407
8 22,650 11,207 14,509 9,291 7,315 16,865 11,348
9 19,143 9,663 12,366 7,941 6,310 14,228 9,769
10 15,540 7,273 10,353 6,339 5,083 11,589 7,666
11 11,427 5,514 7,754 4,742 3,985 8,592 5,680
12 8,675 4,535 6,063 3,596 3,015 6,761 4,462
df_month_item |>
    ggplot(
        aes(x = 月, y = 売上個数, group = 分類, color = 分類)
    ) +
    geom_line() +
    geom_point() +
    theme(legend.position = "top") +
    labs(
        title = "商品と月ごとの売上個数",
        x = "月",
        y = "売上個数"
    ) +
    theme_bw(base_family = "HiraKakuPro-W3") +
    scale_fill_tableau(name = "Tableau 20")

個人的に気に入っているグラフの描き方です。 ここでは12月のデータを抽出して、geom_text()でラベルを付けてることで、グラフ上に商品名を表示しています。

df_name <- df_month_item |>
    filter(月 == 12) # 12月のデータを抽出

g <- df_month_item |>
    ggplot(aes(x = 月, y = 売上個数, group = 分類, color = 分類)) +
    geom_line() + geom_point() + # 線と点を描く
    labs(title = "商品と月ごとの売上個数", x = "月", y = "売上個数") +
    theme_bw(base_family = "HiraKakuPro-W3") +
    scale_fill_tableau(name = "Tableau 20") +
    scale_x_discrete(breaks = 1:12, expand = expansion(mult = c(0, .20))) # x軸の範囲を拡大
g <- g + geom_text(data = df_name, aes(x = 月, y = 売上個数, label = 分類), adj = 0, size = 4, nudge_x = 0.2,family = "HiraKakuProN-W3")
g

3.3 日別の売上個数

df_md_item <- df |>
    summarise(
        .by = c(分類, 月日),
        売上個数 = sum(個数)
    )

df_md_item |>
    pivot_wider(
        names_from = 分類,
        values_from = 売上個数
    ) |>
    head(10) |>
    gt()|>
    fmt_number(columns = 2:8, decimals = 0)
月日 競合Aおいしい緑茶 競合B静岡の緑茶 競合Aおいしい濃茶 競合Cほうじ茶 競合Dウーロン茶 自社緑茶 自社濃い茶
1月2日 148 76 89 37 36 109 62
1月3日 234 105 127 91 65 141 86
1月4日 233 92 152 101 80 180 125
1月5日 162 92 103 71 48 129 95
1月6日 314 216 227 143 87 245 190
1月7日 309 149 246 124 119 264 154
1月8日 301 129 219 132 98 207 149
1月9日 186 115 163 82 47 163 100
1月10日 308 171 226 127 105 269 140
1月11日 375 171 223 131 133 293 197
df_md_item |>
    ggplot() +
    aes(x = 月日, y = 売上個数, group = 分類, color = 分類) +
    geom_line(linewidth = 0.5) +
    geom_point(size = .5) +
    labs(title = "商品と日別の売上個数",
         x = "日", y = "売上個数") +
    # ラベルを縦にする。
    theme_bw(base_family = "HiraKakuPro-W3") +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    scale_fill_tableau(name = "Tableau 20")

df |>
    filter(月 == 1) |>
    filter(
        分類 %in% c("競合Aおいしい濃茶", "競合Aおいしい緑茶", "自社濃い茶", "自社緑茶")
    ) |>
    summarise(
        .by = c(分類, 月日),
        売上個数 = sum(個数)
    ) |>
    ggplot() +
    aes(x = 月日, y = 売上個数, group = 分類, color = 分類) +
    geom_line(linewidth = 0.5) +
    geom_point(size = .5) +
    labs(
        title = "商品と日別の売上個数",
        x = "日",
        y = "売上個数"
    ) +
    # ラベルを縦にする。
    theme_bw(base_family = "HiraKakuPro-W3") +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    scale_fill_tableau(name = "Tableau 20")

df |>
    filter(
        分類 %in% c("競合Aおいしい濃茶", "競合Aおいしい緑茶", "自社濃い茶", "自社緑茶")
    ) |>
    summarise(
        .by = c(分類, 曜日),
        売上個数 = sum(個数)
    ) |>
    ggplot(aes(x = 曜日, y = 売上個数, group = 分類, color = 分類)) +
    geom_line(linewidth = 0.5) +
    geom_point(size = .5) +
    labs(
        title = "商品と曜日の売上個数",
        x = "曜日",
        y = "売上個数"
    ) +
    # ラベルを縦にする。
    theme_bw(base_family = "HiraKakuPro-W3") +
    scale_fill_tableau(name = "Tableau 20")

3.4 移動平均

移動平均を計算するためには、zooパッケージを使います。

pacman::p_load(zoo)
df_mv_item <- df_md_item |>
    filter(
        分類 %in% c("競合Aおいしい濃茶", "競合Aおいしい緑茶", "自社濃い茶", "自社緑茶")
    ) |>
    mutate(
        .by = c(分類),
        移動平均 = rollmean(売上個数, align = "right", k = 7, fill = NA)
    )

levels(df_mv_item$月日)
NULL
df_mv_item |>
    ggplot() + aes(x = 月日, y = 移動平均, group = 分類, color = 分類) +
    geom_line(linewidth = 0.5) + geom_point(size = .5) +
    labs(
        title = "商品の売上個数の7日移動平均",
        x = "基準日",
        y = "売上個数"
    ) +
    theme_bw(base_family = "HiraKakuPro-W3") +
    theme(axis.text.x = element_text(angle = 90, hjust = 1, size = 6)) +
    scale_fill_tableau(name = "Tableau 20")

トップに戻る