オンライン上の補遺

大村 華子『日本の経済投票―なぜ日本で政権交代が起こらないのか?“』有斐閣、2025年

オンライン上の補遺の目的

『日本の経済投票―なぜ日本で政権交代が起こらないのか?』のオンライン上での付録です。本文には掲載できなかった分析の説明、補足の分析結果、分析のための統計ソフトウェアのコードなどを掲載しています。参考になさってください。

本書の構成は以下の通りです。各章の付録には、画面左側のナビゲーションからも、随時移動してもらうことができます。

序章 日本の経済投票についての問い 5

第1章 本書は何を明らかにするのか?(1)―データの素描からみる日本の経済投票 16

第2章 経済評価はどのように動いてきたのか? 41

第3章 経済評価は何によって動いてきたのか? 52

第4章 政治的支持はどのように動いてきたのか? 68

第5章 政治的支持は何によって動いてきたのか? 79

補論:時系列データ分析について考える 99

第6章 所得は経済評価、投票選択を決めるのか?―観察データの分析(1) 104

第7章 党派性、経済評価は投票選択を決めるのか?―観察データの分析(2) 122

補論:社会志向の経済評価と個人志向の経済評価-「個人志向の経済評価のレンズ」を考える 136

第8章 経済情報をどのように受け取っているのか?―実験データの分析(1) 140

第9章 経済情報をどのように推論・表明しているのか?―実験データの分析(2) 173

第10章 日本の経済投票はどのようなものなのか?―実験データの分析(3) 203

終章 日本の経済投票についての答え 218

以降の分析で利用するR packagesの一覧

library(fracdiff) #Ver.1.5-3
library(gridExtra) #Ver.2.3
library(gtable)  #Ver.0.3.6
library(knitr) #Ver.1.49
library(kableExtra) #Ver.1.4.0
library(LSX) #Ver.1.4.2
library(psych) #Ver.2.4.12
library(purrr) #Ver.1.0.4
library(quanteda) #Ver.4.2.0
library(quanteda.textstats) #Ver.0.97.2
library(readtext) #Ver.0.91
library(tidyverse) #Ver.2.00
library(tseries) #0.10-58
library(Zelig) #Ver.5.1.7
library(ZeligChoice) #Ver.09-6
library(zoo) #Ver.1.8-12

第1章:本章は何を明らかにするのか?

利用するデータの記述統計

第1章で利用する時事データの記述統計は、以下 表1-1のとおりである。

時事データの記述統計
統計量
平均 標準偏差 最小値 最大値 歪度 尖度
社会志向(+) 8.187 5.071 0.0 28.4 0.759 0.136
社会志向(-) 32.732 14.171 0.0 86.0 0.702 0.003
個人志向(+) 5.137 2.574 0.0 15.2 1.472 2.081
個人志向(-) 35.353 10.548 0.0 74.1 0.475 1.125
与党支持率 28.981 5.961 5.9 43.6 -0.992 2.401
野党支持率 16.902 5.935 4.7 33.9 -0.167 -0.872
無党派割合 49.045 11.190 18.6 71.4 -0.627 -0.187
内閣支持率 36.689 11.223 4.4 78.4 0.123 0.302
内閣不支持率 36.990 12.262 6.0 83.7 0.653 0.584

JESデータの記述統計を、JESの調査期ごとにまとめる。JES2の記述統計は、以下 表1-2のとおりである。第1章の分析に使う変数だけでなく、個人の属性に関する変数の記述統計も載せる。本文中で、共変量と呼んでいた変数のことである。

また本文図1.3の注でも述べたように、JESデータは分析に必要な変数をもとに成形したデータセットにもとづいたものとなっている。よって、コードブックなどで示されている集計値に必ずしも一致するわけではない。

JES IIデータの記述統計
統計量
平均 中央値 標準偏差 最小値 最大値
社会志向 2.167 2.000 0.891 1 5
個人志向 1.996 2.000 0.832 1 9
与党支持ダミー 0.546 1.000 0.498 0 1
野党支持ダミー 0.454 0.000 0.498 0 1
無党派ダミー 0.382 0.000 1.027 0 10
与党投票ダミー 0.521 1.000 0.500 0 1
野党投票ダミー 0.629 1.000 0.483 0 1
性別(女性割合) 0.497 0.000 0.500 0 1
年齢 48.696 48.000 14.977 20 90
教育歴 0.239 0.000 0.426 0 1
所得 8.798 8.571 5.361 0 20
雇用 0.829 1.000 0.376 0 1
政治関心 2.650 3.000 0.910 1 4

JES3の記述統計は、以下表1-3の通りである。

JES IIIデータの記述統計
統計量
平均 中央値 標準偏差 最小値 最大値
社会志向 2.099 2 0.961 1 5
個人志向 2.835 3 0.647 1 5
与党支持ダミー 0.456 0 0.498 0 1
野党支持ダミー 0.212 0 0.408 0 1
無党派ダミー 0.287 0 0.453 0 1
与党投票ダミー 0.511 1 0.500 0 1
野党投票ダミー 0.489 0 0.500 0 1
性別(女性割合) 0.468 0 0.499 0 1
年齢 51.916 53 16.781 17 101
教育歴 0.185 0 0.388 0 1
所得 3.662 3 1.901 1 9
雇用 0.720 1 0.449 0 1
政治関心 2.776 3 1.081 1 9

JES4の記述統計は、以下表1-4の通りである。

JES IVデータの記述統計
統計量
平均 中央値 標準偏差 最小値 最大値
社会志向 2.029 2 0.872 1 5
個人志向 2.759 3 0.690 1 5
与党支持ダミー 0.426 0 0.494 0 1
野党支持ダミー 0.282 0 0.450 0 1
無党派ダミー 0.225 0 0.417 0 1
与党投票ダミー 0.402 0 0.490 0 1
野党投票ダミー 0.592 1 0.491 0 1
性別(女性割合) 0.535 1 0.499 0 1
年齢 55.740 58 16.080 20 96
教育歴 0.197 0 0.398 0 1
所得 4.584 4 2.732 1 12
雇用 0.843 1 0.494 0 9
政治関心 2.829 3 1.099 1 9

JES5の記述統計は、以下表1-5の通りである。

JES Vデータの記述統計
統計量
平均 中央値 標準偏差 最小値 最大値
社会志向 2.140 2 0.951 1 5
個人志向 2.746 3 0.756 1 5
与党支持ダミー 0.238 0 0.426 0 1
野党支持ダミー 0.313 0 0.464 0 1
無党派ダミー 0.449 0 0.497 0 1
与党投票ダミー 0.497 0 0.500 0 1
野党投票ダミー 0.503 1 0.500 0 1
性別(女性割合) 0.464 0 0.499 0 1
年齢 47.004 47 14.367 18 75
教育歴 0.498 0 0.500 0 1
所得 5.434 5 3.148 1 14
雇用 0.847 1 0.360 0 1
政治関心 1.270 1 1.374 0 4

