第9回講義資料

線形回帰分析(2)

スライド

新しいタブで開く

セットアップ

 本日使用する3つのパッケージとデータ(JES6_W1.csv; LMSからダウンロード)を読み込む。読み込んだデータはjes_dfと名付けて作業スペース内に格納する。

Code 01
library(tidyverse)
library(fastDummies)
library(modelsummary)

jes_df  <- read_csv("Data/JES6_W1.csv")

jes_df
# A tibble: 3,000 × 8
   Temp_Rikken Ideology Interest Gender   Age Education   Job  Income
         <dbl>    <dbl>    <dbl>  <dbl> <dbl>     <dbl> <dbl>   <dbl>
 1          30        9        1      2    69         4     5 4333994
 2          50        7        4      2    47         3     1  979181
 3           0       11        2      2    37         2     1 8498127
 4          50       11        2      1    51         4     2 7572654
 5          30        7        2      1    38         4     1 6436713
 6           0       11        1      1    71         2     5 3410276
 7          10        9        2      1    47         3     2 8652860
 8           0       11        1      1    71         2     5  927703
 9          50        9        1      1    75         4     1 4497693
10          55        6        2      2    66         3     4 2419573
# ℹ 2,990 more rows

 つづいて、データの大きさと変数名を確認する。

Code 02
dim(jes_df) # jes_dfの大きさ(行数と列数)
[1] 3000    8
Code 03
names(jes_df) # jes_df内の変数名
[1] "Temp_Rikken" "Ideology"    "Interest"    "Gender"      "Age"        
[6] "Education"   "Job"         "Income"     

 各変数の詳細は以下の通りである。

変数名 説明 備考
Temp_Rikken 立憲民主党に対する感情温度 高いほど好感
Ideology 回答者のイデオロギー 高いほど保守
Interest 回答者の政治関心 高いほど無関心
Gender 回答者の性別 1: 男性 / 2: 女性
Age 回答者の年齢
Education 回答者の最終学歴 1: 中卒以下 / 2: 高校卒 / 3: 高専・短大卒 / 4: 大卒以上
Job 回答者の職業 1: 勤め / 2: 自営業 / 3: 学生 / 4: 専業主婦・主夫 / 5: 無職 / 6: その他
Income 回答者の世帯収入

記述統計

 分析の前に名目変数(GenderJob)はダミー変数に変換する。GenderJobはデータ上は数値型であるため、平均値や標準偏差などの記述統計量は計算できるものの、数字そのものの意味はない。たとえば、Genderの場合1は男性、2は女性であるが、別に1が女性、2が男性でも関係なく、1が女性、99が男性でも回答者の性別を識別するには問題ない。

 このような名目変数はdummy_cols()関数({fastDummies}パッケージを予め読み込んでおくこと)を使用してダミー変数に変換してから記述統計量を計算する必要がある。生成されるダミー変数の名前は「元の変数名_値」である。たとえば、Gender列は12で構成されているため、Gender_1Gender_2列が追加される。また、新しく生成されたダミー変数はデータセットの右端に追加される。これらの変数の位置を調整するためにはrelocate()関数を使う。第1引数は位置を変更する列名(複数であれば、c():を使用)、第2引数は.before、または.afterである。.before = GenderGender列より前(=左)、.after = GenderGender列より後ろ(=右)である。最後にdescr()関数に渡す前に、記述統計量の計算が不要なGender列とJob列を除外する。

Code 04
jes_df |>
   dummy_cols(c("Gender", "Job")) |>
   # Gender_1と_2列をGenderの前に
   relocate(c(Gender_1, Gender_2), .before = Gender) |> 
   # Job_1から_6列をJobの前に
   relocate(Job_1:Job_6, .before = Job) |>          
   # GenderとJob列を除外してからdscer()に渡す
   select(-c(Gender, Job)) |>
   descr(stats = c("mean", "sd", "min", "max", "n.valid"),
        transpose = TRUE, order = "p")
Descriptive Statistics  

                          Mean      Std.Dev         Min           Max   N.Valid
