Rを使いデータフレームからグラフを連続で画像出力
表から列ごとに順々にグラフ
「消費者物価指数」の「光熱・水道代」の推移グラフを描きます。
「光熱・水道代」は6品目に分け、各グラフを画像として連続出力します。
この一連の処理に「R言語」を使いました。
最新の詳細結果表(月報掲載表へ) → 中分類指数(全国)からデータを取得します。
下記が6品目(電気代、都市ガス代、プロパンガス、灯油、水道料、下水道料)のグラフです。
2020年の物価を100とした「指数」の推移です。
総務総統計局が公表している数値データを、「R」を使い加工しています。
データは「e-Stat」から取得しました。
時間軸をx軸とし、y軸に「電気代」「都市ガス代」・・・と順々に、列を変えながら6種類のライングラフ(折れ線グラフ)を描いています。
R言語で
「R」は、普段使わないので、Googleで調べながら試し試し行いました。
Macを使用しています。
library
使用するパッケージをアクティブにします。
library(tidyverse)
library(readxl)
library(lubridate)
getwd, list.files
ファイルのパスを確認します。
# ファイルのパスを確認
getwd()
[1] "/Users/username/Desktop/app/画像生成R"
path <- '/Users/username/Desktop/app/画像生成R/'
# ファイルパスを変数に格納
path_list <- list.files(path, full.names = T)
path_list
[1] "/Users/username/Desktop/app/画像生成R//消費者物価指数_230203005831.csv"
[2] "/Users/username/Desktop/app/画像生成R//消費者物価指数_230203010208.xlsx"
[3] "/Users/username/Desktop/app/画像生成R//画像生成R_整理版.R"
[4] "/Users/username/Desktop/app/画像生成R//画像生成R.Rproj"
# 特定のパスのみ取り出せることを確認。[3]で3番目
path_list[3]
[1] "/Users/username/Desktop/app/画像生成R//消費者物価指数_noheader_230203021248.csv"
read_csv, type_convert
csvを読み込みます。
cols(.default = "c")で一旦文字列型として読み込みます。
type_convert()で読み込まれたデータフレームの各列のデータ型を自動的に変換します。
一旦文字列型として読み込むのは、データフレームにデータ型が混在しており、自動的な推定が望ましくない場合や、特定の列を数値型として読み込むとエラーが発生する可能性がある場合に便利な方法です。
# csv読み込み。col_types = colsで全部文字列型で。skipで1行飛ばす
# type_convert()で型変換実行
df_data01 <- read_csv(
path_list[3], skip = 1, col_types = cols(.default = "c"),
col_names = TRUE
) %>%
type_convert()
#確認
df_data01
# A tibble: 36 × 9
`地域(2020年基準)` 時間軸(…¹ /2020…² 3500 …³ 3600 …⁴ 3612 …⁵ 3701 …⁶ 3810 …⁷ 4610 …⁸
<chr> <chr> <lgl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 全国 2022年12月 NA 130. 140 113. 136. 100. 100.
2 全国 2022年11月 NA 127 133. 113. 137 100. 100.
3 全国 2022年10月 NA 126 129. 112. 138. 99.9 98.7
colnames(df_data01)
[1] "地域(2020年基準)" "時間軸(年・月)" "2020年基準品目" "3500 電気代"
[5] "3600 都市ガス代" "3612 プロパンガス" "3701 灯油" "3810 水道料"
[9] "4610 下水道料"
# 列名変更
colnames(df_data01) <- c("地域", "時間軸", "2020年基準品目" , "電気代", "都市ガス代" , "プロパンガス", "灯油", "水道料", "下水道料" )
グラフを確認
「ggplot」でグラフ作成の手順を確認しました。
以下では「電気代」の指数を使っています。
ggplot, geom_line
### 棒グラフ
# x, y軸両方に値を指定するには, geom_bar()の引数として, stat="identity"を指定
# element_text で目盛回転。ただしtheme_grayを後ろにすると上書きで横のまま
df_data01 %>%
ggplot(aes(x = 時間軸, y = 電気代, family = "HiraKakuPro-W3")) +
geom_bar(stat="identity") +
theme_gray (base_family = "HiraKakuPro-W3") +
theme(axis.text.x = element_text(angle = 45, hjust=1))
「geom_line」を使用した折れ線グラフでは、x軸の「時間軸」が文字列型なのでエラーが出ました。
### 折れ線グラフ
# 「HiraKakuPro-W3」でMacで起きる文字化けを防ぐ
df_data01 %>%
ggplot(aes(x = 時間軸, y = 電気代, family = "HiraKakuPro-W3")) +
geom_line() +
theme_gray (base_family = "HiraKakuPro-W3") +
theme(axis.text.x = element_text(angle = 45, hjust=1))
# 以下 メッセージが出る
geom_path: Each group consists of only one observation. Do you need to adjust the group
aesthetic?
mutate, ym
時間軸列の型を「日付型」に変更します。
# 日付型に変更した値の列「時間軸2」を作成
df_data02 <- df_data01 %>%
mutate(時間軸2 = ym(時間軸))
# 「ym」についてメモ
# 折れ線グラフのx軸は文字列型では使えないので「lubriate」を使って型変換
# 実行例
mdy("1-19-2017")
[1] "2017-01-19"
ym("2022年12月")
[1] "2022-12-01"
目盛りを調整
上記の「時間軸2」をX軸目盛りの表記を「YY年MM月」に調整します。
geom_line
シンプルに「geom_line」(折れ線グラフ)を描くと、「YYYY」というフォーマットの目盛になりました。
df_data02 %>%
ggplot(aes(x = 時間軸2, y = 電気代, family = "HiraKakuPro-W3")) +
geom_line() +
theme_gray (base_family = "HiraKakuPro-W3") +
theme(axis.text.x = element_text(angle = 45, hjust=1))
「scale_x_date」を使って目盛の表記を変更します。
# 「scale_x_date」で目盛の表記調整
# 「date_breaks = "1 months"」で一ヶ月ごと、「date_labels = "%y/年%m月"」で「YY年MM月」に
df_data02 %>%
ggplot(aes(x = 時間軸2, y = 電気代, family = "HiraKakuPro-W3")) +
geom_line() +
scale_x_date(date_breaks = "1 months",
date_labels = "%y/年%m月") +
theme_gray (base_family = "HiraKakuPro-W3") +
theme(axis.text.x = element_text(angle = 45, hjust=1))
列調整
各品目のグラフを連続で生成する前に、列の並び順と列名を調整しました。
select
まず並び順を変更します。
# 列の数確認
ncol(df_data02)
[1] 10
# 「select」 を使い使う列だけ残す。かつ列の並び順を変更
# 「everything」で指定した列以外の越の並び順はそのままに
colnames(df_data02)
[1] "地域" "時間軸" "2020年基準品目" "電気代" "都市ガス代"
[6] "プロパンガス" "灯油" "水道料" "下水道料" "時間軸2"
df_data03 <- df_data02[, -c(1, 3)] %>%
select(時間軸, 時間軸2, everything())
df_data03
# A tibble: 36 × 8
時間軸 時間軸2 電気代 都市ガス代 プロパンガス 灯油 水道料 下水道料
<chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 2022年12月 2022-12-01 130. 140 113. 136. 100. 100.
2 2022年11月 2022-11-01 127 133. 113. 137 100. 100.
sapply, paste
### 数値列名の後ろに「(指数)」を付ける
df_data03_t <- df_data03 # 元に戻す時使う
# 列の数を変数に入れる
col_n <- ncol(df_data03)
# 「sapply」を使い各列に「指数」を付ける
names(df_data03)[(3:col_n)] <-
sapply(colnames(df_data03[, -(1:2)]), function(x){paste(x, "(指数)")}
)
# 確認
colnames(df_data03)
[1] "時間軸" "時間軸2" "電気代 (指数)"
[4] "都市ガス代 (指数)" "プロパンガス (指数)" "灯油 (指数)"
[7] "水道料 (指数)" "下水道料 (指数)"
列を順々に(準備編)
順々に各列をY軸値とした折れ線グラフを描きます。
まずその準備として動作確認。
軸を設定する「aes」の中で変数を使っています。
aes, .data[[]]
### forループを使って列単位で順々にグラフを描く(準備編)
# Y軸を変数として「for」で回す。ただし以下について注意
# Y軸を変数として扱ってうまくいかなかったケース
# aesの中の「y_ch」を「"電気代"」として認識せず「y_ch」のまま表記。Y軸の値がない状態になる
y_ch <- "電気代(指数)"
ggplot(data = df_data03,
aes(x = 時間軸2, y = y_ch, family = "HiraKakuPro-W3")) +
geom_line()
# df_data03[, x]の中で変数を使おうとしたがエラーが出る
x = 3
ggplot(data = df_data03,
aes(x = 時間軸2, y = df_data03[, x], family = "HiraKakuPro-W3")) +
geom_line()
# 以下のエラーが表示される
Don't know how to automatically pick scale for object of type tbl_df/tbl/data.frame. Defaulting to continuous.
Error in is.finite(x) : default method not implemented for type 'list'
# そもそも「df_data03[, x]」は型が異なる(tibble形式のままな)ので適切ではない
df_data03$"電気代 (指数)"
[1] 130.1 127.0 126.0 124.7 122.9 120.8
# A tibble: 36 × 1
`電気代 (指数)`
<dbl>
1 130.
2 127
3 126
「aes」の中に変数を使う場合は「[[]]」と二重囲みを使います。
# 以下のように「.data[[y_ch]]」とと二重囲みを使う
y_ch <- "電気代"
ggplot(data = df_data03,
aes(x = 時間軸2, y = .data[[y_ch]], family = "HiraKakuPro-W3")) +
geom_line()
### (準備編ここまで)
列を順々に(本番編)
「for」を使い、順々にグラフを作成し、画像を保存します。
for, paste, ggsave
前述同様に「scale_x_date」を使いX軸目盛の表記を「YY年MM月」とし、グラフを生成します。
保存する画像ファイル名は、「paste」を使い「列名.png」としています。
# 「for (i in 3:ncol(df_data03))」で、3列目から列の最後まで順々に列(Y軸)を変更
gg_df <- NULL
for (i in 3:ncol(df_data03)) {
y_col <- colnames(df_data03[, i])
gg_df[[i]] <- df_data03 %>%
ggplot(aes(x = 時間軸2, y = .data[[y_col]], family = "HiraKakuPro-W3")) +
geom_line() +
scale_x_date(date_breaks = "1 months",
date_labels = "%y/年%m月") +
theme_gray (base_family = "HiraKakuPro-W3") +
theme(axis.text.x = element_text(angle = 45, hjust=1))
#グラフ保存
image.file = paste('./images/', y_col, '.png', sep = '')
ggsave(image.file, plot = gg_df[[i]], dpi = 300, width = 6.4)
}
再掲となりますが上記コードを実行し、連続して生成したグラフの画像が以下の6枚です。