-
Notifications
You must be signed in to change notification settings - Fork 0
/
tutorial.qmd
550 lines (398 loc) · 20.5 KB
/
tutorial.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
---
title: "初心者チュートリアル資料"
subtitle: "データの読み込みから可視化"
author: "伊東宏樹"
date: 2024-11-23
lang: ja
format: html
execute:
echo: true
embed-resources: true
code-line-numbers: false
code-copy: true
editor: visual
---
## 内容
- データの読み込み
- ggplot2による可視化
- 地理空間データの読み込み
- 地理空間データの可視化
## データの読み込み
### 準備
tidyverse(メタ)パッケージを読み込みます。
```{r}
#| label: setup
library(tidyverse)
```
### 読み込み
データとして、国勢調査のデータを使用します。
e-statの「[国勢調査/時系列データ/男女,年齢,配偶関係/男女別人口及び人口性比 - 全国,都道府県(大正9年~令和2年)](https://www.e-stat.go.jp/dbview?sid=0003410379)」からCSV(列指向データ)をダウンロードします。ここでは、`FEH_00200521_241003100519.csv`というファイル名でダウンロードされました(ダウンロードごとにファイル名が変わると思われます)。ダウンロードされたファイルを`data`フォルダの中に入れておきます。
ダウンロードされたファイルをreadrパッケージの`read_csv`関数を使ってRに読み込みます。`fie.path`関数で、使用するシステムに応じたファイルパスを作成して、`data_path`変数に入れておきます。
read_csv関数では、このファイルパス(`data_path`)からファイルを読み込みます。その他の引数は、以下のとおりです。
- `col_types`: 各列の型(各文字が各列に対応、f: 因子、c: 文字列、d: 倍精度実数)
- `na`: データファイル中で欠測(データなし)を表す文字(ここでは"`-`")
- `locale`: ここでは文字コード(CP932 (≒Shift_JIS))を指定しています
```{r}
#| label: read_csv
data_path <- file.path("data", "FEH_00200521_241003100519.csv")
pref_data <- read_csv(file = data_path,
col_types = "fcfcfccccd",
na = "-",
locale = locale(encoding = "CP932"))
```
### 結果
この段階で整然データ(tidy data)になっています。
```{r}
pref_data
```
### 整形(必要な部分を残す)
読み込んだデータのうち、後で使うところだけを残します。これには、dplyrパッケージの`filter`関数と`mutate`関数を使用しています。前者で必要な行だけを残し、後者では、新しい列を作ったうえで、その他の列を捨てて(`.keep = "none"` )います。
また、ここでは、パイプ演算子("`|>`")を使用しています。これは、式の計算結果を次の関数の第1引数として与えるというものです。
```{r}
pref_data2 <- pref_data |>
dplyr::filter(`表章項目` == "人口" &
!(`地域_時系列` %in% c("人口集中地区", "人口集中地区以外の地区"))) |>
dplyr::mutate(`男女` = factor(`男女_時系列`, levels = c("総数", "男", "女")),
`地域` = factor(`地域_時系列`, levels = unique(pref_data$`地域_時系列`)),
`年` = as.numeric(str_sub(time_code, 1, 4)),
`人口` = value,
.keep = "none")
```
### 整形結果
必要な部分だけを残すと以下のようになりました。
```{r}
pref_data2
```
### Excelファイルの場合
Excelファイルの場合の読み込み方法もちょっとだけ紹介します。
readxlパッケージの`read_excel`関数で、Excelファイルを読み込むことができます。例として、[e-Gov/人口総数:総務省『国勢調査』](https://data.e-gov.go.jp/data/dataset/cao_20150109_0014)から、ダウンロードしたファイル(`file01.xls`)を使います。
このファイルの先頭6行にはメタデータが記述されていますので、`read_excel`関数で、`skip = 6`"という引数を与えて、先頭から6行を読み飛ばすようにします。
```{r}
#| label: readxl
library(readxl)
excel_file_path <- file.path("data", "file01.xls")
city_data <- read_excel(excel_file_path, skip = 6)
head(city_data)
```
## ggplot2による可視化
ここからデータをグラフにして可視化していきます。そのためにここではggplot2を使用します。データには、先に読み込んだ都道府県の人口データを使用しました。
グラフ作成の前に、使用する日本語フォントを変数にいれておきます。この部分はシステムやお好みで適宜変えてください。
```{r}
#| label: font
jp_font <- "YuGothic"
# jp_font <- "Noto Sans JP"
```
### 折れ線グラフ
まず、全国の人口総数データを時系列で表示します。時系列データの可視化には折れ線グラフを使用します。
dplyrパッケージの`filter`関数で、グラフに必要な行だけに絞り込みます。
```{r}
#| label: pref_data3
pref_data3 <- pref_data2 |>
dplyr::filter(`地域` == "全国", `男女` == "総数")
```
`ggplot`関数は、グラフのオブジェクトの初期化をおこなう関数です。`data`引数に、使用するデータの`pref_data3`を与えます。`mapping`引数には`` aes(x = `年`, y = `人口`) ``という関数の値を与えています(aes = aesthetic mappings)。これにより、X軸に年、Y軸に人口をマッピングすると指定しています。
ggplot2では、"+"演算子で、レイヤー(層)を追加していってグラフを完成させるようになっています。次の行の`geom_line`関数で折れ線グラフを描画します。
```{r}
#| label: line1
ggplot(data = pref_data3, mapping = aes(x = `年`, y = `人口`)) +
geom_line()
```
これでもグラフは作成されますが、さらに見やすくなるようにしていきます。具体的には以下のようにしました。
- `geom_point`で、点も加えます。
- `scale_x_continuous`と`scale_y_continuous`で軸の表示を調整します。
- `theme_gray`で、テーマの設定とフォントの設定をおこないます。
```{r}
#| label: line2
ggplot(pref_data3, aes(x = `年`, y = `人口`)) +
geom_line() + geom_point() +
scale_x_continuous(breaks = seq(1920, 2020, by = 10)) +
scale_y_continuous(name = "人口(人)",
breaks = seq(6e+7, 12e+7, by = 2e+7),
labels = c("6000万", "8000万", "1億", "1億2000万")) +
theme_gray(base_family = jp_font)
```
次に全国のデータを、総数・男・女の別に表示します。
まず、`dplyr::filter`関数で全国のデータだけ残します。この関数の返り値をパイプ演算子で次の行の`ggplot`関数に渡しています。
`ggplot`関数の`mapping`引数では、`aes関数`で`` colour = `男女` ``と引数を与えることで、`男女`列の要素別に色分けして線を引きます。また、`scale_colour_manual`で各要素の色を指定しています(カラーユニバーサルデザイン対応)。
```{r}
#| label: line3
pref_data2 |>
dplyr::filter(`地域` == "全国") |>
ggplot(aes(x = `年`, y = `人口`, colour = `男女`)) +
geom_line() + geom_point(size = 2.5) +
scale_colour_manual(values = c("#000000", "#005aff", "#ff4b00")) +
scale_x_continuous(breaks = seq(1920, 2020, 10)) +
scale_y_continuous(name = "人口(人)",
breaks = seq(4e+7, 12e+7, 2e+7),
labels = c("4000万", "6000万", "8000万", "1億", "1億2000万")) +
theme_gray(base_family = jp_font)
```
つづいて、富山県・石川県・福井県のデータを、総数・男・女の別に表示します。`dplyr::filter`関数で、この3県のデータだけを抽出しています。`aes`関数の引数で"`` shape = `地域`, linetype = `地域` ``"とすることで、県別に点の形と線の種類が変わります。
`scale_y_continuous`関数では、Y軸の目盛りを、2×10^5^から12×10^5^の間で、2×10^5^刻みとすること、表示されるラベルは10^4^(=1万)単位とすることを指定しています。
```{r}
#| label: line4
pref_data2 |>
dplyr::filter(`地域` %in% c("富山県", "石川県", "福井県")) |>
ggplot(aes(x = `年`, y = `人口`, colour = `男女`,
shape = `地域`, linetype = `地域`)) +
geom_line() + geom_point(size = 2.5) +
scale_colour_manual(values = c("#000000", "#005aff", "#ff4b00")) +
scale_x_continuous(breaks = seq(1920, 2020, 10)) +
scale_y_continuous(name = "人口(万人)",
limits = c(2e+5, 12e+5),
breaks = seq(2e+5, 12e+5, by = 2e+5),
labels = \(x) x / 1e+4) +
theme_gray(base_family = jp_font)
```
### 積み上げ折れ線グラフとグラフの分割
一応目的のグラフは描けましたが、これでは煩雑なので、グラフを分けて積み上げ折れ線グラフにします。
そのためまずデータを変形します。総数と男女別の人口が新しい列になるようにします。
```{r}
#| label: transform
pref_data4 <- pref_data2 |>
tidyr::pivot_wider(names_from = `男女`, values_from = `人口`)
```
このようになります。
```{r}
head(pref_data4, 10)
```
さらに必要な3県のデータを取り出して、グラフを描画します。ここでは、`facet_wrap`関数を使って各県のグラフを分割して描くようにしました。
`geom_area`と`geom_ribbon`を組み合わせて使うことで、積み上げグラフにしています。また、`annotate`関数でグラフに直接説明を書き込んでいます。
```{r}
#| label: stack
pref_data4 |>
dplyr::filter(`地域` %in% c("富山県", "石川県", "福井県")) |>
ggplot() +
geom_area(aes(x = `年`, y = `女`), fill ="#ff4b00") +
geom_ribbon(aes(x = `年`, ymin = `女`, ymax = `総数`), fill = "#005aff") +
annotate("text", x = 2000, y = 3e+5, label = "女", colour = "white") +
annotate("text", x = 2000, y = 7.2e+5, label = "男", colour = "white") +
scale_x_continuous(breaks = seq(1920, 2020, 20)) +
scale_y_continuous(name = "人口(万人)",
limits = c(0, 12e+5),
breaks = seq(0, 12e+5, by = 2e+5),
labels = \(x) x / 1e+4) +
theme_gray(base_family = jp_font) +
facet_wrap(~`地域`, nrow = 2)
```
### 散布図
都道府県ごとに、2020年の男女の人口を比較します。
`pref_data4`から、地域が"全国"以外(=各都道府県)で2020年のデータを抽出します。
```{r}
pref_data5 <- pref_data4 |>
dplyr::filter(`地域` != "全国", `年` == 2020)
```
このようになります。
```{r}
head(pref_data5)
```
グラフにします。`geom_point`で散布図を作成します。テーマは`theme_bw`にしました。
```{r}
#| label: point1
ggplot(pref_data5, aes(x = `男`, y = `女`)) +
geom_point() +
theme_bw(base_family = jp_font)
```
見ばえを整えます。
- "`geom_abline(linetype = 2, slope = 1, intercept = 0)`"で、X=Yの点線を引きます。
- "`coord_fixed(ratio = 1)`"で、X軸とY軸の比を1:1に設定します。
```{r}
#| label: point2
ggplot(pref_data5, aes(x = `男`, y = `女`)) +
geom_abline(linetype = 2, slope = 1, intercept = 0) +
geom_point(size = 3, alpha = 0.6) +
scale_x_continuous(name = "男性人口(万人)",
limits = c(0, 8e+6),
breaks = seq(0, 8e+6, by = 2e+6),
labels = \(x) x / 1e+4) +
scale_y_continuous(name = "女性人口(万人)",
limits = c(0, 8e+6),
breaks = seq(0, 8e+6, by = 2e+6),
labels = \(x) x / 1e+4) +
coord_fixed(ratio = 1) +
theme_bw(base_family = jp_font)
```
### 棒グラフ
各都道府県の2020年の人口総数をグラフにします。
`geom_col`は棒グラフを描画します。テーマは`theme_classic`を使用しました。
```{r}
#| label: bar1
pref_data2 |>
dplyr::filter(`地域` != "全国", `男女` == "総数", `年` == 2020) |>
ggplot(aes(x = `地域`, y = `人口`)) +
geom_col() +
theme_classic(base_family = jp_font)
```
横軸のラベルが重なっていて読めないので、`scale_x_discrete`関数で"`guide = guide_axis(angle = 90)`"と指定して、ラベルを90°回転させます。また、`scale_y_continuous`関数で、横軸の表示を整えます。
```{r}
#| label: bar2
pref_data2 |>
dplyr::filter(`地域` != "全国", `男女` == "総数", `年` == 2020) |>
ggplot(aes(x = `地域`, y = `人口`)) +
geom_col() +
scale_x_discrete(name = "都道府県", guide = guide_axis(angle = 90)) +
scale_y_continuous(name = "人口(万人)",
limits = c(0, 1.5e+7),
breaks = seq(0, 1.5e+7, 5e+6),
labels = \(x) x / 1e+4) +
theme_classic(base_family = jp_font)
```
横にしたほうが見やすいかもしれません。そうするには、`coord_flip()`を使います。そうすると、縦軸が下から並ぶようになるので、`scale_x_discrete`関数で、`limits = rev`として、上から並ぶようにさせます。
```{r}
#| label: bar_plot3
#| fig-height: 7
pref_data2 |>
dplyr::filter(`地域` != "全国", `男女` == "総数", `年` == 2020) |>
ggplot(aes(x = `地域`, y = `人口`)) +
geom_col() +
scale_x_discrete(name = "都道府県", limits = rev) +
scale_y_continuous(name = "人口(万人)",
limits = c(0, 1.5e+7),
breaks = seq(0, 1.5e+7, 5e+6),
labels = \(x) x / 1e+4) +
coord_flip() +
theme_classic(base_family = jp_font)
```
都道府県名のラベルと、横軸の0との間の隙間が気になるので、ここを詰めるようにします。これには、`scale_y_continuous`関数で、`expand = expansion(mult = c(0, 0.05))`と指定します。
```{r}
#| label: bar_plot4
#| fig-height: 7
pref_data2 |>
dplyr::filter(`地域` != "全国", `男女` == "総数", `年` == 2020) |>
ggplot(aes(x = `地域`, y = `人口`)) +
geom_col() +
scale_x_discrete(name = "都道府県", limits = rev) +
scale_y_continuous(name = "人口(万人)",
limits = c(0, 1.5e+7),
breaks = seq(0, 1.5e+7, 5e+6),
labels = \(x) x / 1e+4,
expand = expansion(mult = c(0, 0.05))) +
coord_flip() +
theme_classic(base_family = jp_font)
```
男女別の積み上げグラフにします。これには、`geom_col`関数の引数で`position = "stack"`とします(実はデフォルトです)。また、`scale_fill_manual(values = c("#005aff", "#ff4b00"))`で色も指定します。
```{r}
#| label: bar_plot5
#| fig-height: 7
pref_data2 |>
dplyr::filter(`地域` != "全国", `男女` != "総数", `年` == 2020) |>
ggplot(aes(x = `地域`, y = `人口`, fill = `男女`)) +
geom_col(position = "stack") +
scale_fill_manual(values = c("#005aff", "#ff4b00")) +
scale_x_discrete(name = "都道府県", limits = rev) +
scale_y_continuous(name = "人口(万人)",
limits = c(0, 1.5e+7),
breaks = seq(0, 1.5e+7, 5e+6),
labels = \(x) x / 1e+4,
expand = expansion(mult = c(0, 0.05))) +
coord_flip() +
theme_classic(base_family = jp_font)
```
## 地理空間データの読み込み
地理空間データもRで読み込んで使用することができます。この項では、[国土数値情報行政区域データ](https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-2024.html)から石川県のデータをダウンロードして使用します。
### シェープファイル
シェープファイルは複数のファイルから校正されています。sfパッケージの`st_read`関数で`N03-20240101_17.shp`を指定して読み込みます。
```{r}
#| label: read_shapefile_data
#| output: false
library(sf)
shapefile <- file.path("data", "N03-20240101_17.shp")
data_s <- st_read(shapefile)
```
読み込んだデータを表示します。
N03_002は北海道の振興局名、N03_003は郡名、N03_005は政令指定都市の行政区名なので、金沢市の行ではすべて欠損値(NA)になっています。
```{r}
#| label: print_shapefile_data
print(data_s)
```
### GeoJSON
シェープファイルは複数のファイルに分かれていて、あつかいがやや煩雑なので、最近はGeoJSONファイルが使われることも多くなってきています。GeoJSONファイルも`st_read`関数で読むことができます。
```{r}
#| label: read_geojson_data
#| output: false
jsonfile <- file.path("data", "N03-20240101_17.geojson")
data_g <- st_read(jsonfile)
```
こちらも表示します。
```{r}
#| label: print_geojson_data
print(data_g)
```
シェープファイルから読み込んだものと、GeoJSONから読み込んだものでは、なぜか座標参照系(CRS)が異なっている(前者がJGD2011、後者がWGS84)のですが、実用的には問題はないでしょう。
```{r}
st_crs(data_s)
```
```{r}
st_crs(data_g)
```
できたデータの`data_g`のクラスを確認しています。sfクラス(と、data.frameクラス)に属していることがわかります。
```{r}
#| label: class_geojson_data
class(data_g)
```
## 地理空間データの可視化
上で読み込んだデータをggplot2の`geom_sf`関数で表示してみます。
```{r}
#| label: geom_sf
ggplot(data_g) +
geom_sf()
```
この地図に、市区町村名を重ねて表示します。
そのためまず、データに含まれるポリゴンを市町村ごとにst_combine関数でまとめます。また、わかりやすいように、市区町村名のフィールドのN03_004を、nameという名前に変えておきました。
```{r}
#| label: st_combine
data <- data_g |>
dplyr::group_by(N03_004) |>
dplyr::summarise(geometry = st_combine(geometry)) |>
dplyr::ungroup() |>
dplyr::rename(name = N03_004)
```
各市区町村名を地図に重ねて表示します。
```{r}
#| label: geom_sf_text
#| warning: false
ggplot(data) +
geom_sf() +
geom_sf_text(aes(label = name), size = 2.5, family = jp_font) +
scale_x_continuous(breaks = seq(136.5, 137.5, 0.5)) +
labs(x = "経度", y = "緯度") +
theme_bw(base_family = jp_font)
```
### コロプレス図(塗り分け地図)
2020年の総人口データを使って、各市区町村を塗り分けてみます。
まず、各市区町村の総人口を読み込みます。このデータは[e-stat 都道府県・市区町村のすがた(社会・人口統計体系)](https://www.e-stat.go.jp/regional-statistics/ssdsview)からダウンロードしたものです。
読み込んだ後、市区町村名の先頭についている都道府県名を削除し(実際には空白より後だけ残す処理)、2020年度のデータだけを抽出します。
```{r}
#| label: population
pop_data_file <- file.path("data", "FEI_CITY_241027082628.csv")
pop_data <- read_csv(pop_data_file, skip = 1,
col_types = "cc_n",
col_names = c("year", "name", "population")) |>
dplyr::mutate(name = str_sub(name, str_locate(name, " ")[1] + 1)) |>
dplyr::filter(year == "2020年度")
```
人口データを地理空間データに結合します。`left_join`は、`by`引数の変数をキーとして、左側のデータ(この例では`data`)を保存しつつ、右側のデータ(この例では`pop_data`)から共通のキーをもつ行を結合するという関数です。
(この例では両方のデータが1対1対応するので、`left_join`でも`right_join`でも結果は変わりません。)
```{r}
#| label: join
data_join <- dplyr::left_join(data, pop_data, by = "name")
```
2020年の総人口データを色で表現して、地図化しました。総人口は対数スケールにしています。
```{r}
#| label: choropleth
#| warning: false
ggplot(data_join) +
geom_sf(aes(fill = population)) +
geom_sf_text(aes(label = name), size = 2.5, family = jp_font) +
scale_x_continuous(breaks = seq(136.5, 137.5, 0.5)) +
scale_fill_gradient(name = "人口",
low = "#4dc4ff",
high = "#ff4b00",
transform = "log",
limits = c(5e+3, 5e+5),
breaks = c(5e+3, 1e+4, 5e+4, 1e+5, 5e+5),
labels = c("5000", "1万", "5万",
"10万", "50万")) +
labs(x = NULL, y = NULL) +
theme_bw(base_family = jp_font)
```