----------------- ------------ ------------ ----------- ------------- ---------
      Temp_Rikken        34.25        25.95        0.00        100.00   3000.00
         Ideology         6.34         2.10        1.00         11.00   3000.00
         Interest         2.26         0.83        1.00          4.00   3000.00
         Gender_1         0.50         0.50        0.00          1.00   3000.00
         Gender_2         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   3000.00
            Job_1         0.50         0.50        0.00          1.00   3000.00
            Job_2         0.08         0.28        0.00          1.00   3000.00
            Job_3         0.05         0.21        0.00          1.00   3000.00
            Job_4         0.20         0.40        0.00          1.00   3000.00
            Job_5         0.15         0.35        0.00          1.00   3000.00
            Job_6         0.02         0.14        0.00          1.00   3000.00
           Income   6190334.00   4233639.26   643629.00   25286751.00   3000.00

 自分で記述統計量を確認するためにはこれでも良いが、論文・レポートに掲載する際には、必ず読者に読みやすく加工する必要がある。とりわけ、読者から見ればJob_1とかJob_2は意味がわからないだろう。初見の読者さんも読みやすくするために表内の変数名を以下のように変えよう。

変数 平均値 標準偏差 最小値 最大値 有効ケース数
立憲民主党に対する感情温度 34.25 25.95 0 100 3000
イデオロギー 6.34 2.10 1 11 3000
政治関心 2.26 0.83 1 4 3000
性別:男性 0.50 0.50 0 1 3000
性別:女性 0.50 0.50 0 1 3000
年齢 47.34 15.63 18 75 3000
最終学歴 3.11 0.89 1 4 3000
職業:勤め 0.50 0.50 0 1 3000
職業:自営業 0.08 0.28 0 1 3000
職業:学生 0.05 0.21 0 1 3000
職業:専業主婦(夫) 0.20 0.40 0 1 3000
職業:無職・引退 0.15 0.35 0 1 3000
職業:その他 0.02 0.14 0 1 3000
世帯収入 6190334.00 4233639.26 643629 25286751 3000

名目変数と使い方

 それでは名目変数を含む重回帰分析を実装してみよう。重回帰モデルに名目変数を投入する方法する方法は実は簡単だ。それはlm()関数内のformulaにfactor化した名目変数を追加するだけである。Factor型変数が説明変数として投入されると、自動的にダミー変数に変換されてから投入される(つまり、ダミー変数に変換して一つ一つ投入しても問題ないということ)。ただし、全てのダミー変数が投入されるわけではなく、\(k-1\)個のダミー変数が投入されることには注意すること(\(k\)は当該factor型変数の水準数)。たとえば、性別(Gender)の場合、2つ値で構成されている変数であるため、ダミー変数も2つになるが、1つのみ投入される。同様に、職業(Job)変数も、1から6までの6つの値で構成されているため、ダミー変数も6つになるが、5つのみ投入される。ここで除外されたカテゴリーは「ベース・カテゴリー (base category)」、「参照カテゴリー/レファレンス・カテゴリー (reference category)」、「ベースライン (baseline)」などと呼ばれる(どの水準がベース・カテゴリーになるかは後述する)。

 それでは実装してみよう。GenderJob変数はデータ上、まだ数値型変数であるため、これらをfactor化する。また、単純にfactor化するだけでなく、値にラベルも割り当てよう。factor()関数の第1引数はfactor化する変数名を入れる。第2引数以降はlevelslabelsを指定する(引数名を明記するため、順番は関係ない)。levelsは元の値、labelsにはそれぞれの値に割り当てるラベルである。

Code 05
jes_df <- jes_df |>
  mutate(Gender = factor(Gender, levels = 1:2, labels = c("Male", "Female")),
         Job    = factor(Job, levels = 1:6, labels = c("Salary", "Self", "Student", 
                                                       "House", "Retire", "Etc")))

jes_df
# A tibble: 3,000 × 8
   Temp_Rikken Ideology Interest Gender   Age Education Job     Income
         <dbl>    <dbl>    <dbl> <fct>  <dbl>     <dbl> <fct>    <dbl>
 1          30        9        1 Female    69         4 Retire 4333994
 2          50        7        4 Female    47         3 Salary  979181
 3           0       11        2 Female    37         2 Salary 8498127
 4          50       11        2 Male      51         4 Self   7572654
 5          30        7        2 Male      38         4 Salary 6436713
 6           0       11        1 Male      71         2 Retire 3410276
 7          10        9        2 Male      47         3 Self   8652860
 8           0       11        1 Male      71         2 Retire  927703
 9          50        9        1 Male      75         4 Salary 4497693