JES6の記述統計は、以下表1-6の通りである。

JES VIデータの記述統計
統計量
平均 中央値 標準偏差 最小値 最大値
社会志向 2.604 3 1.030 1 5
個人志向 2.810 3 0.801 1 5
与党支持ダミー 0.337 0 0.473 0 1
野党支持ダミー 0.202 0 0.402 0 1
無党派ダミー 0.461 0 0.499 0 1
与党投票ダミー 0.550 1 0.498 0 1
野党投票ダミー 0.450 0 0.498 0 1
性別(女性割合) 0.498 0 0.500 0 1
年齢 48.196 49 15.543 18 75
教育歴 0.921 1 0.894 0 3
所得 4.979 5 2.832 1 12
雇用 0.808 1 0.394 0 1
政治関心 2.715 3 0.817 1 4

本文の補足分析と各図表のコード

第1章で示した各図のRコードを下記に挙げる。分析の追試・再現にご利用いただきたい。但し、データに関しては共有が難しいものが多い。必要に応じて、筆者にご連絡ください。

図1-1:時事データをもとにした景気評価の推移

図1-2:時事データをもとにした暮らし向き評価の推移

#----------------------------
# 関数の読み込み(plot1_1.R)
#----------------------------

source("plot1_1.R") #図1-4のコードも参照

#------------------
# データの読み込み
#------------------

dat1_1 <- read.csv("approve_economy.csv", fileEncoding = "SJIS") %>%
  mutate(
    sociotropic_gd = q5c1 + q5c2,
    sociotropic_bd = q5c4 + q5c5,
    liv_gd         = q3c1 + q3c2,
    liv_bd         = q3c4 + q3c5
  )

df_keiki <- dat1_1 %>%
  select(yearmon, year_graph, sociotropic_gd, sociotropic_bd)

df_kurashi <- dat1_1 %>%
  select(yearmon, year_graph, liv_gd, liv_bd)

#------------------
#  プロットの作成
#------------------

g1_1 <- plot1_1(df_keiki, "sociotropic_bd", "sociotropic_gd", "景気への評価(-)", "景気への評価(+)")
g1_2 <- plot1_1(df_kurashi, "liv_bd", "liv_gd", "暮らし向きへの評価(-)", "暮らし向きへの評価(+)")


grid.arrange(g1_1[[1]], g1_1[[2]], g1_1[[3]], ncol = 3, widths = c(4/9, 1/9, 4/9))
grid.arrange(g1_2[[1]], g1_2[[2]], g1_2[[3]], ncol = 3, widths = c(4/9, 1/9, 4/9))

図1-3:JESデータをもとにした景気評価の推移

【補足】JESデータをもとにした暮らし向き評価の推移

以下では、本文で掲載のなかった「暮らし向き評価」についての図も掲載する。

なお本文で言及できなかった点を、下記に断る。

・ 2012年については、衆議院選挙後・全国インターネット調査のデータを用いた。同年については、選挙後調査において経済評価データが含まれているためである。

・ 2013年については、参院選事前インターネット調査のデータを用いた。

・ 2014年については、衆院選事前インターネット調査のデータを用いた。

・ 2016年については、参院選事前郵送調査のデータを用いた。

#---------------------------
# 関数の読み込み(plot1_3.R)
#---------------------------

source("plot1_3.R")

#------------------
# データの読み込み
#------------------

dat1_3 <- read.csv("df_ec_keiki.csv") %>%
  mutate(否定 = 否定*100,
         肯定 = 肯定*100)
  
#----------------------
# プロットの作成と表示
#----------------------

g1_3 <- plot1_3(dat1_3, "景気への評価(-)", "景気への評価(+)")

grid.arrange(g1_3[[1]], g1_3[[2]], g1_3[[3]], ncol = 3, widths = c(4/9, 1/9, 4/9))
#景気評価に関する図は出力を省略。

図1-4:日本の有権者の与党支持率、野党支持率、無党派層の割合の推移

#------------------
# データの読み込み
#------------------

dat1_4 <- read_csv("approve_economy.csv", locale = locale(encoding = "SJIS")) %>%
  dplyr::select(yearmon, year_graph, ruling, opposite, indep)
#(上述の"approve_economy.csv"データに依拠、データの閲覧・入手については筆者にご相談ください)

#---------------------------------------
# プロットの作成(plot1_1.Rの内部も参照)
#---------------------------------------

g.mid<-ggplot(dat1_4,aes(x=1,y=year_graph))+
  geom_text(aes(label=year_graph))+
  geom_segment(aes(x=0.94,xend=0.96,yend=year_graph))+
  geom_segment(aes(x=1.04,xend=1.065,yend=year_graph))+
  ggtitle("")+
  ylab(NULL)+
  theme(axis.title=element_blank(),
        panel.grid=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        panel.background=element_blank(),
        axis.text.x=element_text(color=NA),
        axis.ticks.x=element_line(color=NA),
        plot.margin = unit(c(1,-1,1,-1), "mm")) +
  scale_x_reverse()


g1 <- ggplot(data = dat1_4, aes(x = as.Date(yearmon,"%Y-%m-%d"), y = ruling)) +
  geom_bar(stat = "identity") +  ggtitle("与党支持率") +
  theme(axis.title.x = element_blank(), 
        axis.title.y = element_blank(), 
        axis.text.y = element_blank(), 
        axis.ticks.y = element_blank(), 
        plot.margin = unit(c(1,-1,1,0), "mm")) +
  coord_flip()+
  ylim(0, 75)+
  xlab("年")+
  ylab("与党支持率")+
  theme(text = element_text(family = "jpfont"))+
  theme_bw()


g2 <- ggplot(data = dat1_4, aes(x = as.Date(yearmon,"%Y-%m-%d"), y = opposite)) +
  geom_bar(stat = "identity") + ggtitle("野党支持率") +
  theme(axis.title.x = element_blank(), 
        axis.title.y = element_blank(), 
        axis.text.y = element_blank(), 
        axis.ticks.y = element_blank(), 
        plot.margin = unit(c(1,-1,1,0), "mm")) +
  coord_flip()+
  ylim(0, 75)+
  xlab("年")+
  ylab("野党支持率")+
  theme(text = element_text(family = "jpfont"))+
    theme_bw()


g3 <- ggplot(data = dat1_4, aes(x = as.Date(yearmon,"%Y-%m-%d"), y = indep)) +
  geom_bar(stat = "identity") + ggtitle("無党派層割合") +
  theme(axis.title.x = element_blank(), 
        axis.title.y = element_blank(), 
        axis.text.y = element_blank(), 
        axis.ticks.y = element_blank(), 
        plot.margin = unit(c(1,-1,1,0), "mm")) +
  coord_flip()+
  xlab("年")+
  ylab("無党派割合")+
  ylim(0, 75)+
  theme(text = element_text(family = "jpfont"))+
    theme_bw()


