国勢調査データのクレンジング

R

人口データのファイルを一括で読み込んで、分析で使いやすくするためのクレンジングコードです。

公開

2024年6月22日

最終更新

2024年6月24日

はじめに

国勢調査のデータを使う際、そのままでは R 等で使えない場合が多いので、分析用にデータをクレンジングするコードをご紹介します。

応用が利くと思うので、ぜひ。

使用するデータ

  • 2020年国勢調査

    • 4次メッシュ(500m四方メッシュ)データ

    • 人口及び世帯(JGD2011)

    • データ:Google ドライブ

    • 出典:e-Stat

データの読み込み

データを読み込みます。ダウンロードした時点では大量のテキストファイルがある状態なので、それを一括で読み込んで処理していきます。

パッケージ

library(tidyverse)  # データハンドリングのため
library(here)  # 相対パスを使うため

読み込み

前提

  • ワーキングディレクトリを指定してあること1

  • ワーキングディレクトリ内の data/census_2020 にテキストファイルが入っていること。

確認

まずはじめに、ファイルの中身がどのようになっているのか、一つのファイルを読み込んで確かめてみます。

ちなみにファイルは Shift_JIS なので、ロケールも設定します。

test <- read_csv(here("data/census_2020/tblT001141H3622.txt"), 
                 locale = locale(encoding = "Shift_JIS"))
head(test)
表 1: 生データ
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 を指定します。

test_skip1 <- read_csv(here("data/census_2020/tblT001141H3622.txt"), skip = 1, 
                       locale = locale(encoding = "Shift_JIS"))
head(test_skip1)
表 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人世帯数 一般世帯数  高齢単身世帯数 一般世帯数  高齢夫婦世帯数 一般世帯数
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] " 高齢夫婦世帯数 一般世帯数"                        

これはトラップで、よく見ると変数名の前に全角スペースが空いています。列名を変更するときはここに注意しないと、謎のエラーに苛まれます。

まとめて読み込む

ではファイルの中身を確認できたところで、ファイルをまとめて読み込みます。

結論から言うと、コードは以下です。

# 指定されたディレクトリ内のファイル名の文字ベクトルを生成
census_files <- list.files(here("data/census_2020"),  # ファイルが入っているフォルダのパス
                           pattern = "\\.txt$", full.names = TRUE)

# lapplyで、ファイル一覧に対して読み込む関数を適用
census_objects <- lapply(
  census_files, 
  function(file) {
    census_obj <- read_csv(file, locale = locale(encoding = "Shift_JIS"), skip = 1) |> 
      # 使いたい列をセレクトする
      select(1:4, " 人口(総数)", " 0〜14歳人口 総数", 
             " 15〜64歳人口 総数", " 65歳以上人口 総数") |> 
      # 2列目が0であれば秘匿対象外
      filter(...2 == 0) |> 
      # 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()

ポイントをいくつか挙げます。

ポイント

  1. list.files()

    • 指定したフォルダ内の .txt で終わるファイルを取得しています。
  2. lapply()

    • 第1引数(1で取得したファイル)に対し、第2引数(function)を適用します。

    • function では、ファイルの読み込みや変数名の変更など、いくつかの作業をして結果を返すよう指示しています。

  3. filter(...2 == 0)

    • ...2 はもともと HTKSYORI(秘匿処理) という列名でした。これが0であると秘匿対象外であり、データが存在します2

    • 逆に秘匿対象だと 表 3 のようになります。

    • フィルターをかけてデータがあるところを抽出します。

表 3: データがアスタリスクで置き換えられています。
...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人世帯数 一般世帯数  高齢単身世帯数 一般世帯数  高齢夫婦世帯数 一般世帯数
372501594 2 372501694 NA 5 1 4 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 3 * * * * * * * * * * * * * * *
372502503 2 372502603 NA 5 3 2 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 2 * * * * * * * * * * * * * * *
372502701 2 372502603 NA 9 6 3 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 5 5 * * * * * * * * * * * * * * *
372502723 2 372502722 NA 4 1 3 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 2 * * * * * * * * * * * * * * *
372502724 2 372502722 NA 6 2 4 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 3 * * * * * * * * * * * * * * *
372502732 2 372502731 NA 3 0 3 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 2 * * * * * * * * * * * * * * *
  1. rename()

    • 変数名を変更するときは、colnames() などで変数名を確認し、おかしなところはないか確認してから変えることをおすすめします(特に日本語列名の場合)。
  2. mutate()

    • KEY_CODE は文字列にしたくて、その他は数値にしたいので、as.character()as.numeric() で変換します。

    • データによっては、この手順を踏まなくても問題ないかもしれません。

  3. bind_rows()

    • lapply() でそれぞれのファイルを読み込んだので、最後にすべてのデータを結合します。

    • 列名もそろえてあるので、問題なく結合できます。

データは次のようになります。

head(census_objects)
表 4: クレンジング後
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
362306721 269 45 152 72

まとめ

今回は国勢調査のメッシュデータを使って、R でデータクレンジングを行う方法をご紹介しました。

複数年分のデータをまとめなければならないときなど、繰り返し作業をするときには特に重宝します。

様々な場合で使えると思いますので、list.files()lapply() をうまく使いながら効率的にデータをまとめていきましょう。

  1. R プロジェクトを使用している場合は問題ありません。R プロジェクトについてはこちらをご参照ください。↩︎

  2. 1だと合算先地域メッシュ、2だと秘匿対象地域メッシュです。詳しくは e-Stat の定義書から確認してください。↩︎