10          55        6        2 Female    66         3 House  2419573
# ℹ 2,990 more rows

 Factor化が済んだら、回帰分析を行い、推定結果はdummy_fit1という名のオブジェクトとして格納する。

Code 06
dummy_fit1 <- lm(Temp_Rikken ~ Ideology + Interest + Gender + Age + 
                    Education + Job + Income, data = jes_df)

 summary()関数で推定結果を確認してみよう。

Code 07
summary(dummy_fit1)

Call:
lm(formula = Temp_Rikken ~ Ideology + Interest + Gender + Age + 
    Education + Job + Income, data = jes_df)

Residuals:
   Min     1Q Median     3Q    Max 
-50.58 -24.62   4.76  18.82  78.05 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   3.477e+01  3.558e+00   9.772  < 2e-16 ***
Ideology     -2.117e+00  2.202e-01  -9.616  < 2e-16 ***
Interest     -1.404e+00  6.100e-01  -2.302 0.021407 *  
GenderFemale  3.395e+00  1.071e+00   3.170 0.001540 ** 
Age           1.871e-01  3.723e-02   5.026 5.31e-07 ***
Education     1.970e+00  5.402e-01   3.648 0.000269 ***
JobSelf      -2.187e+00  1.737e+00  -1.259 0.208045    
JobStudent    5.775e+00  2.369e+00   2.438 0.014836 *  
JobHouse      2.172e+00  1.415e+00   1.535 0.124842    
JobRetire    -1.160e+00  1.519e+00  -0.764 0.444993    
JobEtc       -8.071e-01  3.393e+00  -0.238 0.812021    
Income       -1.539e-07  1.145e-07  -1.343 0.179231    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 25.27 on 2988 degrees of freedom
Multiple R-squared:  0.05472,   Adjusted R-squared:  0.05124 
F-statistic: 15.72 on 11 and 2988 DF,  p-value: < 2.2e-16

 連続変数の場合、これまでの解釈と同じである。たとえば、回答者のイデオロギー(Ideology)の係数を解釈してみよう。係数は約2.117であり、\(p < 0.05\)から統計的に有意である。これはIdeologyの値が上がると立民に対する感情温度が低くなることを意味する。Ideologyの値が上がるということは、より保守的なイデオロギーを持つことを意味し、言い換えれば、保守的な回答者ほど、立民に対する感情温度が低いことを意味する。具体的に係数を解釈するならば、「イデオロギーが1単位上がると(= 有権者が1単位保守的になると)、立民に対する感情温度は約2.113度下がる」ということになる。

 問題はダミー変数の解釈である。ダミー変数の解釈は「ベース・カテゴリーに比べ、〜」といった解釈となる。性別(Gender)変数の場合、投入されなかったのは女性ダミー(GenderFemale)であるため、男性ダミー(GenderMale)がベース・カテゴリーとなる。この場合、係数の解釈は「男性に比べ〜」となる。GenderFemaleの係数が約3.395ということは、「男性に比べ、女性は立民に対する感情温度が約3.395度高い」ことを意味する。

 回答者の職業(Job)についても同じことが言える。投入されなかったのは勤めダミー(JobSalary)であるため、勤めダミー(JobSalary)がベース・カテゴリーとなる。自営業ダミー(JobSelf)の係数は約-2.187であるが、これは「勤めの人に比べ、自営業の人は立民に対する感情温度が約2.187度低い」。ただし、\(p = 0.208\)ということで統計的に有意な関係はないため、具体的な係数を解釈する必要はなく、この場合は「勤めの人に比べ、自営業の人は立民に対する感情温度が異なるとは言えない」程度で十分である。一方、学生ダミー(JobStudent)の場合、係数は約5.775で、統計的に有意でもある。解釈は「勤めの人に比べ、学生は立民に対する感情温度が約5.8度高い」で良いだろう。

 一つ注意すべき点としては、ダミー変数はベース・カテゴリーによって統計的有意性が変わり得ることだ。名目変数を統制変数として投入しただけであれば、そもそも解釈は不要であるが、研究において主要説明変数であれば、ベース・カテゴリーの設定は慎重に行う必要がある。、「どのカテゴリー間を比べたいか」に注目することで設定すべきベース・カテゴリーが決まるだろう。

 今回は男性ダミーと勤めダミーが自動的にベース・カテゴリーになったが、このベース・カテゴリーは何によって決まるだろうか。その仕組は簡単である。Factor型変数の最初の水準(level)がベース・カテゴリーになる。あるfactor型変数の水準の順番を確認するためにはlevels()関数を使用する。