gg1 <- ggplot_gtable(ggplot_build(g1))
gg2 <- ggplot_gtable(ggplot_build(g2))
gg3 <- ggplot_gtable(ggplot_build(g3))

gg.mid <- ggplot_gtable(ggplot_build(g.mid))

grid.arrange(gg1,gg.mid,gg2,gg.mid,gg3,ncol=5,widths=c(4/14,1/14,4/14,1/14,4/14))

図1-5:支持政党への残留と支持政党からの移動

#------------------
# データの読み込み
#------------------

dat1_5 <- read_csv("psupport_move.csv")

#------------
# 要件の設定
#------------

dat1_5 <- dat1_5 %>%
  mutate(Condition = factor(Condition, levels = c("残留: 与党→与党", "残留: 野党→野党", 
                                                  "離脱: 与党→野党", "離脱: 野党→与党")))

#----------------
# プロットの作成
#----------------

ggplot(dat1_5, aes(x = 年, y = Ratio * 100, fill = Condition)) +
  geom_bar(stat = "identity", position = position_dodge(), color = "black") +
  geom_text(aes(label = sprintf("%.1f", Ratio * 100)), 
            position = position_dodge(width = 0.9), 
            vjust = -0.5, size = 4, color = "black") +
  facet_wrap(~Condition, ncol = 2) +
  scale_fill_grey(start = 0.5, end = 0.8) + 
  labs(title = "", x = "年", y = "割合(%) ") +
  theme_bw(base_size = 14) +
  theme(
    legend.position = "none", 
    panel.grid.major = element_line(size = 0.5),
    panel.grid.minor = element_blank(),
    strip.text = element_text(face = "bold", size = 12) 
  ) +
  geom_label(aes(label = sprintf("%.1f", Ratio * 100)), 
             position = position_dodge(width = 0.9), 
             vjust = -0.5, size = 4, fill = "white", color = "black", label.size = 0.3, 
             label.padding = unit(0.2, "lines"))

dat1_5作成のためのコードの詳細については、筆者にお問い合わせください。例は次の通り。

#------------------
# データの読み込み
#------------------

jes2019 <- read_csv("2019jes.csv", locale = locale(encoding = "SJIS"))

#-------------------------------
# 「与党―与党」のダミー変数作成
#-------------------------------

jes2019 <- jes2019 %>%
  mutate(
    rul_rul_dum2019 = case_when(
      (Q2 %in% c("自民党", "公明党")) & (aQ7 %in% c("自民党", "公明党")) ~ 1,
      TRUE ~ 0
    )
  )

#-------------------------------
# 「与党―野党」のダミー変数作成
#-------------------------------

jes2019 <- jes2019 %>%
  mutate(
    rul_op_dum2019 = case_when(
      (aQ7 %in% c("自民党", "公明党")) &
      (Q2 %in% c("立憲民主", "社民党", "共産党", "次世代の", "みんなの",
                 "希望の党", "新党改革", "日本未来の党", "日本維新", "その他")) ~ 1,
      TRUE ~ 0
    )
  )

【補足】政党支持と投票選択間のすべての組み合わせを使った分析

第1章・本文では、政党支持と投票の組み合わせのうち、一部のみを図示した。組み合わせのすべてを含めて、残留と離脱の流れを表す図を以下に示す。以下の図からは、与党支持者の多くがそのまま与党投票に残存していることが見てとれる。

図1―6: 党派別の社会志向の経済評価

library(tidyverse)

#------------------
# データの読み込み
#------------------

dat1_6 <- read_csv("df_temp.csv", locale = locale(encoding = "SJIS"))

dat1_6_1 <- dat1_6 %>%
  select(yearmon, sociotropic_gd_rul, sociotropic_bd_rul) %>%
  mutate(政党支持 = "与党派")

dat1_6_2 <- dat1_6 %>%
  select(yearmon, sociotropic_gd_op, sociotropic_bd_op) %>%
  mutate(政党支持 = "野党派")

dat1_6_3 <- dat1_6 %>%
  select(yearmon, sociotropic_gd_indep, sociotropic_bd_indep) %>%
  mutate(政党支持 = "無党派")

colnames(dat1_6_1) <- colnames(dat1_6_2) <- colnames(dat1_6_3) <- c("年", "肯定", "否定", "政党支持")
dat1_6 <- bind_rows(dat1_6_1, dat1_6_2, dat1_6_3) %>%
  mutate(across(c(肯定, 否定), ~ . * 100))

dat1_6 <- dat1_6 %>%
  pivot_longer(cols = c(肯定, 否定), names_to = "景気評価", values_to = "値") %>%
  mutate(政党支持 = factor(政党支持, levels = c("与党派", "野党派", "無党派")))

#------------------
# プロットの作成
#------------------

ggplot(data = dat1_6, aes(x = as.Date(年,"%Y-%m-%d"), y = 値)) +
  geom_line(aes(color = 景気評価), size = 1) +
  scale_color_manual(values = c("grey", "black")) +
  xlab("年")+
  facet_wrap(~政党支持,ncol=1)+
  ylab("割合(%)")+ 
  theme_bw()+
theme(text = element_text(family = "jpfont"))

図1―7:党派別の景気評価の肯定的/否定的回答の割合

#----------------------------
# 関数の読み込み(plot1_7.R)
#----------------------------

source("plot1_7.R")

#------------------------------------------------
# データの読み込みとプロットの作成: 社会志向評価
#------------------------------------------------

dat1_7socio <- read.csv("df_ec_partisan.csv")
g1_7socio <- plot1_7(dat1_7socio, "景気評価", "景気")


grid.arrange(g1_7socio$g1, g1_7socio$g.mid, g1_7socio$g2, 
             g1_7socio$g.mid, g1_7socio$g3, 
             ncol = 5, widths = c(4/14, 1/14, 4/14, 1/14, 4/14))

【補足】党派別の暮らし向き評価の肯定的/否定的回答の割合

図1-10:与党支持率と内閣支持率の関係に関するローリング回帰分析

以下、図1-10のコードはPythonによるものである。本文においては、与党支持率内閣支持率の関係と社会志向の肯定的経済評価と内閣支持率の関係についてのローリング回帰分析の結果を報告した。以下では、下記の結果について分析結果を報告する。

①個人志向の肯定的な経済評価と内閣支持率の関係

②社会志向の否定的な経済評価と内閣不支持率の関係

③個人志向の否定的な経済評価と内閣不支持率の関係

④野党支持率と内閣不支持率の関係

#------------------
# モジュールの導入
#------------------


import statsmodels.api as sm
import pandas

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

import pandas_datareader as pdr
from statsmodels.regression.rolling import RollingOLS
import matplotlib.pyplot as plt
import seaborn
seaborn.set_style('darkgrid')
pd.plotting.register_matplotlib_converters()
%matplotlib inline


