第4回講義資料

記述統計

スライド

新しいタブで開く

セットアップ

 まず、本日の実習で使用するパッケージを読み込む。

Code 01
library(tidyverse)
library(fastDummies)
library(summarytools)

 当該パッケージがインストールされていない場合、以下のようなメッセージが出力される。

Error in library(パッケージ名) : there is no package called ‘パッケージ名’

 この場合、install.packages("パッケージ名")でパッケージをインストールしてから読み込もう。

パッケージのインストールは1回で十分

 パッケージは1回インストールしておけば、当該サーバーにはずっと残るため、今後、インストールは不要で、library()で読み込むだけで良い。したがって、インストールはコードのスクリプトファイルに書く必要はなく、コンソールで入力して良い。ただし、別のサーバーを使う場合はもう一度インストールする必要がある。

 ただし、当該パッケージがインストールされているかが分からない場合もあろう。あるいは、インストールされているにも関わらず、再インストールしてしまう可能性もある。パッケージによってはインストールに数分かかる場合もあるのでこれは非常に非効率的である。ここで便利なものが{pacman}パッケージだ。{pacman}パッケージがインストールされている場合、p_load()関数でパッケージを読み込むことができる。p_load()関数は{pacman}パッケージが提供する関数であるため、予めlibrary(pacman)で{pacman}パッケージを読み込む必要があるが、パッケージ名::関数名()でパッケージを読み込まずに特定パッケージ内の関数を呼び出すこともできる。

Code 02
# {pacman}パッケージがインストールされていない場合、
# install.packages("pacman") でインストールしておく。
pacman::p_load(tidyverse, fastDummies, summartools)

 一つの関数内に複数のパッケージが同時に読み込めるといったメリットも大きいが、{pacman}最大の特徴は「インストールされていない場合、インストールしてから読み込む」ことだ。一旦、{pacman}をインストールしておけば大変便利になる。

 続いてデータを読み込もう。実習に使用するデータはdescstat_data.csvであり、LMSから入手可能だ。.csv形式データを読み込む関数はread_csv()であり、()内にはパスを含むファイル名を入力する。パス+ファイル名は必ず"で囲むこと。たとえば、プロジェクト・フォルダー内のDataフォルダー内のdescstat_data.csvファイルなら、"Data/descstat_data.csv"と入力する。また、read_csv()だけだとデータが読み込まれて出力されるだけで終わる。つまり、現在の作業環境内に残らない。作業環境にデータを格納するためには<-演算子を使用する。ここではデータを読み込み、raw_dfという名のオブジェクトとして作業環境内に格納しておこう。

 パス(path)とは何かについてよく分からない人は授業後でも良いので必ずファイル・システム」を精読すること。

Code 03
raw_df <- read_csv("Data/descstat_data.csv")

 データの中身を見るためにはオブジェクト名のみ入力すれば良い。

Code 04
raw_df
# A tibble: 3,000 × 48
   USER_ID    Q1    Q2    Q3    Q4  Q5_1  Q5_2  Q5_3  Q5_4  Q5_5  Q5_6  Q5_7  Q5_8  Q5_9 Q5_10 Q5_11
     <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1       1     3     3     1     1    80    80    70    50    40    20    50    45    20    30    30
 2       2     2     2     2     8     0    25    30    30    60    30    10    20    20    10    50
 3       3     3     1     1     8    80    10     0     0     0     0    75     0     0     0     0
 4       4     3     3     1     1   100    50     0     0    50     0   100    50     0     0    50
 5       5     3     3     2     3    70    40    40    50    30    20    70    40    40    50    30
 6       6     3     1     1     1   100     0     0     0     0     0   100     0     0     0     0
 7       7     3     3     1     6   100    10    20    10    10    10    50    10    20    20    10
 8       8     3     1     1     6    80     0    60    55     0     0    90     0     5    10     0
 9       9     3     1     1     1   100    50   100    75    50    25   100    50    75    75    50
10      10     3     3     1     8    25    25    25    25    55    50    50    20    25    30    55
# ℹ 2,990 more rows
# ℹ 32 more variables: Q5_12 <dbl>, Q6_1 <dbl>, Q6_2 <dbl>, Q6_3 <dbl>, Q6_4 <dbl>, Q6_5 <dbl>,
#   Q7 <dbl>, Q8 <dbl>, Q9 <dbl>, Q10_1 <dbl>, Q10_2 <dbl>, Q10_3 <dbl>, Q10_4 <dbl>, Q10_5 <dbl>,
#   Q10_6 <dbl>, Q10_7 <dbl>, Q10_8 <dbl>, Q11 <dbl>, Q12 <dbl>, Q12S1 <dbl>, Q13 <dbl>,
#   Q13S1 <dbl>, Q13S2 <dbl>, Q14 <dbl>, Q14S1 <dbl>, Q15 <dbl>, Q15S1 <dbl>, Q15S2 <dbl>,
#   Q61 <dbl>, gender <dbl>, age <dbl>, chiiki <dbl>

 出力画面の最上段にはraw_dfの大きさが出力される。3,000 × 48は「3000行、48列」の表形式データであることを意味する。非常に大きなデータであるため、この内容が一画面に収めることはできないだろう。read_csv()で読み込まれたデータは画面に表示可能な範囲内でデータを出力してくれる。省略された列は出力画面の下段を見れば分かる。

 raw_dfの変数名(列名)を確認するためには、names()関数を使用する。