Code 08
levels(jes_df$Gender) # jes_dfのGender列の水準
[1] "Male"   "Female"
Code 09
levels(jes_df$Job) # jes_dfのJob列の水準
[1] "Salary"  "Self"    "Student" "House"   "Retire"  "Etc"    

 つまり、GenderJobの水準の順番を変えるとベース・カテゴリーが変更できる。Factor型変数の特定の水準を最初の水準にする場合は、Factor化済みの変数に対し、fct_relevel()を使用する。第1引数は水準の順番を変更する変数名を、第2引数には最初の水準にしたい水準名を"で囲んで入力する。これをGenderJob列に対して適用し、それぞれ最初の水準を"Male""Etc"にする。列の操作後、jes_dfは上書きせず、jes_df2と新しい名のオブジェクトとして格納し、jes_df2Gender列とJob列の水準を出力する。

Code 10
jes_df2 <- jes_df |>
  mutate(Gender = fct_relevel(Gender, "Female"), # Femaleを第1水準に
         Job    = fct_relevel(Job, "Etc"))       # Etcを第1水準に

levels(jes_df2$Gender) # jes_df2のGender列の水準
[1] "Female" "Male"  
Code 11
levels(jes_df2$Job) # jes_df2のJob列の水準
[1] "Etc"     "Salary"  "Self"    "Student" "House"   "Retire" 

 最初の水準が変更され、2番目以降の水準は既存の順番そのままになっていることが分かる1。それではjes_df2を用い、dummy_fit1と同じ推定をやってみよう。推定結果はdummy_fit2に格納し、summary()推定結果を確認してみよう。

Code 12
dummy_fit2 <- lm(Temp_Rikken ~ Ideology + Interest + Gender + Age + 
                    Education + Job + Income, data = jes_df2)
summary(dummy_fit2)

Call:
lm(formula = Temp_Rikken ~ Ideology + Interest + Gender + Age + 
    Education + Job + Income, data = jes_df2)

Residuals:
   Min     1Q Median     3Q    Max 
-50.58 -24.62   4.76  18.82  78.05 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  3.736e+01  4.936e+00   7.570 4.96e-14 ***
Ideology    -2.117e+00  2.202e-01  -9.616  < 2e-16 ***
Interest    -1.404e+00  6.100e-01  -2.302 0.021407 *  
GenderMale  -3.395e+00  1.071e+00  -3.170 0.001540 ** 
Age          1.871e-01  3.723e-02   5.026 5.31e-07 ***
Education    1.970e+00  5.402e-01   3.648 0.000269 ***
JobSalary    8.071e-01  3.393e+00   0.238 0.812021    
JobSelf     -1.380e+00  3.677e+00  -0.375 0.707369    
JobStudent   6.582e+00  4.111e+00   1.601 0.109437    
JobHouse     2.979e+00  3.483e+00   0.855 0.392472    
JobRetire   -3.533e-01  3.547e+00  -0.100 0.920665    
Income      -1.539e-07  1.145e-07  -1.343 0.179231    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 25.27 on 2988 degrees of freedom
Multiple R-squared:  0.05472,   Adjusted R-squared:  0.05124 
F-statistic: 15.72 on 11 and 2988 DF,  p-value: < 2.2e-16

 2つ以上のモデルを比較する際は推定結果を横に並べるとより見やすくなる。modelsummary()関数で2つのモデルを比較する際に非常に便利だ(予め{modelsummary}パッケージを読み込んでおくこと)。

Code 13
modelsummary(list(dummy_fit1, dummy_fit2))
 (1)   (2)