#------------------
# データの読み込み
#------------------

df = pd.read_csv('df_fecm.csv',
                  index_col='yearmon', parse_dates=True,encoding='cp932')
print(df)

#------------------
# 内生変数の設定
#------------------

endog = df.approve
endog

#---------------------------------------
# 外生変数の設定:社会志向の経済評価(+)
#---------------------------------------

exog = sm.add_constant(df['ruling'])

#----------------------
# 推定と推定結果の確認
#----------------------

rols_ruling = RollingOLS(endog, exog, window=60)
rres_ruling = rols_ruling.fit()
params = rres_ruling.params
print(params.head())
print(params.tail())

#------------------
# プロットの作成
#------------------

fig_ruling= rres_dis_liv.plot_recursive_coefficient(variables=['ruling'], figsize=(14,6))

【補足】個人志向の肯定的経済評価と内閣支持率の関係に関するローリング回帰分析

【補足】社会志向の否定的経済評価と内閣不支持率の関係に関するローリング回帰分析

【補足】個人志向の否定的経済評価と内閣不支持率の関係に関するローリング回帰分析

【補足】野党支持率と内閣不支持率の関係に関するローリング回帰分析

第2章:経済評価はどのように動いてきたのか?

本文の補足分析と各図表のコード

図2-2:時事データの経済質問における回答割合の推移

#---------------------------
# 関数の読み込み(plot2_2.R)
#---------------------------

source("plot2_2.R")

#------------------
# データの読み込み
#------------------

dat2_2 <- read.csv("approve_economy.csv", fileEncoding = "SJIS")


# 暮らし向き
cols1 <- c("q3c1", "q3c2", "q3c3", "q3c4", "q3c5", "q3c6")
labels1 <- c("大変楽になった", "やや楽になった", "どちらでもない", "やや苦しくなった", "大変苦しくなった", "わからない")
p2_2_1 <- plot2_1(dat2_2, cols1, labels1, "暮らし向き")

# 物価
cols2 <- c("q4c3", "q4c1", "q4c2", "q4c4")
labels2 <- c("今より下がると思う", "落ち着いてきたと思う", "上がると思う", "わからない")
p2_2_2 <- plot2_1(dat2_2, cols2, labels2, "物価")

# 景気
cols3 <- c("q5c1", "q5c2", "q5c3", "q5c4", "q5c5", "q5c6")
labels3 <- c("確かに良くなってきたと思う", "やや良くなってきたと思う", "どちらでもない", "やや悪くなってきたと思う", "確かに悪くなってきたと思う", "わからない")
p2_2_3 <- plot2_1(dat2_2, cols3, labels3, "景気")

# これから先の生活
cols4 <- c("q6c1", "q6c2", "q6c3", "q6c4")
labels4 <- c("良くなっていく", "変わりない", "悪くなっていく", "どちらともいえない")
p2_2_4 <- plot2_1(dat2_2, cols4, labels4, "これから先の生活")

#------------------
# プロットの作成
#------------------

gridExtra::grid.arrange(p2_2_1, p2_2_2, p2_2_3, p2_2_4, ncol = 2, nrow = 2)

表2-2:2 種類の経済評価に関する実数和分分析の結果

#--------------------------------- 
# FIの計算:社会志向の経済評価(+)
#--------------------------------- 

fdGPH(na.omit(sociotropic_gd))

#--------------------------------- 
# FIの計算:社会志向の経済評価(-)
#--------------------------------- 

fdGPH(na.omit(sociotropic_bd))

#--------------------------------- 
# FIの計算:個人志向の経済評価(+)
#--------------------------------- 

fdGPH(na.omit(liv_gd))

#--------------------------------- 
# FIの計算:個人志向の経済評価(-)
#--------------------------------- 

fdGPH(na.omit(liv_bd))

【補足】2種類の経済評価変数についてのAugmented Dickey-Fuller testとKPSS testの結果

#---------------
# データの設定
#--------------- 

vars <- list(
  "社会志向(+)" = sociotropic_gd,
  "社会志向(-)" = sociotropic_bd,
  "個人志向(+)" = liv_gd,
  "個人志向(-)" = liv_bd
)

#---------------- 
# 関数の読み込み
#----------------

source("adf_kpss_test.R")


#---------------- 
# 分析結果の表化
#----------------

df_results <- map_dfr(
  names(vars),
  ~ adf_kpss_test(vars[[.x]]) %>%
    mutate(Variable = .x)   
) %>%
  select(Variable, everything())  

#----------- 
# 表の出力
#----------- 

df_results %>%
  kbl(
    format = "html",
    digits = 4,                     
    caption = "ADF & KPSS 検定結果一覧"
  ) %>%
  kable_styling(full_width = FALSE)

図2-3:2種類の経済評価と政治経済的出来事の関係

#---------------------------- 
# 関数の読み込み(plot2_3.R)
#---------------------------- 

source(plot2_3.R)

#------------------
# データの読み込み
#------------------

dat2_3 <- read.csv("approve_economy.csv", fileEncoding = "SJIS") %>%
  mutate(
    sociotropic_gd = q5c1 + q5c2,
    sociotropic_bd = q5c4 + q5c5,
    liv_gd         = q3c1 + q3c2,
    liv_bd         = q3c4 + q3c5
  )

#---------------- 
# イベントの設定
#----------------

events <- tibble(
  date = as.Date(c("1973-10-01", "1989-04-01", "1990-01-01", "1997-07-01", "2008-09-01",
                   "2011-03-01", "2012-12-01")),
  label = c("第1次石油ショック(1973)", "消費税導入(1989)", "バブル経済崩壊(1990)", 
            "アジア通貨危機(1997)", "グローバル経済危機(2008)", "東日本大震災(2011)", 
            "アベノミクス導入(2012)")
)


#-------------- 
# データの整形
#--------------

dat2_3keiki <- dat2_3 %>%
  select(yearmon, sociotropic_gd, sociotropic_bd) %>%
  pivot_longer(cols = -yearmon, names_to = "経済評価", values_to = "value") %>%
  mutate(経済評価 = recode(経済評価, sociotropic_gd = "肯定", sociotropic_bd = "否定"))

dat2_3kurashi <- dat2_3 %>%
  select(yearmon, liv_gd, liv_bd) %>%
  pivot_longer(cols = -yearmon, names_to = "経済評価", values_to = "value") %>%
  mutate(経済評価 = recode(経済評価, liv_gd = "肯定", liv_bd = "否定"))

#--------------
# プロット作成
#--------------

p1 <- plot2_3(dat2_3keiki , "A:社会志向の経済評価の推移と政治経済的出来事", 45)
p2 <- plot2_3(dat2_3kurashi, "B:個人志向の経済評価の推移と政治経済的出来事", 28)

windows(30, 20)
grid.arrange(p1, p2, nrow = 2)