Code 05
names(raw_df)
 [1] "USER_ID" "Q1"      "Q2"      "Q3"      "Q4"      "Q5_1"    "Q5_2"    "Q5_3"    "Q5_4"   
[10] "Q5_5"    "Q5_6"    "Q5_7"    "Q5_8"    "Q5_9"    "Q5_10"   "Q5_11"   "Q5_12"   "Q6_1"   
[19] "Q6_2"    "Q6_3"    "Q6_4"    "Q6_5"    "Q7"      "Q8"      "Q9"      "Q10_1"   "Q10_2"  
[28] "Q10_3"   "Q10_4"   "Q10_5"   "Q10_6"   "Q10_7"   "Q10_8"   "Q11"     "Q12"     "Q12S1"  
[37] "Q13"     "Q13S1"   "Q13S2"   "Q14"     "Q14S1"   "Q15"     "Q15S1"   "Q15S2"   "Q61"    
[46] "gender"  "age"     "chiiki" 

 また、データの大きさはdim()関数でも確認することができる。

Code 06
dim(raw_df)
[1] 3000   48

 最後に出力される画面の行数についてだが、デフォルトでは10行出力となっている。もし、15行を出力したい場合はprint()関数を使用し、n引数で指定することができる。

Code 07
print(raw_df, n = 15)
# A tibble: 3,000 × 48
   USER_ID    Q1    Q2    Q3    Q4  Q5_1  Q5_2  Q5_3  Q5_4  Q5_5  Q5_6  Q5_7  Q5_8  Q5_9 Q5_10 Q5_11
     <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1       1     3     3     1     1    80    80    70    50    40    20    50    45    20    30    30
 2       2     2     2     2     8     0    25    30    30    60    30    10    20    20    10    50
 3       3     3     1     1     8    80    10     0     0     0     0    75     0     0     0     0
 4       4     3     3     1     1   100    50     0     0    50     0   100    50     0     0    50
 5       5     3     3     2     3    70    40    40    50    30    20    70    40    40    50    30
 6       6     3     1     1     1   100     0     0     0     0     0   100     0     0     0     0
 7       7     3     3     1     6   100    10    20    10    10    10    50    10    20    20    10
 8       8     3     1     1     6    80     0    60    55     0     0    90     0     5    10     0
 9       9     3     1     1     1   100    50   100    75    50    25   100    50    75    75    50
10      10     3     3     1     8    25    25    25    25    55    50    50    20    25    30    55
11      11     1     2     2     3    60    30    25    10    10     0    60    10    10     5     1
12      12     2     2     2     6    50    50    50    50    50    50    50    50    50    50    50
13      13     3     1     1     3   100     5    30     5     0     0   100     0    10     5     0
14      14     3     3     2     8    60    70    70    50    70    50    50    60    60    50    60
15      15     2     3     3     7    50    50    50    50    50    50    50    50    50    50    50
# ℹ 2,985 more rows
# ℹ 32 more variables: Q5_12 <dbl>, Q6_1 <dbl>, Q6_2 <dbl>, Q6_3 <dbl>, Q6_4 <dbl>, Q6_5 <dbl>,
#   Q7 <dbl>, Q8 <dbl>, Q9 <dbl>, Q10_1 <dbl>, Q10_2 <dbl>, Q10_3 <dbl>, Q10_4 <dbl>, Q10_5 <dbl>,
#   Q10_6 <dbl>, Q10_7 <dbl>, Q10_8 <dbl>, Q11 <dbl>, Q12 <dbl>, Q12S1 <dbl>, Q13 <dbl>,
#   Q13S1 <dbl>, Q13S2 <dbl>, Q14 <dbl>, Q14S1 <dbl>, Q15 <dbl>, Q15S1 <dbl>, Q15S2 <dbl>,
#   Q61 <dbl>, gender <dbl>, age <dbl>, chiiki <dbl>

データハンドリング

 通常、データの分析の歳、読み込んだデータをすべて利用することはあまりない(クリーニング済みのデータならすべて使う)。したがって、分析を始める前に、分析に使用するデータのみを残しておいた方が効率的であろう。データハンドリングについては前期講義資料の「データハンドリング(第9〜11回)」、『私たちのR』の第13141516章を参照されたい。ここではまず、記述統計を出したい変数のみを残し、抽出後のデータをdfという名の新しいオブジェクトとして作業環境内に格納する。select()関数の使い方は『私たちのR』の第13章を参照すること。

Code 08
df <- raw_df |>
  select(ID           = USER_ID, # 回答者ID
         Gender       = gender,  # 性別
         Age          = age,     # 年齢
         Education    = Q61,     # 最終学歴
         Voted        = Q15,     # 投票参加 (2016参院選)
         VotedParty   = Q15S2,   # 投票先 (2016参院選)
         T_Jimin      = Q5_7,    # 自民に対する感情温度
         T_Minshin    = Q5_11)   # 民進に対する感情温度