(Intercept) 34.774 37.362
(3.558) (4.936)
Ideology −2.117 −2.117
(0.220) (0.220)
Interest −1.404 −1.404
(0.610) (0.610)
GenderFemale 3.395
(1.071)
Age 0.187 0.187
(0.037) (0.037)
Education 1.970 1.970
(0.540) (0.540)
JobSelf −2.187 −1.380
(1.737) (3.677)
JobStudent 5.775 6.582
(2.369) (4.111)
JobHouse 2.172 2.979
(1.415) (3.483)
JobRetire −1.160 −0.353
(1.519) (3.547)
JobEtc −0.807
(3.393)
Income 0.000 0.000
(0.000) (0.000)
GenderMale −3.395
(1.071)
JobSalary 0.807
(3.393)
Num.Obs. 3000 3000
R2 0.055 0.055
R2 Adj. 0.051 0.051
AIC 27906.2 27906.2
BIC 27984.2 27984.2
Log.Lik. −13940.081 −13940.081
F 15.724
RMSE 25.22 25.22

 表が縦長なので、標準誤差と係数を同じ行にしてみよう。コードは覚える必要がなく、必要に応じてこのサポートページを参照するか、Google大先生に聞いてみれば良い。

Code 14
modelsummary(list(dummy_fit1, dummy_fit2),
             estimate  = "{estimate} ({std.error})",
             statistic = NULL)
(1) (2)
(Intercept) 34.774 (3.558) 37.362 (4.936)
Ideology -2.117 (0.220) -2.117 (0.220)
Interest -1.404 (0.610) -1.404 (0.610)
GenderFemale 3.395 (1.071)
Age 0.187 (0.037) 0.187 (0.037)
Education 1.970 (0.540) 1.970 (0.540)
JobSelf -2.187 (1.737) -1.380 (3.677)
JobStudent 5.775 (2.369) 6.582 (4.111)
JobHouse 2.172 (1.415) 2.979 (3.483)
JobRetire -1.160 (1.519) -0.353 (3.547)
JobEtc -0.807 (3.393)
Income 0.000 (0.000) 0.000 (0.000)
GenderMale -3.395 (1.071)
JobSalary 0.807 (3.393)
Num.Obs. 3000 3000
R2 0.055 0.055
R2 Adj. 0.051 0.051
AIC 27906.2 27906.2
BIC 27984.2 27984.2
Log.Lik. -13940.081 -13940.081
F 15.724
RMSE 25.22 25.22

 比較の結果から分かるのは、ダミー変数の係数のみ変化したことである。つまり、ダミー変数以外の変数の係数は少しも変わっていない(切片も変わるものの、切片は通常、解釈しない)。性別(Gender)のように2つ値のみ取る(= 1つのダミー変数だけ投入される)変数の係数は大きさは同じで符号だけが逆転される。また、標準誤差も同じであるため、統計的有意性も変わらない。したがって、解釈の変化も直感的である。

  • dummy_fit1男性に比べ、女性の立民に対する感情温度が約3.395度高い
  • dummy_fit2女性に比べ、男性の立民に対する感情温度が約3.395度低い

 一方、職業(Job)のように3つ以上の値のみ取る変数の係数は大きく変わる場合がある。たとえば、学生(JobStudent)の係数を解釈する場合は、以下のようになる。

  • dummy_fit1勤めの人に比べ、学生の立民に対する感情温度が約5.775度高い
  • dummy_fit2その他の職業の人に比べ、学生の立民に対する感情温度が約6.582度高いものの、統計的に有意な差はない。

 ベース・カテゴリーが変わったということは比較対象が変わったことを意味し、係数も当然ながら変わる。それでも各係数間の差は同じである。たとえば、dummy_fit1の場合、学生ダミー(JobStudent)の係数は5.775、その他ダミー(JobEtc)の係数は−0.807である。こと差は5.775 - (-0.807) = 6.582である。つまり、どのモデルでも「学生」の方が「その他」より、立民に対する感情温度が約6.582度高いことは変わらない。ただし、「学生 - 勤め」の差は統計的有意であるものの、「学生 - その他」の差は統計的有意ではなかっただけだ。

線形変換

単位変換

 もう一度、dummy_fit1の推定結果に戻ってみよう。今回注目する係数は世帯収入(Income)の係数である。推定モデルの係数のみ見たい時にはcoef()関数が便利だ。

Code 15
coef(dummy_fit1)
  (Intercept)      Ideology      Interest  GenderFemale           Age 
 3.477403e+01 -2.117306e+00 -1.404169e+00  3.395415e+00  1.871321e-01 
    Education       JobSelf    JobStudent      JobHouse     JobRetire 
 1.970356e+00 -2.187355e+00  5.775400e+00  2.172187e+00 -1.160311e+00 
       JobEtc        Income 