図2-4:2種類の経済評価と景気循環の関係

#---------------------------- 
# 関数の読み込み(plot2_4.R)
#---------------------------- 

source("plot2_4.R")

#------------------
# データの読み込み
#------------------

dat2_4 <- read.csv("approve_economy.csv", fileEncoding = "SJIS") %>%
  mutate(
    sociotropic_gd = q5c1 + q5c2,
    sociotropic_bd = q5c4 + q5c5,
    liv_gd         = q3c1 + q3c2,
    liv_bd         = q3c4 + q3c5
  )

#---------------------------- 
# 景気循環のセグメントを定義
#---------------------------- 

business_cycles <- data.frame(
  start = as.Date(c("1963-12-01", "1965-10-01", "1971-12-01", "1975-03-01",
                    "1977-10-01", "1983-02-01", "1986-11-01", "1993-10-01",
                    "1999-12-01", "2002-01-01", "2009-03-01", "2012-11-01")),
  end = as.Date(c("1964-10-01", "1970-07-01", "1973-11-01", "1977-01-01",
                  "1980-02-01", "1985-06-01", "1991-02-01", "1997-05-01",
                  "2000-11-01", "2008-02-01", "2012-03-01", "2020-05-01"))
)



#----------------
# プロットの作成
#----------------

p1 <- plot2_4(dat2_4, "sociotropic_gd", "sociotropic_bd", 
              "A: 社会志向の経済評価の推移と景気循環", 48, "社会志向の経済評価")

p2 <- plot2_4(dat2_4, "liv_gd", "liv_bd", 
              "B: 個人志向の経済評価の推移と景気循環", 18, "個人志向の経済評価")

windows(width = 240, height = 180)
grid.arrange(p1, p2, nrow = 2)

表2-3:党派別の社会志向の否定的経済評価・党派性差異の記述統計

本文に掲載した否定的な社会志向の経済評価の党派別データの記述統計のコードは以下のとおりである。

#------------------ 
# データの読み込み
#------------------

dat2_3 <- read_csv("approve_economy.csv", locale = locale(encoding = "SJIS")) %>%
  mutate(
    与党派_社会志向_否定 = sociotropic_bd_rul,
    野党派_社会志向_否定 = sociotropic_bd_op,
    無党派_社会志向_否定 = sociotropic_bd_indep,
    与野党派間差異 = sociotropic_bd_rul - sociotropic_bd_op,
    与無党派間差異 = sociotropic_bd_rul - sociotropic_bd_indep,
    野無党派間差異 = sociotropic_bd_op - sociotropic_bd_indep
  ) %>%
  select(与党派_社会志向_否定, 野党派_社会志向_否定, 無党派_社会志向_否定, 
         与野党派間差異, 与無党派間差異, 野無党派間差異)

#----------------
# 記述統計の抽出
#----------------

stats <- dat2_3 %>%
  describe() %>%
  select(mean, sd, min, max, skew, kurtosis) %>%
  rename(平均 = mean, 標準偏差 = sd, 最小値 = min, 最大値 = max, 歪度 = skew, 尖度 = kurtosis)

#---------- 
# 表の作成
#---------- 

stats %>%
  knitr::kable(
    format = "html",
    booktabs = TRUE, 
    caption = "党派別の社会志向の肯定的経済評価・党派性差異の記述統計",
    digits = 3
  ) %>%
  add_header_above(header = c(" " = 1, "統計量" = 6)) %>%
  kable_styling(bootstrap_options = "striped", full_width = FALSE)

【補足】党派別の社会志向の肯定的経済評価・党派性差異の記述統計

党派別の社会志向の否定的経済評価・党派性差異の記述統計
統計量
平均 標準偏差 最小値 最大値 歪度 尖度
与党派・社会志向(+) 0.085 0.057 0.002 0.262 0.626 -0.302
野党派・社会志向(+) 0.070 0.068 0.000 0.401 1.923 4.358
無党派・社会志向(+) 0.056 0.032 0.003 0.160 0.715 0.119
与野党派間差異 0.015 0.061 -0.267 0.166 -1.497 4.289
与無党派間差異 0.029 0.035 -0.036 0.194 0.937 1.651
野無党派間差異 0.014 0.058 -0.071 0.307 2.221 5.610

【補足】党派別の個人志向の肯定的経済評価・党派性差異の記述統計

党派別の社会志向の肯定的経済評価・党派性差異の記述統計
統計量
平均 標準偏差 最小値 最大値 歪度 尖度
与党派・個人志向(+) 0.049 0.027 0.000 0.197 0.759 2.262
野党派・個人志向(+) 0.040 0.045 0.000 0.360 3.310 13.731
無党派・個人志向(+) 0.314 0.077 0.171 0.550 0.575 0.047
与野党派間差異 0.009 0.052 -0.339 0.175 -2.503 10.662
与無党派間差異 -0.265 0.090 -0.531 -0.084 -0.411 -0.161
野無党派間差異 -0.274 0.098 -0.543 0.005 -0.034 0.000

【補足】党派別の個人志向の否定的経済評価・党派性差異の記述統計

党派別の個人志向の否定的経済評価・党派性差異の記述統計
統計量
平均 標準偏差 最小値 最大値 歪度 尖度
与党派・個人志向(-) 0.313 0.109 0.100 0.677 0.566 0.039
野党派・個人志向(-) 0.035 0.010 0.012 0.060 -0.089 -0.635
無党派・個人志向(-) 0.323 0.160 0.000 1.000 1.105 3.891
与野党派間差異 0.278 0.114 0.066 0.656 0.566 -0.034
与無党派間差異 -0.010 0.169 -0.677 0.627 0.323 3.560
野無党派間差異 -0.288 0.162 -0.987 0.060 -1.116 3.808

表2-4:党派別の経済評価に関する実数和分分析の結果

#-----------------
# データの読み込み
#-----------------

dat2_4 <- read_csv("approve_economy.csv", locale = locale(encoding = "SJIS"))

#-------------------
# データリストの作成
#-------------------

dat2_4 <- list(
  dat$sociotropic_gd_rul, dat$sociotropic_gd_op, dat$sociotropic_gd_indep,
  dat$sociotropic_bd_rul, dat$sociotropic_bd_op, dat$sociotropic_bd_indep,
  dat$egotropic_gd_rul,   dat$egotropic_gd_op,   dat$egotropic_gd_indep,
  dat$egotropic_bd_rul,   dat$egotropic_bd_op,   dat$egotropic_bd_indep
)

labels <- c(
  "与党派・社会志向(+)", "野党派・社会志向(+)", "無党派・社会志向(+)",
  "与党派・社会志向(-)", "野党派・社会志向(-)", "無党派・社会志向(-)",
  "与党派・個人志向(+)", "野党派・個人志向(+)", "無党派・個人志向(+)",
  "与党派・個人志向(-)", "野党派・個人志向(-)", "無党派・個人志向(-)"
)

