library(tidyverse) # データハンドリングのため
library(here) # 相対パスを使うため
はじめに
国勢調査のデータを使う際、そのままではR等で使えない場合が多いので、分析用にデータをクレンジングするコードをご紹介します。
応用が利くと思うので、ぜひ。
使用するデータ
2020年国勢調査
4次メッシュ(500m四方メッシュ)データ
人口及び世帯(JGD2011)
データ:Googleドライブ
出典:e-Stat
データの読み込み
データを読み込みます。ダウンロードした時点では大量のテキストファイルがある状態なので、それを一括で読み込んで処理していきます。
パッケージ
読み込み
前提:
ワーキングディレクトリを指定してあること1。
ワーキングディレクトリ内の
data/census_2020
にテキストファイルが入っていること。
確認
まずはじめに、ファイルの中身がどのようになっているのか、一つのファイルを読み込んで確かめてみます。
ちなみにファイルはShift_JISなので、ロケールも設定します。
<- read_csv(here("data/census_2020/tblT001141H3622.txt"),
test locale = locale(encoding = "Shift_JIS"))
head(test)
KEY_CODE | HTKSYORI | HTKSAKI | GASSAN | T001141001 | T001141002 | T001141003 | T001141004 | T001141005 | T001141006 | T001141007 | T001141008 | T001141009 | T001141010 | T001141011 | T001141012 | T001141013 | T001141014 | T001141015 | T001141016 | T001141017 | T001141018 | T001141019 | T001141020 | T001141021 | T001141022 | T001141023 | T001141024 | T001141025 | T001141026 | T001141027 | T001141028 | T001141029 | T001141030 | T001141031 | T001141032 | T001141033 | T001141034 | T001141035 | T001141036 | T001141037 | T001141038 | T001141039 | T001141040 | T001141041 | T001141042 | T001141043 | T001141044 | T001141045 | T001141046 | T001141047 | T001141048 | T001141049 | T001141050 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
NA | NA | NA | NA | 人口(総数) | 人口(総数) 男 | 人口(総数) 女 | 0〜14歳人口 総数 | 0〜14歳人口 男 | 0〜14歳人口 女 | 15歳以上人口 総数 | 15歳以上人口 男 | 15歳以上人口 女 | 15〜64歳人口 総数 | 15〜64歳人口 男 | 15〜64歳人口 女 | 18歳以上人口 総数 | 18歳以上人口 男 | 18歳以上人口 女 | 20歳以上人口 総数 | 20歳以上人口 男 | 20歳以上人口 女 | 65歳以上人口 総数 | 65歳以上人口 男 | 65歳以上人口 女 | 75歳以上人口 総数 | 75歳以上人口 男 | 75歳以上人口 女 | 85歳以上人口 総数 | 85歳以上人口 男 | 85歳以上人口 女 | 95歳以上人口 総数 | 95歳以上人口 男 | 95歳以上人口 女 | 外国人人口 総数 | 外国人人口 男 | 外国人人口 女 | 世帯総数 | 一般世帯数 | 1人世帯数 一般世帯数 | 2人世帯数 一般世帯数 | 3人世帯数 一般世帯数 | 4人世帯数 一般世帯数 | 5人世帯数 一般世帯数 | 6人世帯数 一般世帯数 | 7人以上世帯数 一般世帯数 | 親族のみの世帯数 一般世帯数 | 核家族世帯数 一般世帯数 | 核家族以外の世帯数 一般世帯数 | 6歳未満世帯員のいる世帯数 一般世帯数 | 65歳以上世帯員のいる世帯数 一般世帯数 | 世帯主の年齢が20〜29歳の1人世帯数 一般世帯数 | 高齢単身世帯数 一般世帯数 | 高齢夫婦世帯数 一般世帯数 |
362257353 | 0 | NA | NA | 29 | 15 | 14 | 5 | 2 | 3 | 24 | 13 | 11 | 19 | 11 | 8 | 23 | 12 | 11 | 23 | 12 | 11 | 5 | 2 | 3 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 16 | 16 | 10 | 1 | 4 | 0 | 1 | 0 | 0 | 6 | 4 | 2 | 1 | 4 | 1 | 1 | 0 |
362257354 | 0 | NA | NA | 96 | 91 | 5 | 0 | 0 | 0 | 96 | 91 | 5 | 96 | 91 | 5 | 96 | 91 | 5 | 96 | 91 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 11 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
362257381 | 0 | NA | NA | 101 | 46 | 55 | 24 | 9 | 15 | 77 | 37 | 40 | 54 | 27 | 27 | 76 | 36 | 40 | 76 | 36 | 40 | 23 | 10 | 13 | 5 | 1 | 4 | 4 | 1 | 3 | 1 | 0 | 1 | 0 | 0 | 0 | 39 | 39 | 11 | 8 | 8 | 10 | 2 | 0 | 0 | 28 | 24 | 4 | 8 | 16 | 1 | 4 | 3 |
362257382 | 0 | NA | NA | 28 | 16 | 12 | 1 | 0 | 1 | 27 | 16 | 11 | 19 | 13 | 6 | 27 | 16 | 11 | 27 | 16 | 11 | 8 | 3 | 5 | 6 | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 1 | 1 | 18 | 18 | 11 | 4 | 3 | 0 | 0 | 0 | 0 | 7 | 6 | 1 | 0 | 5 | 1 | 1 | 2 |
362257451 | 0 | NA | NA | 117 | 59 | 58 | 20 | 13 | 7 | 97 | 46 | 51 | 70 | 34 | 36 | 96 | 46 | 50 | 96 | 46 | 50 | 27 | 12 | 15 | 14 | 4 | 10 | 5 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 58 | 58 | 25 | 18 | 10 | 1 | 2 | 2 | 0 | 32 | 25 | 7 | 3 | 22 | 0 | 7 | 4 |
これを見てみると、1行目には特に意味がなく、2行目が列名になっていることが分かります。
そこで、1行目をスキップして読み込むために、read_csv()
内でskipを指定します。
<- read_csv(here("data/census_2020/tblT001141H3622.txt"), skip = 1,
test_skip1 locale = locale(encoding = "Shift_JIS"))
head(test_skip1)
...1 | ...2 | ...3 | ...4 | 人口(総数) | 人口(総数) 男 | 人口(総数) 女 | 0〜14歳人口 総数 | 0〜14歳人口 男 | 0〜14歳人口 女 | 15歳以上人口 総数 | 15歳以上人口 男 | 15歳以上人口 女 | 15〜64歳人口 総数 | 15〜64歳人口 男 | 15〜64歳人口 女 | 18歳以上人口 総数 | 18歳以上人口 男 | 18歳以上人口 女 | 20歳以上人口 総数 | 20歳以上人口 男 | 20歳以上人口 女 | 65歳以上人口 総数 | 65歳以上人口 男 | 65歳以上人口 女 | 75歳以上人口 総数 | 75歳以上人口 男 | 75歳以上人口 女 | 85歳以上人口 総数 | 85歳以上人口 男 | 85歳以上人口 女 | 95歳以上人口 総数 | 95歳以上人口 男 | 95歳以上人口 女 | 外国人人口 総数 | 外国人人口 男 | 外国人人口 女 | 世帯総数 | 一般世帯数 | 1人世帯数 一般世帯数 | 2人世帯数 一般世帯数 | 3人世帯数 一般世帯数 | 4人世帯数 一般世帯数 | 5人世帯数 一般世帯数 | 6人世帯数 一般世帯数 | 7人以上世帯数 一般世帯数 | 親族のみの世帯数 一般世帯数 | 核家族世帯数 一般世帯数 | 核家族以外の世帯数 一般世帯数 | 6歳未満世帯員のいる世帯数 一般世帯数 | 65歳以上世帯員のいる世帯数 一般世帯数 | 世帯主の年齢が20〜29歳の1人世帯数 一般世帯数 | 高齢単身世帯数 一般世帯数 | 高齢夫婦世帯数 一般世帯数 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
362257353 | 0 | NA | NA | 29 | 15 | 14 | 5 | 2 | 3 | 24 | 13 | 11 | 19 | 11 | 8 | 23 | 12 | 11 | 23 | 12 | 11 | 5 | 2 | 3 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 16 | 16 | 10 | 1 | 4 | 0 | 1 | 0 | 0 | 6 | 4 | 2 | 1 | 4 | 1 | 1 | 0 |
362257354 | 0 | NA | NA | 96 | 91 | 5 | 0 | 0 | 0 | 96 | 91 | 5 | 96 | 91 | 5 | 96 | 91 | 5 | 96 | 91 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 11 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
362257381 | 0 | NA | NA | 101 | 46 | 55 | 24 | 9 | 15 | 77 | 37 | 40 | 54 | 27 | 27 | 76 | 36 | 40 | 76 | 36 | 40 | 23 | 10 | 13 | 5 | 1 | 4 | 4 | 1 | 3 | 1 | 0 | 1 | 0 | 0 | 0 | 39 | 39 | 11 | 8 | 8 | 10 | 2 | 0 | 0 | 28 | 24 | 4 | 8 | 16 | 1 | 4 | 3 |
362257382 | 0 | NA | NA | 28 | 16 | 12 | 1 | 0 | 1 | 27 | 16 | 11 | 19 | 13 | 6 | 27 | 16 | 11 | 27 | 16 | 11 | 8 | 3 | 5 | 6 | 3 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 1 | 1 | 18 | 18 | 11 | 4 | 3 | 0 | 0 | 0 | 0 | 7 | 6 | 1 | 0 | 5 | 1 | 1 | 2 |
362257451 | 0 | NA | NA | 117 | 59 | 58 | 20 | 13 | 7 | 97 | 46 | 51 | 70 | 34 | 36 | 96 | 46 | 50 | 96 | 46 | 50 | 27 | 12 | 15 | 14 | 4 | 10 | 5 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 58 | 58 | 25 | 18 | 10 | 1 | 2 | 2 | 0 | 32 | 25 | 7 | 3 | 22 | 0 | 7 | 4 |
362257452 | 1 | NA | 362257454 | 348 | 182 | 166 | 85 | 41 | 44 | 273 | 149 | 124 | 214 | 118 | 96 | 271 | 148 | 123 | 269 | 148 | 121 | 59 | 31 | 28 | 23 | 10 | 13 | 11 | 3 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 162 | 162 | 86 | 34 | 19 | 15 | 10 | 5 | 1 | 80 | 72 | 8 | 26 | 43 | 12 | 18 | 9 |
この後必要な列をセレクトして名前を付け直すので、ここで一旦列名を確認してみましょう。
colnames(test_skip1)
[1] "...1"
[2] "...2"
[3] "...3"
[4] "...4"
[5] " 人口(総数)"
[6] " 人口(総数) 男"
[7] " 人口(総数) 女"
[8] " 0〜14歳人口 総数"
[9] " 0〜14歳人口 男"
[10] " 0〜14歳人口 女"
[11] " 15歳以上人口 総数"
[12] " 15歳以上人口 男"
[13] " 15歳以上人口 女"
[14] " 15〜64歳人口 総数"
[15] " 15〜64歳人口 男"
[16] " 15〜64歳人口 女"
[17] " 18歳以上人口 総数"
[18] " 18歳以上人口 男"
[19] " 18歳以上人口 女"
[20] " 20歳以上人口 総数"
[21] " 20歳以上人口 男"
[22] " 20歳以上人口 女"
[23] " 65歳以上人口 総数"
[24] " 65歳以上人口 男"
[25] " 65歳以上人口 女"
[26] " 75歳以上人口 総数"
[27] " 75歳以上人口 男"
[28] " 75歳以上人口 女"
[29] " 85歳以上人口 総数"
[30] " 85歳以上人口 男"
[31] " 85歳以上人口 女"
[32] " 95歳以上人口 総数"
[33] " 95歳以上人口 男"
[34] " 95歳以上人口 女"
[35] " 外国人人口 総数"
[36] " 外国人人口 男"
[37] " 外国人人口 女"
[38] " 世帯総数"
[39] " 一般世帯数"
[40] " 1人世帯数 一般世帯数"
[41] " 2人世帯数 一般世帯数"
[42] " 3人世帯数 一般世帯数"
[43] " 4人世帯数 一般世帯数"
[44] " 5人世帯数 一般世帯数"
[45] " 6人世帯数 一般世帯数"
[46] " 7人以上世帯数 一般世帯数"
[47] " 親族のみの世帯数 一般世帯数"
[48] " 核家族世帯数 一般世帯数"
[49] " 核家族以外の世帯数 一般世帯数"
[50] " 6歳未満世帯員のいる世帯数 一般世帯数"
[51] " 65歳以上世帯員のいる世帯数 一般世帯数"
[52] " 世帯主の年齢が20〜29歳の1人世帯数 一般世帯数"
[53] " 高齢単身世帯数 一般世帯数"
[54] " 高齢夫婦世帯数 一般世帯数"
これはトラップで、よく見ると変数名の前に全角スペースが空いています。列名を変更するときはここに注意しないと、謎のエラーに苛まれます。
まとめて読み込む
ではファイルの中身を確認できたところで、ファイルをまとめて読み込みます。
結論から言うと、コードは以下です。
# 指定されたディレクトリ内のファイル名の文字ベクトルを生成
<- list.files(here("data/census_2020"), # ファイルが入っているフォルダのパス
census_files pattern = "\\.txt$", full.names = TRUE)
# lapplyで、ファイル一覧に対して読み込む関数を適用
<- lapply(
census_objects
census_files, function(file) {
<- read_csv(file, locale = locale(encoding = "Shift_JIS"), skip = 1) |>
census_obj # 使いたい列をセレクトする
select(1:4, " 人口(総数)", " 0〜14歳人口 総数",
" 15〜64歳人口 総数", " 65歳以上人口 総数") |>
# 2列目が0であればデータがあり、1であれば他メッシュにデータを合算
filter(...2 == 0 | ...2 == 1) |>
# 2, 3, 4列目はもう使わないので除く
select(-c(...2, ...3, ...4)) |>
# 変数名は任意
rename(
KEY_CODE = ...1,
pop_total = " 人口(総数)",
pop_young = " 0〜14歳人口 総数",
pop_working = " 15〜64歳人口 総数",
pop_old = " 65歳以上人口 総数"
|>
) # 変数のクラスを指定
mutate(
KEY_CODE = as.character(KEY_CODE),
pop_total = as.numeric(pop_total),
pop_young = as.numeric(pop_young),
pop_working = as.numeric(pop_working),
pop_old = as.numeric(pop_old)
)
}|>
) # 読み込んだデータをバインドする
bind_rows()
ポイントをいくつか挙げます。
ポイント
list.files()
- 指定したフォルダ内の
.txt
で終わるファイルを取得しています。
- 指定したフォルダ内の
lapply()
第1引数(1で取得したファイル)に対し、第2引数(
function
)を適用します。function
では、ファイルの読み込みや変数名の変更など、いくつかの作業をして結果を返すよう指示しています。
filter(...2 == 0 | ...2 == 1)
...1 | ...2 | ...3 | ...4 | 人口(総数) | 人口(総数) 男 | 人口(総数) 女 | 0〜14歳人口 総数 | 0〜14歳人口 男 | 0〜14歳人口 女 | 15歳以上人口 総数 | 15歳以上人口 男 | 15歳以上人口 女 | 15〜64歳人口 総数 | 15〜64歳人口 男 | 15〜64歳人口 女 | 18歳以上人口 総数 | 18歳以上人口 男 | 18歳以上人口 女 | 20歳以上人口 総数 | 20歳以上人口 男 | 20歳以上人口 女 | 65歳以上人口 総数 | 65歳以上人口 男 | 65歳以上人口 女 | 75歳以上人口 総数 | 75歳以上人口 男 | 75歳以上人口 女 | 85歳以上人口 総数 | 85歳以上人口 男 | 85歳以上人口 女 | 95歳以上人口 総数 | 95歳以上人口 男 | 95歳以上人口 女 | 外国人人口 総数 | 外国人人口 男 | 外国人人口 女 | 世帯総数 | 一般世帯数 | 1人世帯数 一般世帯数 | 2人世帯数 一般世帯数 | 3人世帯数 一般世帯数 | 4人世帯数 一般世帯数 | 5人世帯数 一般世帯数 | 6人世帯数 一般世帯数 | 7人以上世帯数 一般世帯数 | 親族のみの世帯数 一般世帯数 | 核家族世帯数 一般世帯数 | 核家族以外の世帯数 一般世帯数 | 6歳未満世帯員のいる世帯数 一般世帯数 | 65歳以上世帯員のいる世帯数 一般世帯数 | 世帯主の年齢が20〜29歳の1人世帯数 一般世帯数 | 高齢単身世帯数 一般世帯数 | 高齢夫婦世帯数 一般世帯数 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
372501694 | 1 | NA | 372501594 | 6 | 3 | 3 | 0 | 0 | 0 | 11 | 4 | 7 | 4 | 1 | 3 | 11 | 4 | 7 | 11 | 4 | 7 | 7 | 3 | 4 | 7 | 3 | 4 | 5 | 2 | 3 | 1 | 0 | 1 | 0 | 0 | 0 | 3 | 3 | 1 | 5 | 0 | 0 | 0 | 0 | 0 | 5 | 5 | 0 | 0 | 4 | 0 | 0 | 3 |
372502544 | 0 | NA | NA | 14 | 7 | 7 | 2 | 1 | 1 | 12 | 6 | 6 | 2 | 1 | 1 | 12 | 6 | 6 | 12 | 6 | 6 | 10 | 5 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 6 | 0 | 5 | 0 | 1 | 0 | 0 | 0 | 6 | 6 | 0 | 1 | 5 | 0 | 0 | 5 |
372502553 | 0 | NA | NA | 14 | 5 | 9 | 1 | 0 | 1 | 13 | 5 | 8 | 7 | 3 | 4 | 12 | 5 | 7 | 12 | 5 | 7 | 6 | 2 | 4 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 6 | 2 | 1 | 2 | 1 | 0 | 0 | 0 | 4 | 2 | 2 | 1 | 4 | 0 | 1 | 1 |
372502603 | 1 | NA | 372502503;372502701 | 114 | 50 | 64 | 9 | 3 | 6 | 118 | 56 | 62 | 53 | 25 | 28 | 117 | 56 | 61 | 117 | 56 | 61 | 65 | 31 | 34 | 42 | 17 | 25 | 16 | 3 | 13 | 5 | 0 | 5 | 7 | 1 | 6 | 62 | 61 | 33 | 24 | 8 | 1 | 2 | 0 | 0 | 34 | 31 | 3 | 2 | 41 | 1 | 18 | 11 |
372502641 | 0 | NA | NA | 12 | 8 | 4 | 0 | 0 | 0 | 12 | 8 | 4 | 4 | 3 | 1 | 12 | 8 | 4 | 12 | 8 | 4 | 8 | 5 | 3 | 2 | 2 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | 7 | 3 | 3 | 1 | 0 | 0 | 0 | 0 | 4 | 2 | 2 | 0 | 4 | 0 | 1 | 1 |
372502643 | 0 | NA | NA | 93 | 48 | 45 | 2 | 0 | 2 | 91 | 48 | 43 | 55 | 30 | 25 | 88 | 45 | 43 | 88 | 45 | 43 | 36 | 18 | 18 | 18 | 8 | 10 | 7 | 4 | 3 | 0 | 0 | 0 | 1 | 0 | 1 | 42 | 42 | 12 | 18 | 7 | 1 | 4 | 0 | 0 | 30 | 25 | 5 | 1 | 25 | 1 | 6 | 9 |
rename()
- 変数名を変更するときは、
colnames()
などで変数名を確認し、おかしなところはないか確認してから変えることをおすすめします(特に日本語列名の場合)。
- 変数名を変更するときは、
mutate()
KEY_CODE
は文字列にしたくて、その他は数値にしたいので、as.character()
とas.numeric()
で変換します。データによっては、この手順を踏まなくても問題ないかもしれません。
bind_rows()
lapply()
でそれぞれのファイルを読み込んだので、最後にすべてのデータを結合します。列名もそろえてあるので、問題なく結合できます。
データは次のようになります。
head(census_objects)
KEY_CODE | pop_total | pop_young | pop_working | pop_old |
---|---|---|---|---|
362257353 | 29 | 5 | 19 | 5 |
362257354 | 96 | 0 | 96 | 0 |
362257381 | 101 | 24 | 54 | 23 |
362257382 | 28 | 1 | 19 | 8 |
362257451 | 117 | 20 | 70 | 27 |
362257452 | 348 | 85 | 214 | 59 |
まとめ
今回は国勢調査のメッシュデータを使って、Rでデータクレンジングを行う方法をご紹介しました。
複数年分のデータをまとめなければならないときなど、繰り返し作業をするときには特に重宝します。
様々な場合で使えると思いますので、list.files()
やlapply()
をうまく使いながら効率的にデータをまとめていきましょう。