-8.070534e-01 -1.538790e-07 

 Incomeの傾き係数は約-1.538790e-07である。e-07は「\(\times\) 10-7」を意味し、ちなみに10-1は0.1、10-2は0.01である。つまり、-1.538790e-07は-1.538790e-07 = -1.538790 \(\times\) 10-7 = -0.000000153879である。この係数は「世帯収入が1円上がると、立憲民主党への感情温度が約0.000000153879度下がる」ことを意味する。Incomeの単位は1円であるため、係数そのまま解釈できる。しかし、これで良いだろうか。世帯収入(しかも年収)における1円の変動は無視できる微々たるものである。むしろ、1円の増加よりも100万円の増加の方が、より現実的な解釈であろう。この場合の解釈は「世帯収入が100万円上がると、立憲民主党への感情温度が-0.154度下がる」こととなる。Incomeの単位は1円であるため、係数に100万をかけるだけで良い(-0.000000153879 \(\times\) 1000000 = -0.153879)。しかし、解釈のたびに係数に100万をかけて解釈する必要があるのは非常に面倒であるし、0が多い分、計算ミスも生じやすい。したがって、Incomeの単位を予め100万円に変えておいた方が安全だろう。つまり、3000000(300万)を3に、12000000(1200万)を12に変換することである。

 Incomeを100万単位にするためには、Incomeを100万で割るだけで良い。ここではjes_dfIncomeの値を100万で割り、Income_mという新しい変数として追加し、jes_df3という新しいデータフレームを作成。新しく追加される変数名は何でも良いが、ここではmillionの頭文字を使用する。

Code 16
jes_df3 <- jes_df |>
  mutate(Income_m = Income / 1000000)

jes_df3
# A tibble: 3,000 × 9
   Temp_Rikken Ideology Interest Gender   Age Education Job     Income Income_m
         <dbl>    <dbl>    <dbl> <fct>  <dbl>     <dbl> <fct>    <dbl>    <dbl>
 1          30        9        1 Female    69         4 Retire 4333994    4.33 
 2          50        7        4 Female    47         3 Salary  979181    0.979
 3           0       11        2 Female    37         2 Salary 8498127    8.50 
 4          50       11        2 Male      51         4 Self   7572654    7.57 
 5          30        7        2 Male      38         4 Salary 6436713    6.44 
 6           0       11        1 Male      71         2 Retire 3410276    3.41 
 7          10        9        2 Male      47         3 Self   8652860    8.65 
 8           0       11        1 Male      71         2 Retire  927703    0.928
 9          50        9        1 Male      75         4 Salary 4497693    4.50 
10          55        6        2 Female    66         3 House  2419573    2.42 
# ℹ 2,990 more rows

 それではdummy_fit1と同じ推定をしてみよう。ただし、使用するデータはjes_dfでなく、jes_df3を使用する。また、世帯年収もIncomeの代わりにIncome_mを使う。推定結果はfit3という名のオブジェクトとして作業スペースに格納する。

Code 17
fit3 <- lm(Temp_Rikken ~ Ideology + Interest + Gender + Age + 
              Education + Job + Income_m, data = jes_df3)

 それではmodelsummary()を使ってdummy_fit1fit3の結果を比較してみよう。他の係数は一切変わらず、線形変換された変数の係数(と標準誤差)のみ変わったことが確認できる。Income_mの単位は100万円であるため、係数の解釈は「世帯収入が100万円上がる(= Income_mの値が1上がる)と、立憲民主党への感情温度が-0.154度下がる」になり、より解釈しやすくなる。

Code 18
modelsummary(list(dummy_fit1, fit3),
             estimate  = "{estimate} ({std.error})",
             statistic = NULL)