#----------
# FIの計算
#----------

results2_4 <- lapply(data_list2_4, function(data) {
  res <- fdGPH(na.omit(data))
  c(round(res$d, 3), round(res$sd.reg, 3))
})


#------------
# 結果の表化
#------------

results_df2_4 <- results %>%
  do.call(rbind, .) %>%
  as.data.frame() %>%
  setNames(c("d", "sd.reg")) %>%
  mutate(Variable = labels) %>%
  select(Variable, everything())

【補足】党派別の経済評価変数についてのDickey-Fuller testとKPSS testの結果

#-----------------
# データの読み込み
#-----------------

data_list2_4 <- read_csv("approve_economy.csv", locale = locale(encoding = "SJIS")) %>%
  select(
    sociotropic_gd_rul, sociotropic_gd_op, sociotropic_gd_indep,
    sociotropic_bd_rul, sociotropic_bd_op, sociotropic_bd_indep,
    egotropic_gd_rul,   egotropic_gd_op,   egotropic_gd_indep,
    egotropic_bd_rul,   egotropic_bd_op,   egotropic_bd_indep
  ) %>%
  as.list()

#----------------------
#各変数に対応するラベル
#----------------------

labels <- c(
  "与党派・社会志向(+)", "野党派・社会志向(+)", "無党派・社会志向(+)",
  "与党派・社会志向(-)", "野党派・社会志向(-)", "無党派・社会志向(-)",
  "与党派・個人志向(+)", "野党派・個人志向(+)", "無党派・個人志向(+)",
  "与党派・個人志向(-)", "野党派・個人志向(-)", "無党派・個人志向(-)"
)

#----------------
# 分析結果の表化
#----------------

df_results2_4 <- map2_dfr(data_list2_4, labels, ~{
  series <- na.omit(.x)         # NA を除去
  
  # ADF 検定
  adf_res <- adf.test(series)
  adf_stat <- round(adf_res$statistic, 3)
  adf_pval <- round(adf_res$p.value, 4)
  
  # KPSS 検定
  kpss_res <- kpss.test(series, null = "Level")
  kpss_stat <- round(kpss_res$statistic, 3)
  kpss_pval <- round(kpss_res$p.value, 4)
  
  tibble(
    Variable  = .y,         
    ADF_Stat  = adf_stat,
    ADF_pval  = adf_pval,
    KPSS_Stat = kpss_stat,
    KPSS_pval = kpss_pval
  )
})

#----------
# 表の出力
#----------

df_results2_4 %>%
  kbl(
    format = "html",
    caption = "ADF & KPSS検定の結果",
    digits = 3
  ) %>%
  kable_styling(full_width = FALSE)
ADF & KPSS検定の結果
Variable ADF_Stat ADF_pval KPSS_Stat KPSS_pval
与党派・社会志向(+) -2.888 0.202 0.225 0.100
野党派・社会志向(+) -4.424 0.010 0.200 0.100
無党派・社会志向(+) -3.042 0.137 0.155 0.100
与党派・社会志向(-) -2.521 0.356 0.202 0.100
野党派・社会志向(-) -2.594 0.326 0.209 0.100
無党派・社会志向(-) -2.237 0.476 0.195 0.100
与党派・個人志向(+) -3.274 0.076 0.652 0.018
野党派・個人志向(+) -5.832 0.010 0.974 0.010
無党派・個人志向(+) -2.536 0.350 2.074 0.010
与党派・個人志向(-) -3.012 0.150 2.232 0.010
野党派・個人志向(-) -2.503 0.364 0.541 0.032
無党派・個人志向(-) -5.256 0.010 2.216 0.010

図2-5:党派性と社会志向の肯定的経済評価

#------------------ 
# 関数の読み込み
#------------------

source("plot2_5df.R")
source("plot2_5_1.R")
source("plot2_5_2.R")


#------------------ 
# データの読み込み
#------------------

dat2_5 <- read.csv("approve_economy.csv", fileEncoding = "SJIS")
attach(dat2_5)
year <- read.csv("year.csv")
attach(year)


#------------------ 
# ハイライトの設定
#------------------

temp <- data.frame(
  start = as.Date( '2009-09-01'), 
  end   = as.Date('2012-11-01'))


#------------------ 
# プロットの作成
#------------------

#---- 社会志向 (+):原系列
df_parec1 <- plot2_5df(year$yearmon, cbind(sociotropic_gd_rul, sociotropic_gd_op), c("年", "与党派", "野党派"))
g1 <- plot2_5_1(df_parec1, "A:党派別の社会志向の経済評価(+)","年", "value", "党派別経済効果")

#---- 社会志向 (+): 差異
socposdiff = sociotropic_gd_rul-sociotropic_gd_op
df_parec2 <- create_dataframe(year$yearmon, socposdiff, c("年", "党派性差異"))
g2 <- plot2_5_2(df_parec2, "B:党派別の社会志向の党派性差異(+)", "党派性差異", "value")


grid.arrange(g1, g2, ncol = 1)

図2-6:党派性と社会志向の否定的経済評価

#------------------ 
# プロットの作成
#------------------

# 社会志向 (-):2系列併記
df_parec3 <- plot2_5df(year$yearmon, cbind(sociotropic_bd_rul, sociotropic_bd_op), c("年", "与党派", "野党派"))
g3 <- plot2_5_1(df_parec3, "A:党派別の社会志向の経済評価(-)","年", "value", "党派別経済効果")

# 社会志向 (-): 差異
socnegdiff = sociotropic_bd_rul-sociotropic_bd_op
df_parec4 <- plot2_5df(year$yearmon, socnegdiff, c("年", "党派性差異"))
g4 <- plot2_5_2(df_parec4, "B:党派別の社会志向の党派性差異(-)", "党派性差異", "value")


grid.arrange(g3, g4, ncol = 1)

【補足】党派性と個人志向の肯定的経済評価

### 【補足】党派性と個人志向の否定的経済評価

第3章:経済評価は何によって動いてきたのか?

推定方法についての説明

なぜ実数和分誤差修正メカニズムなのか?

本書・第1章でも述べたように、政治学は、多くの時系列データの分析手法を導入してきた。なかでも政治学者が好んだ推定方法が、誤差修正モデル(Error correction model: ECM)である。第II部・マクロ・レベルのデータの分析でも、これまでの国内外の研究の流れを重視し、ECM関連のモデルを利用した分析を進める。以下で、具体的な推定モデルを述べる。

2008年にDe Boef & Keele (2008)が、「時間を重視する(``Taking Time seriously”)」と題する論文を公表して以降、1次の自己回帰、移動平均、そして階差(\((p,d,q)=(1,1,1)\))を設定する一般誤差修正モデル(General Error Correction Model: GECM)を、政治学者は多用した。GECMは、各変数の短期変動の効果(short-run effect)と長期均衡からの乖離に対する部分的な調整項(error correction term)からなる。但し、GECMを使うことには、2つの問題があった。