df
# A tibble: 3,000 × 8
      ID Gender   Age Education Voted VotedParty T_Jimin T_Minshin
   <dbl>  <dbl> <dbl>     <dbl> <dbl>      <dbl>   <dbl>     <dbl>
 1     1      2    69         4     1          7      50        30
 2     2      2    47         3     2         NA      10        50
 3     3      2    37        99     1          1      75         0
 4     4      1    51         4     1          1     100        50
 5     5      1    38        99     2         NA      70        30
 6     6      1    71         2     1          1     100         0
 7     7      1    47         3     1          7      50        10
 8     8      1    71         2     1          1      90         0
 9     9      1    75         4     1          1     100        50
10    10      2    66         3     1          2      50        55
# ℹ 2,990 more rows

 続いて、投票参加有無を示すVoted変数をリコーディングする。元のVoted変数は12の値で構成されており、1は「投票」、2は「棄権」を意味する。このVoted列を修正したい。具体的にはVotedの元の値が1なら1に、それ以外なら0に修正したい。「ある条件を満たせばX、それ以外はYを返す」場合はif_else()関数が有効である。if_else()関数には3つの引数が必要であり、「1. 条件文」、「2. 条件が満たされた場合の戻り値」、「3. 条件が満たされない場合の戻り値」だ。Voted1か否かを判定する条件文はVoted == 1=でなく、==であることに注意)であるため、if_else(Voted == 1, 1, 0)となる(元の値が数値型でなく、文字型である場合は値を"で囲むこと)。このリコーディングの結果をVotedに上書きしたい。特定の列を修正したり、追加する関数はmutate()だ。mutate()内での書き方はmutate(修正/追加したい変数 = 修正内容)である(ここは==でなく=であることに注意)。

 また、Education変数もリコーディングする。Educationは1以上4以下の整数のみをとる変数であるが、99という値も含まれている。この99は欠損値を意味している(どの値が欠損値を意味するかはデータによって異なる。自分が作成したデータでない場合、必ずコードブックに目を通しておこう)。これを99のままにすると、分析上、大きな問題を招きかねない。したがって、予め99を欠損値(NA)に変更しておく必要がある。つまり、Educationの値が99なら(Education == 99NAを、それ以外の場合は元のEducationの値をとるようにリコーディングする。

 以上の手順は以下のように記述する。dfを上書きしないと変更内容が保存されないため、上書きも忘れずに1

Code 09
df <- df |>
  mutate(Voted     = if_else(Voted == 1, 1, 0),
         Education = if_else(Education == 99, NA, Education))

df
# A tibble: 3,000 × 8
      ID Gender   Age Education Voted VotedParty T_Jimin T_Minshin
   <dbl>  <dbl> <dbl>     <dbl> <dbl>      <dbl>   <dbl>     <dbl>
 1     1      2    69         4     1          7      50        30
 2     2      2    47         3     0         NA      10        50
 3     3      2    37        NA     1          1      75         0
 4     4      1    51         4     1          1     100        50
 5     5      1    38        NA     0         NA      70        30
 6     6      1    71         2     1          1     100         0
 7     7      1    47         3     1          7      50        10
 8     8      1    71         2     1          1      90         0
 9     9      1    75         4     1          1     100        50
10    10      2    66         3     1          2      50        55
# ℹ 2,990 more rows

それではこの変数らの記述統計量を計算してみよう。

記述統計

 記述統計量(descriptive statistics)とはある変数が持つ情報を要約した数値である。例えば、dfAge列は回答者の年齢の変数である。この回答者たちの年齢について語る時、「このデータの回答者の年齢は69、47、37、51、…、18歳ですよ」という人はいないだろう。4-5人分のデータならまだしも、3000人の回答者ならあり得ない。我々は普段、「このデータの回答者の年齢はだいたいXX歳ですよ」とか、「真ん中の年齢はYY歳ですよ」と言うだろう。また、年齢の格差/ばらつきを語るときも標準偏差や範囲(「18歳から75歳までいますよ」など)を言うのが普通であろう。このように元の長い情報を一つの数値として要約したものが記述統計量である。

 Rには記述統計量を計算するいくつかの関数が用意されている。

  • mean(): 平均値
  • median(): 中央値
  • var(): 不偏分散
  • sd(): 不偏分散の平方根(いわゆる「標準偏差」)
  • min()max(): 最小値と最大値

 たとえば、dfAge列(df$Age)の平均値は以下のように計算する。na.rm = TRUEは「もしdf$Ageに欠損値がある場合、それは除外して平均値を計算する」ことを意味する。

Code 10
mean(df$Age, na.rm = TRUE)
[1] 47.34

 同じやり方で中央値(median())、最小値(min())、最大値(max())などが計算できる。しかし、本講義ではtidyverseパッケージ群を積極的に活用しているため、ここからは{dplyr}パッケージ(tidyverseを構成するパッケージの一つであり、{tidyverse}を読み込むと自動的に読み込まれる)のsummarise()関数を使用する。summarise()関数の詳細については、『私たちのR』の第14章を参照すること。ここではAge変数の平均値、中央値、標準偏差、最小値、最大値、有効ケース数を計算し、それぞれMeanMedianSDMinMaxNという名の列として出力してみよう。

Code 11
df |>
  summarise(Mean   = mean(Age, na.rm = TRUE),
            Median = median(Age, na.rm = TRUE),
            SD     = sd(Age, na.rm = TRUE),
            Min    = min(Age, na.rm = TRUE),
            Max    = min(Age, na.rm = TRUE),
            N      = sum(!is.na(Age)))
# A tibble: 1 × 6
   Mean Median    SD   Min   Max     N
  <dbl>  <dbl> <dbl> <dbl> <dbl> <int>
1  47.3     47  15.6    18    18  3000

 有効ケース数(欠損していないケースの数)を計算する方法がやや面倒である。これはまずis.na()関数を使って、当該変数が欠損していればTRUE、そうでなければFALSEと判定する。そしてis.na()の前には否定演算子!が付いている。つまり、is.na()から得られた結果が逆となり、欠損していればFALSE、値があればTRUEになる。RにおいてTRUEは1、FALSEは0扱いとなるので、この合計(sum())を求めることで欠損していないケースの数が計算できるようになる。

名目変数の場合

 これまでの内容は変数が連続変数(continuous variable)に限った話である。名目変数(categorical variable)の場合、平均値などは存在しない。100円と1万円の平均値は計算できるものの、男性と女性の平均値や北海道と鹿児島の平均値などはあり得ないからだ。しかし、名目変数でもデータ分析に使われる場面は多く、分析に使われる以上、記述統計量をしっかりと掲載すべきである。

 名目変数の記述する簡単な方法としては度数分布表がある。たとえば、dfの場合、性別(Gender)は男性(=1)と女性(=2)で構成されている。つまり、2つの要素(levels)で構成される変数だ。度数分布表は各要素がいくつあるかを示したものであり、table()関数で簡単に確認することができる。

Code 12
table(df$Gender)

   1    2 
1492 1508 

 また、{dplyr}を使う場合、count()関数を使用すれば良い。

Code 13
df |>
  count(Gender)
# A tibble: 2 × 2
  Gender     n
   <dbl> <int>
1      1  1492
2      2  1508

 しかし、連続変数用の記述統計表と名目変数用の度数分布表を分けることは非効率的である。分析に用いられる名目変数が数が多いと尚更だ。できれば名目変数も連続変数と同じ表で記述統計量を出した方が良いだろう。そのためには名目変数をダミー変数として変換すれば、平均値や標準偏差などが計算できるようになる。

 ダミー変数は0と1のみで構成される変数である。たとえば、性別変数(Gender列)は名目変数であるが、現在、1(男性)と2(女性)の2つの値で構成されている。この変数を男性ダミー変数と女性ダミー変数といった2つの変数に変換することである。男性ダミー変数はGenderの値が1なら、つまり当該回答者が男性(=1)なら1の値を、それ以外の場合は0の値をとる。女性ダミー変数の場合、当該回答者が女性(=2)なら1の値を、それ以外の場合は0の値をとる。以下の 表 1 はダミー変数のイメージである。 表 1 (a) の「出身」変数は普通の文字型変数であるが、この変数をダミー変数にすると 表 1 (b) の「早稲田」、「学習院」のようなダミー変数である。このようにダミー変数は0と1のみで構成される変数であり、通常、一つのダミー変数が1であれば他のダミー変数は0となる。

表 1: ダミー変数の例
(a) 「出身」変数をダミー化する前
氏名 出身
橋本 慶應
小渕 早稲田
早稲田
小泉 慶應
安倍 成蹊
福田 早稲田
麻生 学習院
鳩山 東京
東工
野田 早稲田
法政
岸田 早稲田
石破 慶應

 

(b) 「出身」変数をダミー化した後
氏名 早稲田 慶應 学習院 東京 東工 成蹊 法政
橋本 0 1 0 0 0 0 0
小渕 1 0 0 0 0 0 0
1 0 0 0 0 0 0
小泉 0 1 0 0 0 0 0
安倍 0 0 0 0 0 1 0
福田 1 0 0 0 0 0 0
麻生 0 0 1 0 0 0 0
鳩山 0 0 0 1 0 0 0
0 0 0 0 1 0 0
野田 1 0 0 0 0 0 0
0 0 0 0 0 0 1
岸田 1 0 0 0 0 0 0
石破 0 1 0 0 0 0 0

 それでは、if_else()関数を使って男性ダミー変数(Male)と女性ダミー変数(Female)を作ってみよう。このダミー変数はGender列の後ろにし、df2という名のオブジェクトとして格納する。

Code 14
df2 <- df |>
  mutate(Male   = if_else(Gender == 1, 1, 0),
         Female = if_else(Gender == 2, 1, 0),
         .after = Gender)

df2
# A tibble: 3,000 × 10
      ID Gender  Male Female   Age Education Voted VotedParty T_Jimin T_Minshin
   <dbl>  <dbl> <dbl>  <dbl> <dbl>     <dbl> <dbl>      <dbl>   <dbl>     <dbl>
 1     1      2     0      1    69         4     1          7      50        30
 2     2      2     0      1    47         3     0         NA      10        50
 3     3      2     0      1    37        NA     1          1      75         0
 4     4      1     1      0    51         4     1          1     100        50
 5     5      1     1      0    38        NA     0         NA      70        30
 6     6      1     1      0    71         2     1          1     100         0
 7     7      1     1      0    47         3     1          7      50        10
 8     8      1     1      0    71         2     1          1      90         0
 9     9      1     1      0    75         4     1          1     100        50
10    10      2     0      1    66         3     1          2      50        55
# ℹ 2,990 more rows

 df2にはもう一つの名目変数がある。それは投票先を意味するVotedParty変数だ。VotedPartyは1から7までの整数で構成されている。VotedPartyの値が1なら自民党に投票、2なら民進党に投票、…といった変数であり、これは計7個のダミー変数となる。

Code 15
df2 <- df2 |>
  mutate(VotedParty_Jimin   = if_else(VotedParty == 1, 1, 0),
         VotedParty_Minshin = if_else(VotedParty == 2, 1, 0),
         VotedParty_Komei   = if_else(VotedParty == 3, 1, 0),
         VotedParty_Ishin   = if_else(VotedParty == 4, 1, 0),
         VotedParty_Kyosan  = if_else(VotedParty == 5, 1, 0),
         VotedParty_Etc     = if_else(VotedParty == 6, 1, 0),
         VotedParty_DK      = if_else(VotedParty == 7, 1, 0),
         .after             = VotedParty)

df2
# A tibble: 3,000 × 17
      ID Gender  Male Female   Age Education Voted VotedParty VotedParty_Jimin VotedParty_Minshin
   <dbl>  <dbl> <dbl>  <dbl> <dbl>     <dbl> <dbl>      <dbl>            <dbl>              <dbl>
 1     1      2     0      1    69         4     1          7                0                  0
 2     2      2     0      1    47         3     0         NA               NA                 NA
 3     3      2     0      1    37        NA     1          1                1                  0
 4     4      1     1      0    51         4     1          1                1                  0
 5     5      1     1      0    38        NA     0         NA               NA                 NA
 6     6      1     1      0    71         2     1          1                1                  0
 7     7      1     1      0    47         3     1          7                0                  0
 8     8      1     1      0    71         2     1          1                1                  0
 9     9      1     1      0    75         4     1          1                1                  0
10    10      2     0      1    66         3     1          2                0                  1
# ℹ 2,990 more rows
# ℹ 7 more variables: VotedParty_Komei <dbl>, VotedParty_Ishin <dbl>, VotedParty_Kyosan <dbl>,
#   VotedParty_Etc <dbl>, VotedParty_DK <dbl>, T_Jimin <dbl>, T_Minshin <dbl>

 あとはGenderVotedParty列は不要なので、こちらを除外する。

Code 16
df2 <- df2 |>
  select(-c(Gender, VotedParty))

df2
# A tibble: 3,000 × 15
      ID  Male Female   Age Education Voted VotedParty_Jimin VotedParty_Minshin VotedParty_Komei
   <dbl> <dbl>  <dbl> <dbl>     <dbl> <dbl>            <dbl>              <dbl>            <dbl>
 1     1     0      1    69         4     1                0                  0                0
 2     2     0      1    47         3     0               NA                 NA               NA
 3     3     0      1    37        NA     1                1                  0                0
 4     4     1      0    51         4     1                1                  0                0
 5     5     1      0    38        NA     0               NA                 NA               NA
 6     6     1      0    71         2     1                1                  0                0
 7     7     1      0    47         3     1                0                  0                0
 8     8     1      0    71         2     1                1                  0                0
 9     9     1      0    75         4     1                1                  0                0
10    10     0      1    66         3     1                0                  1                0
# ℹ 2,990 more rows
# ℹ 6 more variables: VotedParty_Ishin <dbl>, VotedParty_Kyosan <dbl>, VotedParty_Etc <dbl>,
#   VotedParty_DK <dbl>, T_Jimin <dbl>, T_Minshin <dbl>

 これで名目変数も連続変数と同じやり方で記述統計量が計算できる。

{fastDummies}の利用

 しかし、以上の作業はかなり面倒だろう。7個の変数でも大変だが、たとえば回答者の都道府県があれば、計47行のコードを書く必要がある。このように面倒なダミー変数の作成を{fastuDummies}パッケージを使えばたった数行のコードでダミー化ができる。手順は以下の通りである。

  1. 名目変数をfactor型変数へ変換する。
  2. {fastDummies}パッケージのdummy_cols()関数でダミー化する。
  3. 生成された列を適宜修正する(変数名や位置など)。

 それではまず、dfGenderVotedParty列をfactor化してみよう。Genderの場合、値が1なら"Male"、2なら"Female"を付ける。VotedPartyは値が1なら"Jimin"、2なら"Minshin"、3なら"Komei"、4なら"Ishin"、5なら"Kyosan"、6なら"Etc"(その他の政党)、7なら"DK"(覚えていない/答えたくない)とする。修正後、dfdf3という名の新しいオブジェクトとして作業環境内に格納する。

Code 17
df3 <- df |>
  mutate(Gender     = factor(Gender, levels = c(1, 2), 
                             labels = c("Male", "Female")),
         VotedParty = factor(VotedParty, levels = 1:7,
                             labels = c("Jimin", "Minshin", "Komei", "Ishin",
                                        "Kyosan", "Etc", "DK"))) 

df3
# A tibble: 3,000 × 8
      ID Gender   Age Education Voted VotedParty T_Jimin T_Minshin
   <dbl> <fct>  <dbl>     <dbl> <dbl> <fct>        <dbl>     <dbl>
 1     1 Female    69         4     1 DK              50        30
 2     2 Female    47         3     0 <NA>            10        50
 3     3 Female    37        NA     1 Jimin           75         0
 4     4 Male      51         4     1 Jimin          100        50
 5     5 Male      38        NA     0 <NA>            70        30
 6     6 Male      71         2     1 Jimin          100         0
 7     7 Male      47         3     1 DK              50        10
 8     8 Male      71         2     1 Jimin           90         0
 9     9 Male      75         4     1 Jimin          100        50
10    10 Female    66         3     1 Minshin         50        55
# ℹ 2,990 more rows

 続いて、{fastDummies}のdummy_cols()関数でGenderVotedPartyをダミー変数に変換する。第一引数はダミー変数にしたい変数の名前を"で囲んだものを入れる。2つ以上の変数をダミー化するならc()でまとめる。続いて、ignore_na = TRUEを指定する。これを指定しない場合、「欠損か否か」のダミー変数まで作成される。つづいて、元の変数(GenderVotedParty)を除外する。

Code 18
df3 <- df3 |>
  dummy_cols(c("Gender", "VotedParty"), ignore_na = TRUE) |>
  select(-c(Gender, VotedParty))

df3
# A tibble: 3,000 × 15
      ID   Age Education Voted T_Jimin T_Minshin Gender_Male Gender_Female VotedParty_Jimin
   <dbl> <dbl>     <dbl> <dbl>   <dbl>     <dbl>       <int>         <int>            <int>
 1     1    69         4     1      50        30           0             1                0
 2     2    47         3     0      10        50           0             1               NA
 3     3    37        NA     1      75         0           0             1                1
 4     4    51         4     1     100        50           1             0                1
 5     5    38        NA     0      70        30           1             0               NA
 6     6    71         2     1     100         0           1             0                1
 7     7    47         3     1      50        10           1             0                0
 8     8    71         2     1      90         0           1             0                1
 9     9    75         4     1     100        50           1             0                1
10    10    66         3     1      50        55           0             1                0
# ℹ 2,990 more rows
# ℹ 6 more variables: VotedParty_Minshin <int>, VotedParty_Komei <int>, VotedParty_Ishin <int>,
#   VotedParty_Kyosan <int>, VotedParty_Etc <int>, VotedParty_DK <int>

 これでダミー化は完了だ。ここで更に変数名を変更し、位置を調整してみよう。たとえば、Gender_MaleMaleに、Gender_FemaleFemaleに変更し、ID列の後ろへ移動させるとしよう。この場合、relocate()関数を使用する。列名を変更する場合は新しい変数名 = 既存の変数名と指定し、.after、あるいは.beforeで位置を指定する。

Code 19
df3 <- df3 |>
  relocate(Male   = Gender_Male,
           Female = Gender_Female,
           .after = ID)

df3
# A tibble: 3,000 × 15
      ID  Male Female   Age Education Voted T_Jimin T_Minshin VotedParty_Jimin VotedParty_Minshin
   <dbl> <int>  <int> <dbl>     <dbl> <dbl>   <dbl>     <dbl>            <int>              <int>
 1     1     0      1    69         4     1      50        30                0                  0
 2     2     0      1    47         3     0      10        50               NA                 NA
 3     3     0      1    37        NA     1      75         0                1                  0
 4     4     1      0    51         4     1     100        50                1                  0
 5     5     1      0    38        NA     0      70        30               NA                 NA
 6     6     1      0    71         2     1     100         0                1                  0
 7     7     1      0    47         3     1      50        10                0                  0
 8     8     1      0    71         2     1      90         0                1                  0
 9     9     1      0    75         4     1     100        50                1                  0
10    10     0      1    66         3     1      50        55                0                  1
# ℹ 2,990 more rows
# ℹ 5 more variables: VotedParty_Komei <int>, VotedParty_Ishin <int>, VotedParty_Kyosan <int>,
#   VotedParty_Etc <int>, VotedParty_DK <int>

 続いて、VotedParty_JiminからVotedParty_DKまでの列をVoted列の後ろへ動かしてみよう。変数選択の場合、:演算子を使うと「〜から〜まで」の指定ができる。

Code 20
df3 <- df3 |>
  relocate(VotedParty_Jimin:VotedParty_DK, .after = Voted)

df3
# A tibble: 3,000 × 15
      ID  Male Female   Age Education Voted VotedParty_Jimin VotedParty_Minshin VotedParty_Komei
   <dbl> <int>  <int> <dbl>     <dbl> <dbl>            <int>              <int>            <int>
 1     1     0      1    69         4     1                0                  0                0
 2     2     0      1    47         3     0               NA                 NA               NA
 3     3     0      1    37        NA     1                1                  0                0
 4     4     1      0    51         4     1                1                  0                0
 5     5     1      0    38        NA     0               NA                 NA               NA
 6     6     1      0    71         2     1                1                  0                0
 7     7     1      0    47         3     1                0                  0                0
 8     8     1      0    71         2     1                1                  0                0
 9     9     1      0    75         4     1                1                  0                0
10    10     0      1    66         3     1                0                  1                0
# ℹ 2,990 more rows
# ℹ 6 more variables: VotedParty_Ishin <int>, VotedParty_Kyosan <int>, VotedParty_Etc <int>,
#   VotedParty_DK <int>, T_Jimin <dbl>, T_Minshin <dbl>

 むろん、:ではなく、starts_with()関数で変数選択もできる。いずれも"VotedParty_"で始まる変数名なので、starts_with("VotedParty_")と書けば、VotedParty_で始まる全変数が選択される。

Code 21
df3 |>
  relocate(starts_with("VotedParty"), .after = Voted)

{summarytools}の利用

 記述統計量は実証分析の論文において必須であり、多くの場合、最初の表として登場する。人によっては記述統計量の表をTable Oneとも呼ぶのもこれが理由である。記述統計量を示すことが重要だというのは、表作成の需要が高いことを意味し、高い需要はかならず供給を生み出す。Rにおいても簡単に記述統計量をまとめてくれるパッケージが多数あり、ここでは{summarytools}パッケージをを紹介する。

 {summarytools}には記述統計量をまとめてくれる関数が複数あるが、ここではdescr()関数を使用する。使い方は非常に単純で、()内にデータのオブジェクト名を入力するだけだ。むろん、パイプ演算子(|>)も使える。パイプ演算子は今後、毎回登場するので、忘れた人はミクロ政治データ分析実習のhttps://www.jaysong.net/r4ps/materials/micro/handling1.html、または『私たちのR』の第13章を参照すること。

Code 22
df |>
  descr()
Descriptive Statistics  
df  
N: 3000  

                        Age   Education    Gender        ID   T_Jimin   T_Minshin     Voted   VotedParty
----------------- --------- ----------- --------- --------- --------- ----------- --------- ------------
             Mean     47.34        3.11      1.50   1500.50     41.13       34.25      0.74         2.94
          Std.Dev     15.63        0.89      0.50    866.17     28.02       25.95      0.44         2.21
              Min     18.00        1.00      1.00      1.00      0.00        0.00      0.00         1.00
               Q1     34.00        2.00      1.00    750.50     20.00       10.00      0.00         1.00
           Median     47.00        3.00      2.00   1500.50     50.00       40.00      1.00         2.00
               Q3     61.00        4.00      2.00   2250.50     60.00       50.00      1.00         5.00
              Max     75.00        4.00      2.00   3000.00    100.00      100.00      1.00         7.00
              MAD     19.27        1.48      0.00   1111.95     29.65       29.65      0.00         1.48
              IQR     27.00        2.00      1.00   1499.50     40.00       40.00      1.00         4.00
               CV      0.33        0.29      0.33      0.58      0.68        0.76      0.60         0.75
         Skewness     -0.03       -0.38     -0.01      0.00      0.02        0.16     -1.07         0.82
      SE.Skewness      0.04        0.05      0.04      0.04      0.04        0.04      0.04         0.05
         Kurtosis     -1.14       -1.28     -2.00     -1.20     -0.83       -0.81     -0.85        -0.82
          N.Valid   3000.00     2913.00   3000.00   3000.00   3000.00     3000.00   3000.00      2208.00
        Pct.Valid    100.00       97.10    100.00    100.00    100.00      100.00    100.00        73.60

 よく使う平均値(Mean)、標準偏差(Std.Dev)など以外にも第一四分位数(Q1)や四分位範囲(IQR)、歪度(Skewness)などまで出力される。実際はこれら全てを掲載するケースはあまりない。ここでは平均値("mean")、標準偏差("sd")、最小値("min")、最大値("max")、有効ケース数("n.vailid")のみに絞ってみよう。出力する記述統計量はstats引数で指定できる。

Code 23
df |>
  descr(stats = c("mean", "sd", "min", "max", "n.valid"))
Descriptive Statistics  
df  
N: 3000  

                    Age   Education    Gender        ID   T_Jimin   T_Minshin     Voted   VotedParty
------------- --------- ----------- --------- --------- --------- ----------- --------- ------------
         Mean     47.34        3.11      1.50   1500.50     41.13       34.25      0.74         2.94
      Std.Dev     15.63        0.89      0.50    866.17     28.02       25.95      0.44         2.21
          Min     18.00        1.00      1.00      1.00      0.00        0.00      0.00         1.00
          Max     75.00        4.00      2.00   3000.00    100.00      100.00      1.00         7.00
      N.Valid   3000.00     2913.00   3000.00   3000.00   3000.00     3000.00   3000.00      2208.00

 ただし、まだ気になる点がある。それは行と列が普段見る記述統計量の表と逆だということだ。これはtranspose = TRUEを追加することで対応できる。また、変数の順番もdf内の順番でなく、勝手にアルファベット順になっている。これをdf内の順番にするためにはorder = "p"を追加すれば良い。

Code 24
df |>
  descr(stats = c("mean", "sd", "min", "max", "n.valid"),
        transpose = TRUE, order = "p")
Descriptive Statistics  
df  
N: 3000  

                      Mean   Std.Dev     Min       Max   N.Valid
---------------- --------- --------- ------- --------- ---------
              ID   1500.50    866.17    1.00   3000.00   3000.00
          Gender      1.50      0.50    1.00      2.00   3000.00
             Age     47.34     15.63   18.00     75.00   3000.00
       Education      3.11      0.89    1.00      4.00   2913.00
           Voted      0.74      0.44    0.00      1.00   3000.00
      VotedParty      2.94      2.21    1.00      7.00   2208.00
         T_Jimin     41.13     28.02    0.00    100.00   3000.00
       T_Minshin     34.25     25.95    0.00    100.00   3000.00

 最後にID行の記述統計量を削除してみよう。これは回答者の識別番号であって、その平均値や標準偏差はどうでもいい。そのためにはdfdescr()を渡す前にselect()関数を使ってID列を除外してから渡せば良いだろう。GenderVotedPartyもまた名目変数であるが、ここではとりあえず放置しておく。

Code 25
df |>
  select(-ID) |>
  descr(stats = c("mean", "sd", "min", "max", "n.valid"),
        transpose = TRUE, order = "p")
Descriptive Statistics  

                    Mean   Std.Dev     Min      Max   N.Valid
---------------- ------- --------- ------- -------- ---------
          Gender    1.50      0.50    1.00     2.00   3000.00
             Age   47.34     15.63   18.00    75.00   3000.00
       Education    3.11      0.89    1.00     4.00   2913.00
           Voted    0.74      0.44    0.00     1.00   3000.00
      VotedParty    2.94      2.21    1.00     7.00   2208.00
         T_Jimin   41.13     28.02    0.00   100.00   3000.00
       T_Minshin   34.25     25.95    0.00   100.00   3000.00

 それでは名目変数を含めた記述統計表を作成してみよう。dfGenderVotedParty変数のダミー化を済ませてからdescr()に渡せば良い。記述統計表はdesc_statという名のオブジェクトとして作業環境内に格納する。

Code 26
desc_stat <- df |>
  mutate(Gender     = factor(Gender, levels = c(1, 2), 
                             labels = c("Male", "Female")),
         VotedParty = factor(VotedParty, levels = 1:7,
                             labels = c("Jimin", "Minshin", "Komei", "Ishin",
                                        "Kyosan", "Etc", "DK"))) |>
  dummy_cols(c("Gender", "VotedParty"), ignore_na = TRUE,
             # 以下の引数を追加すると元の変数が自動的に削除される
             remove_selected_columns = TRUE) |>
  # Gender_MaleとGender_Femaleの変数名を変更し、ID列の後ろに移動させる。
  relocate(Male   = Gender_Male,
           Female = Gender_Female,
           .after = ID) |>
  relocate(starts_with("VotedParty"), .after = Voted) |>
  select(-ID) |>
  descr(stats = c("mean", "sd", "min", "max", "n.valid"),
        transpose = TRUE, order = "p")

desc_stat
Descriptive Statistics  

                            Mean   Std.Dev     Min      Max   N.Valid
------------------------ ------- --------- ------- -------- ---------
                    Male    0.50      0.50    0.00     1.00   3000.00
                  Female    0.50      0.50    0.00     1.00   3000.00
                     Age   47.34     15.63   18.00    75.00   3000.00
               Education    3.11      0.89    1.00     4.00   2913.00
                   Voted    0.74      0.44    0.00     1.00   3000.00
        VotedParty_Jimin    0.40      0.49    0.00     1.00   2208.00
      VotedParty_Minshin    0.20      0.40    0.00     1.00   2208.00
        VotedParty_Komei    0.05      0.22    0.00     1.00   2208.00
        VotedParty_Ishin    0.10      0.30    0.00     1.00   2208.00
       VotedParty_Kyosan    0.08      0.27    0.00     1.00   2208.00
          VotedParty_Etc    0.01      0.10    0.00     1.00   2208.00
           VotedParty_DK    0.16      0.37    0.00     1.00   2208.00
                 T_Jimin   41.13     28.02    0.00   100.00   3000.00
               T_Minshin   34.25     25.95    0.00   100.00   3000.00

 {gt}パッケージを使えば、よりまとまった表として出力できる。興味のある履修者はやってみよう。{gt}パッケージのチュートリアルおよびレファレンスは公式ページを参照すること。

Code 27
library(gt) # or pacman::p_load(gt)

desc_stat |> 
  gt(rownames_to_stub = TRUE) |> # 行の名前(変数の名前)を1列目に出力
  fmt_number(columns = 2:3, decimals = 3) # 2列、3列の値は小数点3桁まで
Mean Std.Dev Min Max N.Valid
Male 0.497 0.500 0 1 3000
Female 0.503 0.500 0 1 3000
Age 47.340 15.628 18 75 3000
Education 3.114 0.893 1 4 2913
Voted 0.736 0.441 0 1 3000
VotedParty_Jimin 0.399 0.490 0 1 2208
VotedParty_Minshin 0.199 0.399 0 1 2208
VotedParty_Komei 0.051 0.220 0 1 2208
VotedParty_Ishin 0.100 0.300 0 1 2208
VotedParty_Kyosan 0.078 0.269 0 1 2208
VotedParty_Etc 0.011 0.104 0 1 2208
VotedParty_DK 0.163 0.369 0 1 2208
T_Jimin 41.130 28.015 0 100 3000
T_Minshin 34.248 25.947 0 100 3000

グループごとの記述統計

可視化

  1. まずは上書きせず出力結果を確認し、問題ない場合は上書きするようにしよう。間違ったコードで上書きをした場合、最初のコードからもう一度実行すること。↩︎