(1) (2)
(Intercept) 34.774 (3.558) 34.774 (3.558)
Ideology -2.117 (0.220) -2.117 (0.220)
Interest -1.404 (0.610) -1.404 (0.610)
GenderFemale 3.395 (1.071) 3.395 (1.071)
Age 0.187 (0.037) 0.187 (0.037)
Education 1.970 (0.540) 1.970 (0.540)
JobSelf -2.187 (1.737) -2.187 (1.737)
JobStudent 5.775 (2.369) 5.775 (2.369)
JobHouse 2.172 (1.415) 2.172 (1.415)
JobRetire -1.160 (1.519) -1.160 (1.519)
JobEtc -0.807 (3.393) -0.807 (3.393)
Income 0.000 (0.000)
Income_m -0.154 (0.115)
Num.Obs. 3000 3000
R2 0.055 0.055
R2 Adj. 0.051 0.051
AIC 27906.2 27906.2
BIC 27984.2 27984.2
Log.Lik. -13940.081 -13940.081
F 15.724 15.724
RMSE 25.22 25.22

スケールの逆転

 今回注目する係数はdummy_fit1の政治関心(Intrest)の係数である。政治関心の傾き係数は約-1.404であり、これは「Interestが1単位上がると、立憲民主党への感情温度が約1.404度下がる」と解釈できる。ただし、これだと「政治関心が高い人ほど、立憲民主党に反感を持つ」といったイメージを漂わせる。しかし、政治関心(Interest)の値は1が「関心あり」、2が「やや関心あり」、3が「やや関心なし」、4が「関心なし」という点に注意する必要がある。つまり、「Interestが1単位上がる」ということは、「政治関心が1単位下がる」ことを意味する。したがって、「Interestが1単位上がると、立憲民主党への感情温度が約1.404度下がる。」の意味は、「政治関心が1単位下がると、立憲民主党への感情温度が約1.404度下がる」か「政治関心が1単位上がると、立憲民主党への感情温度が約1.404度上がる」である。要は「Intrestと立民感情温度」は負の関係になるが、「政治関心と立民感情温度」は正の関係があることである。これは非常にややこしいし、解釈の際、ミスの原因にもなり得る。この問題を解決するためには、最初からInterestの値を逆転させることが有効だろう。つまり、Intrestの値が大きいほど政治関心が高まるようにすれば良い。

 このようなスケールの逆転は単なる引き算や掛け算でできる。

  • ケース1: 1〜\(m\)のスケールで測定された変数は\(m + 1\)から引くと、逆転される。今回の例がこれに該当する。Interestは1〜4であるため、5から引けばよい。
Code 19
x1 <- c(1, 2, 3, 4) # x1 <- 1:4 でもOK
x1
[1] 1 2 3 4
Code 20
5 - x1
[1] 4 3 2 1

 他にも変数の範囲(range)によって逆転の仕方が異なる。

  • ケース2: 0〜\(m\)のスケールで測定された変数は\(m\)から引くと、逆転される。
Code 21
x2 <- c(0, 1, 2, 3, 4, 5, 6) # x23 <- 0:6 でもOK
x2
[1] 0 1 2 3 4 5 6
Code 22
6 - x2
[1] 6 5 4 3 2 1 0
  • ケース3: \(-m\)\(m\)のスケールで測定された変数は-1をかけると、逆転される。
Code 23
x3 <- c(-3, -2, -1, 0, 1, 2, 3) # x3 <- -3:3 でもOK
x3
[1] -3 -2 -1  0  1  2  3
Code 24
x3 * (-1)
[1]  3  2  1  0 -1 -2 -3

 それではIntrestを逆転して、もう一度推定してみよう。jes_df3Interestの値を5から引き、Interest_rという新しい変数として追加し、jes_df3を上書きする。変数名は何でも良いが、ここではreverseの頭文字を使うとする。

Code 25
jes_df3 <- jes_df3 |>
  mutate(Interest_r = 5 - Interest)

jes_df3
# A tibble: 3,000 × 10
   Temp_Rikken Ideology Interest Gender   Age Education Job     Income Income_m
         <dbl>    <dbl>    <dbl> <fct>  <dbl>     <dbl> <fct>    <dbl>    <dbl>
 1          30        9        1 Female    69         4 Retire 4333994    4.33 
 2          50        7        4 Female    47         3 Salary  979181    0.979
 3           0       11        2 Female    37         2 Salary 8498127    8.50 
 4          50       11        2 Male      51         4 Self   7572654    7.57 
 5          30        7        2 Male      38         4 Salary 6436713    6.44 
 6           0       11        1 Male      71         2 Retire 3410276    3.41 
 7          10        9        2 Male      47         3 Self   8652860    8.65 
 8           0       11        1 Male      71         2 Retire  927703    0.928
 9          50        9        1 Male      75         4 Salary 4497693    4.50 