第一に、単位根検定の信頼性の問題がある。GECMの仮説検定とモデルの解釈は、和分(integration)と共和分(cointegration)に依存する。そこで、系列の定常性(stationary)と非定常性(non-stationary)、さらに単位根の有無を評価するために検定を行う。しかし、政治学が扱う世論調査のデータは往々にして時点数が少ない。また一定の値の範囲を、しばしば循環的に行き来する。これを、境界性(bounded)と呼ぶ。データの境界性ゆえに、KPSS検定を使って定常性を、拡張ディッキー=フラー検定(augmented Dicky-Fuller test: ADF検定)検定を使って単位根を検出したとしても、その検定結果が信頼に足るのかという問題が残っていた。仮に単位根の有無が不確かならば、GECMを使う根拠は不十分か、弱まらざるをえない。

第二に、第一の点と関わって、階差の信頼性の問題があった。GECMでは、単位根検定の結果をもとに、短期変動の効果を測定するために整数1次分の階差をとる。しかし、この処理は直観的にも、理論的にも難点がある。例えば、和分\(d\)=0.4 という定常の(頻繁な更新の)系列に対して1次分の階差をとるなら、1-0.4=0.6分の過剰な差分を除いたことになる。一方、\(d\)=1.2という発散する系列に対して1次分の階差しかとらないならば、1-1.2=-0.2分の階差の除去が足りない。さらに、1つの推定モデルには複数の系列が含まれるが、それらの系列の更新の程度が\(d\)=0.4、\(d\)=0.7、\(d\)=1.0、\(d\)=1.2…といったようにばらついているとき、全項に共通して1の階差を取るなら、差分を除去後の系列は不均衡(unbalanced)となる。そして、1次の階差をとるGECMでは、t検定における第I種の過誤が生じると指摘されるようになった。階差、ひいては和分の問題を、政治学の研究者はとりわけ重視した。なぜなら、各種の政治的支持率、マクロ政治・経済指標の和分過程は、ほとんどの場合異なるからである。よってECMを使うのだとしても、GECM(1,1,1)以外のより妥当性の高い推定量の開発、解釈の方法が必要 との見方が主流となった。

そして2015年以降、政治学におけるECMの推定は著しく発展した。2019年と2020年に、Webb, Linn & Lebo (2019, 2020)は、GECMや自己回帰分布ラグモデル(autoregressive distributed lag model: ADL)の長期均衡を正確に解釈する方法を、相次いで提案した。Webb, Linn & Lebo (2019, 2020)は、単位根に関する不確実性が高い場合に、とりわけ長期効果の解釈は困難になるという。少なくとも、右辺変数のラグ項の解釈だけでは不十分となる。そこで、ラグ項を分子とし、左辺変数のラグ項を分母とする長期乗数(Long run Multiplier: LRM)をもとに、長期効果と累積的な将来的効果を判断する代替的な検定方法を示した。LRMの精査は、マクロ政治指標間の分析に応用を見始めている(Wolak & Peterson 2020)。

しかし短期効果も重視される推定の場合、LRMの解釈だけでは、GECMの短期効果をめぐる\(t\)検定の難点を解決しきれない。また本章のように、長期効果・長期的累積効果よりも、各月ごとの経済情報、経済評価の短期効果を知りたい場合、長期効果を測ることに加えて、短期効果の厳密な推定を目指さねばならない。この対処として、2016年にが実数和分に注目し、実数和分をECMに適用しようと呼びかけた特集は、有効な解決方法を示している。実数和分は、既に第4章の分析でも使った。Grant & Lebo (2016)は、実数和分にもとづく差分をとった系列に対して、誤差修正メカニズムを適用する実数和分誤差修正メカニズム(Fractional Error Correction Mechanism: FECM)を使うことを勧めた(参考:Lebo & Grant 2006)。本書でいえば、第4章の実数和分・\(d\)分の差分をとった左辺変数(経済評価)を、短期効果\(\Delta d\)の差分をとった右辺変数(経済状況、経済情報、経済評価など)と部分調整の誤差修正項に回帰する。FECM推定をめぐる3段階のプロセスについては、表\(\ref{tb:tb1}\)にまとめた。

FECMの3段階の推定手順
手順 数式 補足
第1段階:部分調整の誤差修正項の算出 \(\mathrm{ECM} = y_{\text{socio}} - \bigl(\beta_0 + \sum_k \beta_k x_k\bigr)\) 従属変数 \(y_{\text{socio}}\) と独立変数 \(x_k\) を用いて誤差修正項 (\(ECM\)) を算出。
第2段階:各系列の実数和分 (\(d\)) をもとにしたフィルター処理 左辺変数 \(y_{\text{socio}}\) を実数和分 \(d\) で処理、部分調整誤差修正項 \(\Delta^{d_{ECM}}ECM\) も同様に処理。 ここで得られるフィルター処理後の系列を第3段階で利用。
第3段階:フィルター処理後の系列をもとにした誤差修正モデル (\(ECM\)) の推定 \(\Delta^{d_{y_{\text{socio}}}}\,y_{\text{socio},t} = \alpha_0 + \alpha_1\,\Delta^{d_{ECM}}ECM_{t-1} + \sum_i \beta_i\,\Delta^{d_{x_{i}}}x_{i,t} + \epsilon_t\) フィルター処理後の系列を用いて、誤差修正項を含む回帰式を推定。

報道データに関する分析

どのように経済情報スコアを定義したか?

本書では、日本の全国紙3紙の新聞記事のデータを集め、経済情報の変数を作成した。その手順について、以下で説明する。

新聞記事は朝日新聞、日経新聞、読売新聞から「経済」という言葉を含む記事の見出し93万100のデータをもとにしている。集めたデータに対して、\(i\)番目の記事を\(A_i\)、記事\(_i\)に含まれる肯定的な語の数を\(P_i\)、記事\(_i\)に含まれる否定的な語の数を\(N_i\)\(M_i\)を記事\(_i\)の月とすると、以下の手順に基づき、記事を分類する。まず、記事\(_i\)が肯定的であるかを以下式、

\[\begin{eqnarray} D_i^+ = \begin{cases} 1 & \text{if } P_i > 0 \\ 0 & \text{if } P_i = 0 \end{cases} \end{eqnarray}\]

次に、記事\(_i\)が否定的であるかを以下式、

\[\begin{eqnarray} D_i^+ = \begin{cases} 1 & \text{if } N_i > 0 \\ 0 & \text{if } N_i = 0 \end{cases} \end{eqnarray}\]

それぞれによって判別し、次に各月\(m\)について、記事の総数を、

\[\begin{eqnarray} A_m = \sum_{i \text{ where } M_i = m} 1 \end{eqnarray}\]

\(_m\)の肯定的な記事数を、

\[\begin{eqnarray} A_m^+ = \sum_{i \text{ where } M_i = m} D_i^+ \end{eqnarray}\]

\(_m\)の否定的な記事数を、

\[\begin{eqnarray} A_m^+ = \sum_{i \text{ where } M_i = m} D_i^- \end{eqnarray}\]

上記の3式によってそれぞれカウントする。最終的に、月\(_m\)の肯定的情報スコアは、以下の通りである。

\[\begin{eqnarray} S_m^+ = \frac{A_m^+}{A_m} \end{eqnarray}\]

また、否定的情報スコアは、以下の通りである。

\[\begin{eqnarray} S_m^- = \frac{A_m^-}{A_m} \end{eqnarray}\]

上記も参考の上、Rによる前処理の手順は以下の通りである。

#------------------------------
# データの読み込みとテーブル化
#------------------------------

corp_tex1 <- read.csv("newspaper_text_contents.csv", fileEncoding = "SJIS")
tib_corp <- as_tibble(corp_tex1)
tb_corp <- tib_corp %>%
  add_column(id = paste0("news", 1:nrow(tib_corp)), .before = "text")

#------------------------------
# コーパスの作成とトークン分割
#------------------------------

corp <- corpus(tb_corp)
summary(corp)
toks <- tokens(corp)

#------------
# 漢字の処理
#------------

min_count <- 10
kanji_col <- toks %>%
  tokens_select("^[一-龠]+$", valuetype = "regex", padding = TRUE) %>%
  textstat_collocations(min_count = min_count)
toks <- tokens_compound(toks, kanji_col[kanji_col$z > 3, ], concatenator = "")

#----------------
# カタカナの処理
#----------------

kana_col <- toks %>%
  tokens_select("^[ァ-ヶー]+$", valuetype = "regex", padding = TRUE) %>%
  textstat_collocations(min_count = min_count)
toks <- tokens_compound(toks, kana_col[kana_col$z > 3, ], concatenator = "")

#--------------------------------
# 漢字・カタカナおよび数字の処理
#--------------------------------

any_col <- toks %>%
  tokens_select("^[0-9ァ-ヶー一-龠]+$", valuetype = "regex", padding = TRUE) %>%
  textstat_collocations(min_count = min_count)
toks <- tokens_compound(toks, any_col[any_col$z > 3, ], concatenator = "")

#---------------------------------------
# データの整形:DFM作成とフィルタリング
#---------------------------------------

news_df <- toks %>%
  dfm(remove = "") %>%
  dfm_remove("^[ぁ-ん]+$", valuetype = "regex", min_nchar = 2) %>%
  dfm_trim(min_termfreq = 0.50, termfreq_type = "quantile", max_termfreq = 0.99)

#---------------------
# keynessの計算と確認
#---------------------

key <- textstat_keyness(news_df)
head(key, 20) %>% kable()

#------------------------
# LIWC辞書を用いた感情分析
#------------------------

dfmt <- dfm(toks)
# ※dictliwcは事前に用意されたLIWC辞書オブジェクトとする
dict_liwc <- dfm_lookup(dfmt, dictliwc)
# 詳細は https://tasukuigarashi.com/lab/archives/1712.html を参照

#------------------------------------------
# 感情データのデータフレーム化と日付の接合
#------------------------------------------

data_liwc <- convert(dict_liwc, to = "data.frame")
data_liwc_em <- data.frame(
  posemo = data_liwc$posemo,
  negemo = data_liwc$negemo,
  sentiment = data_liwc$posemo - data_liwc$negemo
)
data_date <- read.csv("newspaper_text_contents_date.csv")
df_contents <- data.frame(data_liwc_em, data_date)

#--------------------------------------------
# 肯定・否定センチメントの抽出と月ごとの集計
#--------------------------------------------

df_sentiment <- data.frame(
  date = df_contents$date,
  positive = data_liwc$posemo,
  negative = data_liwc$negemo,
  sentiment = df_contents$sentiment
)
colnames(df_sentiment) <- c("date", "positive", "negative", "sentiment")

sentiment_data <- df_sentiment %>%
  group_by(date) %>%
  summarise(
    total_positive = sum(positive),
    mean_positive = sum(positive) / n(),
    total_negative = sum(negative),
    mean_negative = sum(negative) / n(),
    total_sentiment = sum(sentiment),
    mean_sentiment = sum(sentiment) / n()
  )

#------------------------
# CSVファイルへの出力
#------------------------

write.csv(sentiment_data, file = "sentiment.csv", row.names = FALSE)

本文の補足分析と各図表のコード

図3-1:新聞社ごとの肯定的情報スコアと否定的情報スコア

#------------------------
# データの読み込みと整形
#------------------------


dat3_1 <- read_csv("sentiment_data_includingNEWS.csv", locale = locale(encoding = "SJIS")) %>%
  na.omit() %>%
  group_by(newspaper) %>%
  summarise(across(c(positive, negative), mean, na.rm = TRUE)) %>%
  ungroup() %>%
  pivot_longer(cols = c(positive, negative), names_to = "sentiment", values_to = "value") %>%
  mutate(
    sentiment = recode(sentiment, "positive" = "肯定", "negative" = "否定"),
    newspaper = recode(newspaper, "asahi" = "朝日", "nikkei" = "日経", "yomiuri" = "読売"),
    newspaper = factor(newspaper, levels = c("朝日", "日経", "読売")),
    sentiment = factor(sentiment, levels = c("肯定", "否定"))
  )

#-----------
# ANOVA検定
#-----------

anova_result <- dat3_1 %>% aov(value ~ newspaper * sentiment, data = .)
summary(anova_result)

#----------------
# Tukey HSD 検定
#----------------

tukey_result <- TukeyHSD(anova_result)
print(tukey_result)


#----------------
# プロットの作成
#----------------

windows(10, 8)
dodge <- position_dodge(width = 0.8)

ggplot(dat3_1, aes(x = newspaper, y = value, fill = sentiment, group = sentiment)) +
    geom_bar(stat = "identity", position = dodge, width = 0.7) +  
    geom_label(aes(label = round(value, 2)),
             position = dodge, vjust = -0.2, size = 3, fill = "white", color = "black", label.size = 0.25) +
  xlab("新聞社") +
  ylab("肯定的/否定的情報スコア") +
  geom_signif(comparisons = list(c("朝日", "日経"), c("日経", "読売"), c("朝日", "読売")),
              map_signif_level = TRUE, y_position = c(0.34, 0.34, 0.36),
              annotation = c("***.", "***", "*"), tip_length = 0) +
  geom_signif(
    y_position = c(0.25, 0.28, 0.32),
    xmin = c(0.8, 1.8, 2.8),
    xmax = c(1.2, 2.2, 3.2),
    annotation = c("NS.", "***", "***"),
    tip_length = 0
  ) +
  theme_bw() +
  scale_fill_grey() +
  labs(fill = "情報")