10          55        6        2 Female    66         3 House  2419573    2.42 
# ℹ 2,990 more rows
# ℹ 1 more variable: Interest_r <dbl>

 続いてfit3と同じ推定を行う。ただし、Intrestの代わりにIntrest_rを使用し、推定結果はfit4に格納する。

Code 26
fit4 <- lm(Temp_Rikken ~ Ideology + Interest_r + Gender + Age +
              Education + Job + Income_m, data = jes_df3)

summary(fit4)

Call:
lm(formula = Temp_Rikken ~ Ideology + Interest_r + Gender + Age + 
    Education + Job + Income_m, data = jes_df3)

Residuals:
   Min     1Q Median     3Q    Max 
-50.58 -24.62   4.76  18.82  78.05 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  27.75319    3.07847   9.015  < 2e-16 ***
Ideology     -2.11731    0.22019  -9.616  < 2e-16 ***
Interest_r    1.40417    0.60999   2.302 0.021407 *  
GenderFemale  3.39541    1.07112   3.170 0.001540 ** 
Age           0.18713    0.03723   5.026 5.31e-07 ***
Education     1.97036    0.54017   3.648 0.000269 ***
JobSelf      -2.18735    1.73706  -1.259 0.208045    
JobStudent    5.77540    2.36914   2.438 0.014836 *  
JobHouse      2.17219    1.41493   1.535 0.124842    
JobRetire    -1.16031    1.51895  -0.764 0.444993    
JobEtc       -0.80705    3.39325  -0.238 0.812021    
Income_m     -0.15388    0.11454  -1.343 0.179231    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 25.27 on 2988 degrees of freedom
Multiple R-squared:  0.05472,   Adjusted R-squared:  0.05124 
F-statistic: 15.72 on 11 and 2988 DF,  p-value: < 2.2e-16

 それでは、fit3fit4の結果を比較してみよう。

Code 27
modelsummary(list(fit3, fit4),
             estimate  = "{estimate} ({std.error})",
             statistic = NULL)
(1) (2)
(Intercept) 34.774 (3.558) 27.753 (3.078)
Ideology -2.117 (0.220) -2.117 (0.220)
Interest -1.404 (0.610)
GenderFemale 3.395 (1.071) 3.395 (1.071)
Age 0.187 (0.037) 0.187 (0.037)
Education 1.970 (0.540) 1.970 (0.540)
JobSelf -2.187 (1.737) -2.187 (1.737)
JobStudent 5.775 (2.369) 5.775 (2.369)
JobHouse 2.172 (1.415) 2.172 (1.415)
JobRetire -1.160 (1.519) -1.160 (1.519)
JobEtc -0.807 (3.393) -0.807 (3.393)
Income_m -0.154 (0.115) -0.154 (0.115)
Interest_r 1.404 (0.610)
Num.Obs. 3000 3000
R2 0.055 0.055
R2 Adj. 0.051 0.051
AIC 27906.2 27906.2
BIC 27984.2 27984.2
Log.Lik. -13940.081 -13940.081
F 15.724 15.724
RMSE 25.22 25.22

 他の係数は一切変わらず、線形変換された変数の係数(と標準誤差)の符号のみ変わることが確認できる。Intrest_rは高いほど政治に関心があることを意味するので、「政治関心が1単位上がると、立憲民主党に対する感情温度は約1.404度上がる」と解釈できるようになる。社会調査(世論調査)の場合、このような5件法、7件法で測定された変数がほとんどである(このような尺度を「リッカート尺度」と呼ぶ)。また、これらは最初の選択肢が「そう思う」や「とても当てはまる」など、ポジティブなものになっているケースが多いため、このようなミスはよく生じる。データ分析とはパソコン/ソフトウェアスキルだけでなく、このようにデータを読み取る能力も重要だ。

  1. たとえば、要素の順番が"A""B""C"である任意のベクトルvector1があるとし、vector1 <- fct_relevel(vector1, "B")を実行すると、要素の順番は"B""A""C"の順となり、vector1は上書きされる。つまり、fct_relevel()の第2引数で指定した要素以外の順番は元通りである。↩︎