StatsBeginner: 初学者の統計学習ノート

統計学およびR、Pythonでのプログラミングの勉強の過程をメモっていくノート。たまにMacの話題。

CotEditor(テキストエディタ)上の選択範囲をタグで囲むショートカットをPythonで書く

Macでテキストエディタを使うならCotEditorがいいと昔から思っているのですが、CotEditorには、ショートカットの処理とか、あるいは編集中のテキスト上にファイルをドラッグ&ドロップしたときに自動的にテキストを入力するような処理を、自分で追加していける機能があります。
今回、選択範囲をで囲むショートカットをPythonで書いて、追加してみました。
単にHTMLのタグを入れたいだけなら、ふつうに入力支援機能のあるエディタを使えばいいですが、スクリプトを自分で書けるといろいろ柔軟なショートカットを設定できますね。
やりたいことはすごい簡単なのに、ネットでパッとわかる資料がなかったのでメモしておきます。

CotEditorのスクリプト機能

ちなみに、ショートカットでカーソルの位置に文字列を挿入するだけの処理なら、CotEditorの「環境設定」→「キーバインド」→「スニペット」で設定できるのですが、「文字列をタグで挟む」といった複雑なことはできないようです。
スクリプトの機能だと、bashやPythonやJavaScriptなどで書いたスクリプトを組み込むことができ、ショートカットキーによってそのスクリプトを起動するような設定もできて便利です。


具体的なやり方は、CotEditorのメニューの「ヘルプ」→「CotEditorスクリプトガイド」からマニュアルをみることができます。主に、

  • スクリプトメニューをカスタマイズする
  • UNIXスクリプトとの連携
  • CotEditorスクリプトのファイル名規則


といったページを見ておけばだいたいのことはわかると思います。
以下、実際にやってみます。

スクリプトを書く

まずスクリプトを書きますが、上記のマニュアルに書いてあるように、スクリプトの冒頭には、

  • python(インタープリタ)の置き場所
  • このスクリプトにやらせたい仕事は何なのか


をコメントで宣言してあげる必要があります。
たとえば今回書いたのは以下のようなスクリプトなんですが、

#!/usr/bin/env python
# %%%{CotEditorXInput=Selection}%%%
# %%%{CotEditorXOutput=ReplaceSelection}%%%

import sys
selected_text = sys.stdin.read()
output_text = '<B>' + selected_text  + '</B>'
sys.stdout.write(output_text )


1行目は、Pythonインタープリタの置き場所の指定です。もちろんここは「#!/usr/bin/python」とかでも動くのですが、envにしておくと、インタープリタの置き場所が違った場合(バージョン管理ツールを使っている場合など)でも適宜発見して起動してくれます(下記の記事のとおり)。
「#!/usr/bin/python」と「#!/usr/bin/env python」の違い - 座敷牢日誌


2行目は、CotEditor上で選択箇所の文字列をとってきますよ、という意味。「Selection」のところは、他にもいろいろな引数があって、マニュアルに載っています。


3行目は、選択箇所の文字列を置換しますよ、という意味。同じく、「ReplaceSelection」のところは、他にもいろいろな引数があります。


Pythonのコード自体は、標準入力経由で文字列を受け取って、適当に処理をして、標準出力でCotEditorに引き渡すという内容です。
Print関数でも引き渡せるのですが、末尾に改行が無駄に追加されてしまうので、標準出力のstdoutを使いました。
↓の記事に書いてあるように、print関数でもend引数を設定すれば末尾に改行のない状態で出力できるはずなのですが、やってみたところ、CotEditorから呼び出したときによくわからないエラーが出たので、とりあえず標準出力の関数を使っておきました。
Python Tips: 改行をうまく扱いたい - Life with Python

スクリプトを保存し、実行権限を与える

上述の内容のスクリプトを、今回は、


bolding.^~b.py


というファイル名にして、スクリプト置き場である、


~/Library/Application Scripts/com.coteditor.CotEditor


という場所に保存しました。


なお、ファイル名の「.^~b」の部分は、「control + option + B」というキー操作を意味しています。ルールはマニュアルの「CotEditorスクリプトのファイル名規則」をみればわかりますが、ファイル名内の記法によって、どのキーにスクリプトの処理を割り当てるかを指定するわけです。


そして、スクリプトを保存しただけではCotEditorからの実行権限がないので、ターミナルから、chmodで755などの権限設定を行う必要があります。

スクリプトを使ってみる

ここまでの作業を行うと、下記の画像のように、メニューのスクリプト一覧に今回つくったスクリプトが表示されます。


f:id:midnightseminar:20190815151100p:plain


ファイル名称を先程のようなルールに従って作っていなければ、ショートカットキーは割り当てられません。
その場合は、この一覧から選択することによって、スクリプトを実行することになります。


実際に文字列を選択して「control + option + B」下記のように、無事、テキストをタグで囲むことができました。


f:id:midnightseminar:20190815151224p:plain
f:id:midnightseminar:20190815151240p:plain

Rで連立方程式を解く練習(例:超小型の日本経済マクロ計量モデル)

先日、『gretlで計量経済分析』という本に載っている二段階最小二乗法の演習をRでやってみるエントリ(リンク)を書いたのですが、同じ本の次の章は「マクロ計量モデル入門」となっていて、1980年から2009年までの日本経済のデータを用い、5本の構造方程式と2本の定義式、7つの内生変数と9つの外生変数からなる超小型のマクロ計量モデルをつくるというものでした。
Rで連立方程式を解く方法の確認がてら、Rで実行してみます。
最近、研究室の学生にRの使い方をイチから教えてるのですが、これをさらに単純化して練習問題に使えるかも……?

データは本のサポートページからダウンロードできるものですが、「model.gdt」というファイルをgretlで読み込んでcsvで書き出したものを、Rに読み込ませて使いました。
 
 

準備

データは↓のようなイメージです(画像は一部です)。


f:id:midnightseminar:20190808022913p:plain

library(lmtest)
library(car)
library(nleqslv)

# パラメータ推定用データを読み込みます
d_macro <- read.csv('data/csv/model.csv', header=T)

# obsという最初の列の列名称を、なんとなく、YEARに変更しておきます
colnames(d_macro)[1] <- "YEAR"


元データは1980年から2009年までの日本のマクロ経済のデータですが、最大で「2期前」を取るラグ変数があることから、教科書では全て「1982年以降」のデータでパラメータを推定しているので、ここで1、2行目はカットしておきます。

d_macro <- d_macro[3:30,]

 
 

構造方程式(推計式)群のパラメータ推定

この章では、著者によると「内生性が顕著でなく、結果があまり違わないので、全て2SLSではなくOLSで推定する」とのことなので、それに合わせます。二段階最小二乗法にするなら先日のエントリの方法になりますが、そんなに手間は変わらないです。


内生変数になる「民間最終消費支出」「民間企業設備投資」「輸入」「民間可処分所得」「利子率」を推計する回帰モデルを作っていきます。
モデルの説明もコメントで書いておきますが、たとえば民間最終消費支出は、

### (1)民間最終消費支出
# CP = α + β1*YD_1 + β2*WH_1
# CP: 民間最終消費支出
# YD_1: 1期前の民間可処分所得
# WH_1: 1期前の家計金融資産残高

# 回帰分析でパラメータを推定
est1 <- lm(data=d_macro, formula=CP~YD_1 + WH_1)


こういうふうになります。
推定はもうこれでできているんですが、あとで連立方程式を解く処理のところで使いやすいように、predict()をラップして「説明変数を与えると、予測値(理論値)を吐き出す」ようにしておきます。

CP_fn <- function(YD_1, WH_1){
  YD_1 <- as.numeric(YD_1); WH_1 <- as.numeric(WH_1)
  prd <- predict(est1,data.frame(YD_1=YD_1, WH_1=WH_1))
  return(prd)
}


as.numeric()しているのは、事情があります。後でここには、外生変数をまとめたデータフレームから特定の行を抜き出したあとに列名称で値を探して入れることにしたのですが、データフレームの列名称を要素名として持ったままの数字を引っ張ってくると、ここでdata.frame()内での列名称指定が無視されてしまいました。
なので、ごちゃごちゃするけどas.numeric()を挟むことにしました。
なお、predict()関数には、newdataという引数にデータフレーム型でデータを与える必要があります。


他の変数についても同じようにやっていきます。

### (2)民間企業設備投資
# IP = α + β1*(GDP_1-GDP_2) + β2*INT_l1 + β3*IP_1
# IP, IP_1: 当期と1期前の民間企業設備投資
# GDP_1, GDP_2: 1期前と2期前の実質GDP
# INT: 利子率

est2 <- lm(data=d_macro, formula=IP ~ dGDP12 + INT_1 + IP_1)
IP_fn <- function(GDP_1, GDP_2, INT_1, IP_1){  # 引き算は中で計算する
  GDP_1 <- as.numeric(GDP_1); GDP_2 <- as.numeric(GDP_2)
  INT_1 <- as.numeric(INT_1); IP_1 <- as.numeric(IP_1)
  prd <- predict(est2,data.frame(dGDP12=(GDP_1-GDP_2), INT_1=INT_1, IP_1=IP_1))
  return(prd)
}

### (3)輸入
# IM = α + β1*IM_1 + β2*GDP
# IM, IM_1: 当期と1期前の輸入

est3 <- lm(data=d_macro, formula=IM ~ IM_1 + GDP)
IM_fn <- function(IM_1, GDP){
  IM_1 <- as.numeric(IM_1); GDP <- as.numeric(GDP)
  prd <- predict(est3,data.frame(IM_1=IM_1, GDP=GDP))
  return(prd)
}

### (4)民間可処分所得
# YD = α + β1*(GDP-TAX)
# TAX: 租税

GDPTAX <- d_macro$GDP - d_macro$TAX
est4 <- lm(data=d_macro, formula=YD ~ GDPTAX)
YD_fn <- function(GDP, TAX){  # 引き算は中で計算する
  GDP <- as.numeric(GDP); TAX <- as.numeric(TAX)
  prd <- predict(est4, data.frame(GDPTAX=(GDP-TAX)))
  return(prd)
}

### (5)利子率(LM方程式)
# INT = α + β1*ln(GDP) + β2*ln(M2CDN)
# M2CDN: マネーストック

est5 <- lm(data=d_macro, formula=INT ~ l_GDP + l_M2CDN)
INT_fn <- function(GDP, M2CDN){  # 対数化は中で
  GDP <- as.numeric(GDP); M2CDN <- as.numeric(M2CDN)
  prd <- predict(est5, data.frame(l_GDP=log(GDP), l_M2CDN=log(M2CDN)))
  return(prd)
}


ところで、5番目の利子率の式は、教科書とはやり方を変えています。
GDPも内生変数なので、ln(GDP)で説明されるINTはGDPと同時に決まるという構造ですが、gretlでは連立方程式を解かせるときに、「内生変数として計算されたGDPのlogを取って、別の内生変数の説明変数にする」という処理が書けない(?)らしいので、教科書ではちょっと変なやり方で代用していました。


どういうやり方かというと、推定用元データ上は、ln(GDP)はエクセルか何かで予め計算してあって、元データのテーブルに一つの変数として入っているのですが、その上でまず、
ln(GDP)〜GDP
という回帰分析を行っています。(つまり、対数を取る処理を線形モデルで代用している…)
この回帰分析の結果を使って、GDPをln(GDP)ではない何かに変形したものを、疑似ln(GDP)としてINTの説明変数に入れているわけです。


しかしここではそんなことはせずに、普通に、GDPのlogをとってそれをINTの予測に用いるようにしておきます。
なので、教科書とは、最終の結果が少しずれます。(ここを教科書どおりにすると最終結果がピッタリ一致することは確認しました。)
 
 

lmの結果をまとめてCSV出力する

べつにやる必要はないのですが、上の回帰分析の結果をまとめて表にして出力する関数も書いておきます。

# 関数定義
save_lm_results <- function(model, model_name='none'){
  sum     <- summary(model)
  coef    <- sum$coefficients
  R2      <- c(sum$r.squared, NA, NA, NA)
  Adj_R2  <- c(sum$adj.r.squared, NA, NA, NA)
  # ダービンワトソン検定(p<.05だと系列相関あり)
  DW_test <- c(dwtest(model)$statistic, NA, NA, dwtest(model)$p.value)
  # Breusch-Godfrey検定(p<.05だと系列相関あり)
  BG_test <- c(bgtest(model)$statistic, NA, NA, bgtest(model)$p.value)
  results <- rbind(coef,R2, Adj_R2, DW_test, BG_test)
  
  if(length(model$coefficients)-1 >= 2){  # 説明変数が2個以上あるならVIFを計算する
    VIF <- c(NA, vif(model), NA, NA, NA, NA)
  } else{
    VIF <- c(NA, NA, NA, NA, NA, NA)
  }
  
  results <- cbind(results, VIF)
  
  # モデル名を指定しない場合はformulaをファイル名にする
  if(model_name=='none'){
    output_name <- as.character(paste(model$call$formula[2], model$call$formula[1], model$call$formula[3], sep=''))
  } else{
    output_name <- model_name
  }
  write.csv(results, paste('results/lm_result_', output_name, '.csv', sep=""), row.names=TRUE, quote=FALSE)
}

# 実行(空のリストがコンソール上に出力されるけど気にしない)
lapply(X=list(est1, est2, est3, est4, est5), FUN=save_lm_results)

 
 

恒等式(定義式)群の定義

マクロモデル中の定義式(パラメータを推定するのではなく変数間の定義上の関係を記述するもの)を記述しておきます。

### (6)国内総生産
# GDP = CP + IP + CG + IG + IH + ST + EX - IM
# CG: 政府最終消費支出
# IG: 公的資本形成
# IH: 住宅投資
# ST: 在庫投資
# EX: 輸出
GDP_fn <- function(CP, IP, CG, IG, IH, ST, EX, IM){
  def <- CP + IP + CG + IG + IH + ST + EX - IM
  return(def)
}

### (7)名目国内総生産
# GDPN = GDP*GDPDEF/100
# GDPDEF: GDPデフレータ
GDPN_fn <- function(GDP, GDPDEF){
  def <- GDP*GDPDEF/100
  return(def)
}

 
 

外生変数テーブルを作る

さてここからは、推定されたパラメータをつかってシミュレーションを行っていきます。
外生変数をどうやって与えようかなと思ったのですが、なんとなく、データフレームに整理しておいて、そのうち1行を選択して与えると、全ての外生変数を読み込んで内生変数を導いてくれるような組み立てがわかりやすいかなと思い、そうしてみました。


まず、パラメータの推定に使ったデータから、外生変数として使用する変数群を抜き出してまとめます。

Exog_df <- d_macro[,c(
  'YEAR',
  'YD_1', 'WH_1',                     # CPの説明変数(他との重複は除く)
  'GDP_1', 'GDP_2', 'INT_1', 'IP_1',  # IPの説明変数( 〃 )
  'IM_1',                             # IMの説明変数( 〃 )
  'TAX',                              # YDの説明変数( 〃 ) 
  'M2CDN',                            # INTの説明変数( 〃 )
  'CG', 'IG', 'IH', 'ST', 'EX',       # GDPの定義に使う( 〃 )
  'GDPDEF'                            # GDPN(名目GDP)の定義に使う( 〃 )
)]

# 1982年以降のデータだけ抜き出す
Exog_df <- subset(Exog_df, Exog_df$YEAR >= 1982)


上記で抜き出した外生変数のテーブルには、外生というよりも「先決内生変数」と言われるものが混じっていて、たとえば「1期前のGDP」であれば、前のサイクルで推定された内生変数であるGDPの値を、当期の外生変数のようにして使うというものです。
先決内生変数については、見間違えないように、必要なもの以外はデータをNAに置き換えておくことにします。
1期のラグ変数なら1982年だけ残し、2期のラグ変数なら1983年まで残しておく必要があります。

# NAに置き換える関数
remove_future_data <- function(df, valname, lag){
  colnum <- which(colnames(df)==valname)
  df[(lag+1):nrow(df),colnum] <- rep(NA, (nrow(df)-lag))
  return(df)
}

# 先決内生変数の使わない値を置き換え
Exog_df <- remove_future_data(df=Exog_df, valname='IP_1', lag=1)
Exog_df <- remove_future_data(df=Exog_df, valname='IM_1', lag=1)
Exog_df <- remove_future_data(df=Exog_df, valname='YD_1', lag=1)
Exog_df <- remove_future_data(df=Exog_df, valname='INT_1', lag=1)
Exog_df <- remove_future_data(df=Exog_df, valname='GDP_1', lag=1)
Exog_df <- remove_future_data(df=Exog_df, valname='GDP_2', lag=2)

 
 

内生変数の値を得る

「外生変数を与えると、連立方程式を解いて内生変数を返してくれる」という処理を書いていきます。
連立方程式を解くnleqslv()の使い方は次の通り。
未知数が並んだベクトルだけを引数に取る関数(f0とする)を定義して、nleqslv()に、関数foと「未知数の初期値ベクトル」を与えると、未知数の値をちょっとずつ変えてf0に与えながら、f0がゼロになる未知数の組み合わせを探してくれます。
つまりf0は、連立方程式が解けたらゼロベクトルになるように記述しておく必要があります。


たとえば、


INT = α + β1*ln(GDP) + β2*ln(M2CDN)


というような関係を想定しているのであれば、移項して、


INT -(α + β1*ln(GDP) + β2*ln(M2CDN))


というように記述しておくことになります。
で、以下のように定義する関数で、1期分の外生変数を与えると、その期の内生変数が得られます。
xの並び順に注意が必要です。

# 内生変数を計算する関数
get_endo <- function(init, exo, year){
  e <- subset(exo, exo$YEAR==year)
  fn0 <- function(x){
    # xはCP,IP,IM,YD,INT,GDP,GDPNの順
    output <- c(
      x[1] - CP_fn(e$YD_1, e$WH_1),                                   # CP=の方程式
      x[2] - IP_fn(e$GDP_1, e$GDP_2, e$INT_1, e$IP_1),                # IP=の方程式
      x[3] - IM_fn(e$IM_1, x[6]),                                     # IM=の方程式
      x[4] - YD_fn(x[6], e$TAX),                                      # YD=の方程式
      x[5] - INT_fn(x[6], e$M2CDN),                                   # INT=の方程式
      x[6] - GDP_fn(x[1], x[2], e$CG, e$IG, e$IH, e$ST, e$EX, x[3]),  # GDP=の方程式
      x[7] - GDPN_fn(x[6], e$GDPDEF)                                  # GDPN=の方程式
    )
    return(output)
  }
  solution <- nleqslv(x=init, fn=fn0, method = "Newton")
  return(solution$x)
}


内生変数を保存するテーブルを作っておきます。

Endog_df <- data.frame(YEAR = Exog_df$YEAR,
                       CP   = rep(NA, nrow(Exog_df)), 
                       IP   = rep(NA, nrow(Exog_df)), 
                       IM   = rep(NA, nrow(Exog_df)), 
                       YD   = rep(NA, nrow(Exog_df)), 
                       INT  = rep(NA, nrow(Exog_df)), 
                       GDP  = rep(NA, nrow(Exog_df)),
                       GDPN = rep(NA, nrow(Exog_df))
                       )


次に、先ほど定義した関数を繰り返し使って各期の内生変数を順次求めていき、外生変数テーブルと内生変数テーブルをともに1期ずつ更新していく関数を書いておきます。

simulate <- function(init, exo_df, endo_df){
  for (i in 1:nrow(exo_df)){

    # iサイクル目の外生変数セット(1行だけのデータフレームの形)
    exo <- exo_df[i,]
    
    # iサイクル目の解を求める
    sol <- get_endo(init=init, exo=exo_df, year=exo_df$YEAR[i])

    # 内生変数テーブルのi行目を更新
    endo_df[i,'CP']   <- sol[1]
    endo_df[i,'IP']   <- sol[2]
    endo_df[i,'IM']   <- sol[3]
    endo_df[i,'YD']   <- sol[4]
    endo_df[i,'INT']  <- sol[5]
    endo_df[i,'GDP']  <- sol[6]
    endo_df[i,'GDPN'] <- sol[7]

    # 得られた内生変数を、外生変数テーブルのy+1年の行に先決内生変数
    # として上書きする(ただしiが終わりの年を超えるまで)
    if(i<nrow(exo_df)){
    exo_df[i+1,'IP_1']  <- sol[2]
    exo_df[i+1,'IM_1']  <- sol[3]
    exo_df[i+1,'YD_1']  <- sol[4]
    exo_df[i+1,'INT_1'] <- sol[5]
    exo_df[i+1,'GDP_1'] <- sol[6]
    # 2サイクル目からはGDP_2(の3行目以降)も更新する
    if(i>=2){
      exo_df[i+1,'GDP_2'] <- endo_df[(i-1),'GDP'] 
      }
    }
  }
  output <- list(endo_df, exo_df)
  return(output)
}


ではいよいよ下記でシミュレーションを実行します。
内生変数の初期値は、全部0とかにしててもきちんと推計できましたが、推計に使った元データの平均値を取って入れるようにしておきます。

# 内生変数の初期値(元データの平均)
initial <- c(mean(d_macro$CP), mean(d_macro$IP), mean(d_macro$IM), mean(d_macro$YD),
             mean(d_macro$INT), mean(d_macro$GDP), mean(d_macro$GDPN))

# シミュレーション実行
results <- simulate(init=initial, exo_df=Exog_df, endo_df=Endog_df)

# 結果の取り出し
Endo_results <- results[[1]]
Exo_results  <- results[[2]]

# 結果の保存
write.csv(Endo_results, 'results/Endo_results.csv', quote=FALSE, row.names=FALSE)
write.csv(Exo_results, 'results/Exo_results.csv', quote=FALSE, row.names=FALSE)


得られた結果を推計に使った元データと比較してみます。
GDPとINT(利子率)の予測値と実績値を並べておきます。実線が実績値、破線が予測値(シミュレーション値)です。

xlim=c(1982,2009)
ylim=c(300000, 600000)
plot(x=1982:2009, d_macro$GDP, type='l', lty=1, 
     xlim=xlim, ylim=ylim, ylab="GDP")
par(new=TRUE)
plot(x=1982:2009, Endo_results$GDP, type='l', lty=2, 
     xlim=xlim, ylim=ylim, axes = FALSE, xlab="", ylab="")

xlim=c(1982,2009)
ylim=c(0, 10)
plot(x=1982:2009, d_macro$INT, type='l', lty=1, 
     xlim=xlim, ylim=ylim, ylab="INT")
par(new=TRUE)
plot(x=1982:2009, Endo_results$INT, type='l', lty=2, 
     xlim=xlim, ylim=ylim, axes = FALSE, xlab="", ylab="")


f:id:midnightseminar:20190808023021p:plain
f:id:midnightseminar:20190808023036p:plain


教科書に従ってOLSで推定しましたが、2SLSにしても大して手間はかからないと思います。

researchmapにCSVで論文のデータを投入するときの注意点

ResearchmapにCSVで論文のデータを投入するときの注意点として、

  • 英語のタブからダウンロードしたフォーマットを使っているなら、英語のタブからインポートしなければならない。
  • 説明書きに、情報がないセルにはnullを入れろと書いてあるが、べつに入れなくてもデータは読み込める。
  • 同じ論文が含まれている場合、上書きで更新はしてくれないので、上書きを伴うのであればデータをいったん全削除してからインポートする。
  • 元データをエクセルで管理している場合、単にCSVで吐き出すのではなく、ダブルクォーテーション付きにしなければならないので、たとえばこのページのやり方でCSV作成をする。(簡単にいうと、エクセル上でダブルクォーテーション付きにした上で、それをテキストエディタにコピペし、タブをカンマに置換する)

忘れそうなのでメモしました。
しかし今年7月に仕様の変更があるらしいですが。
更新していく上では一番最後の点がめんどくさいので、変換するプログラムを自分で用意したほうが楽な気もします。

Rで二段階最小二乗法の演習(『gretlで計量経済分析』を参考に)

『gretlで計量経済分析』という教科書があって、入門的な統計分析を非常にわかりやすく解説していると思いました。
学部レベルの人に統計分析を教える上では、関心の対象が政治や経済なのであれば、こういう「経済ネタ」で統計学が学べる本が良いのかもしれない。(私は最初は心理学系の本で勉強した。)
gretl(グレーテル)というソフトの使い勝手は私はよく知りませんが、見た感じ、初学者向けにはGUIもわかりやすくて良いんじゃないでしょうか。


ところで、第8章でごく簡単なマクロ経済モデルを材料にして二段階最小二乗法を実行するという演習があり、内生性の問題とその解決法としての操作変数法・二段階最小二乗法について説明するのに、なかなか分かりやすい事例だなと思いました。
しかし、gretlを使っていく予定はないので、以下のようにRで実行しました。

OLSでの推定

以下のように超単純なマクロモデルを考える。

Ct = α + βYt + ut
Yt = Ct + It

1つめの式を変形すると、
Yt = α/(1-β) + It/(1-β) + ut/(1-β)

ここで、
C:消費、Y:所得、I:投資、u:撹乱項、0 < β < 1

これらはようするに、消費は所得だけの関数として決まり、所得は、消費と投資の合計に一致する、というモデルを想定している。
最初の式で、説明変数にYtが入っているが、Ytにはutが入っているわけなので、説明変数と撹乱項が相関しており内生性があるということになる。内生性があると、OLSが一致推定になるための条件を満たさないので、サンプルサイズを増やしても真の値に近づいていかないことになる。そのためOLSでは妥当な推定ができない。


まずパラメータの真の値を自分で設定した上で、乱数で変数を作成し、生成された変数からOLSでパラメータを推定してみて、真の値とズレてしまう様子を確認する。

# ========== OLSで推定する ========== #

# まず、αとβの真の値を設定しておく。
alpha <- 2.5
beta <- 0.6

# 以下は、乱数からデータ系列をつくって、OLSで推定したパラメータを返すという処理を繰り返す関数。

repeat_ols <- function(para, n, T, sd){

  # あとで結果を並べるために設けておく空のベクトル
  alpha_output_ols <- c()
  beta_output_ols <- c()
  
  # 処理はn回繰り返させる
  for (i in 1:n) {
  
    # 投資Itは1から始まって毎期0.5ずつ増えることにする。全部でT期分。
    It <- seq(from=1, by=0.5, length.out=T)
    
    # 変形後の上式からYtをつくる。撹乱項utは正規乱数。
    set.seed(i)
    ut <- rnorm(n=T, mean=0, sd=sd)
    Yt <- (alpha/(1-beta)) + (It/(1-beta)) + (ut/(1-beta))

    # Ctをつくる
    Ct <- alpha + beta*Yt + ut
    
    # CをYに回帰してαとβをOLSで推定する。
    model_cy_ols <- lm(Ct ~ Yt)  # OLS推定
    alpha_est_ols <- model_cy_ols$coefficients[1]  # αの推定値
    beta_est_ols <- model_cy_ols$coefficients[2]  # βの推定値
    
    # 繰り返し推定した結果を並べておく
    alpha_output_ols <- c(alpha_output_ols, alpha_est_ols)
    beta_output_ols <- c(beta_output_ols, beta_est_ols)
    }
  
  # 出力
  if(para=='alpha'){
    return(alpha_output_ols)
  }
  if(para=='beta'){
  return(beta_output_ols)
  }
}

# 1000回推定して結果を取り出す
alpha_results_ols <- repeat_ols(para='alpha', n=1000, T= 100, sd=5)
beta_results_ols <- repeat_ols(para='beta', n=1000, T= 100, sd=5)

# 推定した1000個のα・βの平均を確認する
mean(alpha_results_ols)
mean(beta_results_ols)
> mean(alpha_results_ols)
[1] -0.4664703
> mean(beta_results_ols)
[1] 0.6419773
# ヒストグラムをかいてみる
hist(alpha_results_ols, breaks=20)
hist(beta_results_ols, breaks=20)


f:id:midnightseminar:20190515125702p:plain
f:id:midnightseminar:20190515125712p:plain


αもβも真の値(それぞれ2.5、0.6)からけっこうズレていることが分かる。

二段階最小二乗法で推定してみる

次に、内生性のあるモデルでもバイアスなく推定してくてるという噂の二段階最小二乗法をやってみます。
二段階最小二乗法が何であるかはググってどこかで見てもらえればと思いますが、あるモデル式の説明変数の中にある内生変数を、「内生変数 = α + β1外生変数1 + β2外生変数2 + ε」という形の回帰分析により、「外生変数だけで完全に説明できる部分と、それ以外の誤差」に分けます。「外生変数だけで完全に説明できる部分」というのは、この回帰分析の結果得られるαとβを用いた「予測値」のことで、内生変数のかわりにこれを使うことで、被説明変数の撹乱項と相関が生まれるのを防ぐことができるわけです。

# ========== 二段階最小二乗法で推定してみる ========== #
# さっきと同様に、αとβの真の値を設定
alpha <- 2.5
beta <- 0.6

# 推定を繰り返す関数
repeat_2sls <- function(para, n, T, sd){
  alpha_output_2sls <- c()
  beta_output_2sls <- c()
  
  # n回繰り返させる
  for (i in 1:n) {

    # 投資Itは1から始まって毎期0.5ずつ増えることにする。全部でT期分。
    It <- seq(from=1, by=0.5, length.out=T)
    
    # 変形後の上式からYtをつくる。撹乱項utは正規乱数。
    set.seed(i)
    ut <- rnorm(n=T, mean=0, sd=sd)
    Yt <- (alpha/(1-beta)) + (It/(1-beta)) + (ut/(1-beta))
    
    # Ctをつくる
    Ct <- alpha + beta*Yt + ut
    
    # ここから二段階の推定を行う。
    # まず、Y~Iの回帰分析をOLSでやります。
    model_yi <- lm(Yt ~ It)
    
    # パラメータの推定値を取り出します
    const_yi <- model_yi$coefficients[1]
    coef_yi <- model_yi$coefficients[2]
    
    # 上記パラメータからYの予測値を作ります
    Yt_pred <- const_yi + coef_yi*It
    
    # ちなみにこれは、predict関数を使って
    # Yt_pred <- predict(model_yi)
    # としても同じものが得られます。
    
    # 上の予測値を使って、二段階目の回帰をします。
    model_cy_2sls <- lm(Ct ~ Yt_pred)
    
    # パラメータの推定値を取り出します
    alpha_est_2sls <- model_cy_2sls$coefficients[1]
    beta_est_2sls <- model_cy_2sls$coefficients[2]
    
    alpha_output_2sls <- c(alpha_output_2sls, alpha_est_2sls)
    beta_output_2sls <- c(beta_output_2sls, beta_est_2sls)
  }
  
  # 出力
  if(para=='alpha'){
    return(alpha_output_2sls)
    }
  if(para=='beta'){
    return(beta_output_2sls)
    }
}

# 1000回推定して結果を取り出す。
alpha_result_2sls <- repeat_2sls(para='alpha', n=1000, T=100, sd=5)
beta_result_2sls <- repeat_2sls(para='beta', n=1000, T=100, sd=5)

# 推定値の平均を確認
mean(alpha_result_2sls)
mean(beta_result_2sls)
> mean(alpha_result_2sls)
[1] 2.524852
> mean(beta_result_2sls)
[1] 0.5996154
# ヒストグラムをかいてみる
hist(alpha_result_2sls, breaks=20)
hist(beta_result_2sls, breaks=20)


f:id:midnightseminar:20190515125839p:plain
f:id:midnightseminar:20190515125851p:plain


かなり「真の値」(α=2.5、β=0.6)に近い結果きました。

上記2つの計算方法の結果を比較

sd(撹乱校の標準偏差=ばらつき)を変えてみて、両者の結果を比較します。

> # OLSでsdを1〜10まで変えてβを推定してみる
> for(i in 1:10){
+ b <- mean(repeat_ols(para='beta', n=1000, T=100, sd=i))
+ print(b)
+ }
[1] 0.6018791
[1] 0.6073759
[1] 0.6162016
[1] 0.6279157
[1] 0.6419773
[1] 0.6578006
[1] 0.6748069
[1] 0.6924639
[1] 0.7103121
[1] 0.7279768
> 
> # 2SLSでsdを1〜10まで変えてβを推定してみる
> for(i in 1:10){
+   b <- mean(repeat_2sls(para='beta', n=1000, T=100, sd=i))
+   print(b)
+ }
[1] 0.6000004
[1] 0.5999623
[1] 0.5998856
[1] 0.59977
[1] 0.5996154
[1] 0.5994214
[1] 0.5991876
[1] 0.5989136
[1] 0.5985988
[1] 0.5982427


OLSの推定のほうは、撹乱項の標準偏差を大きくしていくにつれ、推定のバイアスもどんどん大きくなってますが、2SLSのほうは結果が安定してますね。

2SLSの部分にパッケージをつかってみる

二段階最小二乗法は、semパッケージのtsls関数で簡単に実行できるので、それを使うように書き換えたものも置いておきます。

# パッケージの読み込み
library(sem)

# αとβの真の値を設定
alpha <- 2.5
beta <- 0.6

# 推定を繰り返す関数
repeat_2sls_sem <- function(para, n, T, sd){
  alpha_output_2sls_sem <- c()
  beta_output_2sls_sem <- c()
  
  # n回繰り返させる
  for (i in 1:n) {

        # 投資Itは1から始まって毎期0.5ずつ増えることにする。全部でT期分。
    It <- seq(from=1, by=0.5, length.out=T)
    
    # 変形後の上式からYtをつくる。撹乱項utは正規乱数。
    set.seed(i)
    ut <- rnorm(n=T, mean=0, sd=sd)
    Yt <- (alpha/(1-beta)) + (It/(1-beta)) + (ut/(1-beta))
    
    # Ctをつくる
    Ct <- alpha + beta*Yt + ut
    
    # tsls関数で2SLS(カンタン!!)
    model_tsls_sem <- tsls(Ct ~ Yt,  ~ It, data=data.frame(It, ut, Yt, Ct))
    
    alpha_est_2sls_sem <- model_tsls_sem$coefficients[1]
    beta_est_2sls_sem <- model_tsls_sem$coefficients[2]
    
    alpha_output_2sls_sem <- c(alpha_output_2sls_sem, alpha_est_2sls_sem)
    beta_output_2sls_sem <- c(beta_output_2sls_sem, beta_est_2sls_sem)
  }
  
  # 出力
  if(para=='alpha'){
    return(alpha_output_2sls_sem)
    }
  if(para=='beta'){
    return(beta_output_2sls_sem)
    }
}

# 1000回推定して結果を取り出す。
alpha_results_2sls_sem <- repeat_2sls_sem(para='alpha', n=1000, T=100, sd=5)
beta_results_2sls_sem <- repeat_2sls_sem(para='beta', n=1000, T=100, sd=5)


# 推定値の平均を確認
mean(alpha_results_2sls_sem)
mean(beta_results_2sls_sem)

# ヒストグラムをかいてみる
hist(alpha_results_2sls_sem, breaks=20)
hist(beta_results_2sls_sem, breaks=20)

# 2SLSでsdを1〜10まで変えてβを推定してみる
for(i in 1:10){
  b <- mean(repeat_2sls_sem(para='beta', n=1000, T=100, sd=i))
  print(b)
}


結果はさっきと同じになります(乱数のシードも揃えてるので)ので省略します。

IS-LM分析

教科書に沿って、IS-LM分析を行います。
データは、教科書のサポートサイトにあるものを使います。
https://www.nippyo.co.jp/shop/download/35.html
このデータの、islm.gdtというデータを、gretlで開いてCSVでエクスポートしておけば、Rでインポートして使えます。


IS方程式は、
lnGDPN <- α1 + β11INT + β12lnINV + u1


LM方程式は、
INT <- α2 + β21GDPN + β22lnM2CDN + u2

ここで、
GDPNは名目GDP、
INVは名目投資(民間設備投資、民間住宅投資、在庫投資の合計)、
INTは名目長期金利、
M2CDNはマネーストック
であり、lnは対数値です。


サポートサイトのデータは、1980年から2009年の日本の時系列データになっていて、変数名が、lnGDPNは「l_GDPN」、lnINVは「l_I」、lnM2CDNは「l_M2CD」になっています。

# ========== ISLM分析を二段階最小二乗法でやってみる ========== #
# パッケージの読み込み
library(sem)

# データの読み込み
data <- read.csv('data/csv/islm.csv', header=T)  # データの置き場所は各自の環境に合わせて

# IS方程式を求めるための二段階最小二乗法
tsls(data$l_GDPN ~ data$INT + data$l_I, ~ data$l_M2CD + data$l_I, data=data)

# ばらして二段階それぞれを計算しても同じ値になる
model_int_m2 <- lm(data$INT ~ data$l_M2CD + data$l_I)
INT_pred <- predict(model_int_m2)
model_gdp <- lm(data$l_GDPN ~ INT_pred + data$l_I)

model_gdp$coefficients[1]  # α1
model_gdp$coefficients[2]  # β11
model_gdp$coefficients[3]  # β12


# LM方程式を求めるための二段階最小
tsls(data$INT ~ data$l_GDPN + data$l_M2CD, ~ data$l_M2CD + data$l_I, data=data)

# ばらして二段階それぞれを計算しても同じ値になる
model_gdp_m2 <- lm(data$l_GDPN ~ data$l_M2CD + data$l_I)
GDP_pred <- predict(model_gdp_m2)
model_int <- lm(data$INT ~ GDP_pred + data$l_M2CD)

model_int$coefficients[1]  # α2
model_int$coefficients[2]  # β21
model_int$coefficients[3]  # β22


出力結果は下に貼り付けます。

> tsls(data$l_GDPN ~ data$INT + data$l_I, ~ data$l_M2CD + data$l_I, data=data)

Model Formula: data$l_GDPN ~ data$INT + data$l_I

Instruments: ~data$l_M2CD + data$l_I

Coefficients:
(Intercept)    data$INT    data$l_I 
 6.40360864 -0.05130671  0.59363934 
> tsls(data$INT ~ data$l_GDPN + data$l_M2CD, ~ data$l_M2CD + data$l_I, data=data)

Model Formula: data$INT ~ data$l_GDPN + data$l_M2CD

Instruments: ~data$l_M2CD + data$l_I

Coefficients:
(Intercept) data$l_GDPN data$l_M2CD 
   26.97856    14.70982   -13.88998 


ちなみに教科書の本文では、「二段階最小二乗法で推定された、IS方程式の利子率INTのパラメータは6.403」と書いてありますが、これは見るところを間違ってますね(定数項を報告してしまっている)。正しくは「-0.051」です。LM方程式のほうも記述が間違っています。
(出力自体は、上記の結果と教科書に載っているgretlの結果は一致しています。)


OLSでも推定してみて、ズレがどれぐらいあるか確認しておきましょう。

> # OLSでも推定してみて違いを検証
> lm(data$l_GDPN ~ data$INT + data$l_I)

Call:
lm(formula = data$l_GDPN ~ data$INT + data$l_I)

Coefficients:
(Intercept)     data$INT     data$l_I  
    5.95760     -0.04657      0.63120  

> lm(data$INT ~ data$l_GDPN + data$l_M2CD)

Call:
lm(formula = data$INT ~ data$l_GDPN + data$l_M2CD)

Coefficients:
(Intercept)  data$l_GDPN  data$l_M2CD  
     80.019        3.020       -7.491  


IS方程式のほうはある程度近い値ですが、LM方程式はだいぶ違いますね。

某メーカーの採用担当者に聞いた、研究開発職の新卒採用の裏話

採用の当事者へヒアリング

 さっき就活エントリを書いたついでに、10年ぐらい前に別のブログに書いたネタを再掲しておこう。
 食品会社や製薬会社を狙って研究・開発職志望で就職活動を始めた▲▲大学のA子さんから、エントリーシートの書き方とか面接での自己PRの仕方について、軽く相談を受けたことがあった。全然業種が違ったんだけど、私はもう就職してたから一応コメントするみたいな。
 で、たまたま私は、某大手食品会社の人事部採用担当にB子という知り合いがいたことを思い出して、そいつに「採用側の視点から何かアドバイスしてやってくれ」と、ヒアリングを実施したわけである。


 採用担当者も面接官もタイプは色々なので、あくまで「こいういう人もいる」という一例に過ぎないし、エントリーシートを紙で書いてた時代の話なので今とは違う面もある。当時私は就職1年目ぐらい、A子は4年目ぐらいとどちらも若かったので、今同じ話をすれば付け加えたいこともたくさんあるだろう。ただ、読み返したら面白くて、現在でも通用する内容が結構あると思ったので、貼り付けておく。B子の当事者目線のコメントもさすがではあるけど、マメに議事録を起こしてた俺の暇っぷりもなかなかのものだと感心する。


 文中に登場する社名は伏せてある。一部推測可能な社名もあるけど、B子の会社は絶対に推測できないように書いてあり、しかも今はもうその会社もやめて転職している*1。文中の「C太郎」は私です。
 なお、A子さんは無事、本文中には登場しない某大手メーカーに研究職として採用されました。

ヒアリングの記録

C太郎 A子さんは食品か製薬の研究・開発職志望なんだけど、選考する人って、やっぱり人事部の人なの? 人事だと基本的に文系だよね。


B子 会社にもよると思うけど、最初はまず、人事部の若手が大量のESを絞り込む作業からはじまるね。研究職でも、一次面接までは人事部の若手が担当して、二次面接ぐらいから役員が登場するのがふつうなんじゃないかな。


C太郎 ESとか面接で、研究の専門的な内容はどれぐらいアピールして良いものなの? 採用する側って、研究内容を聞いても分からない人も多いよね?


B子 まぁそうだね。会社によると思うけど。募集するときに「○○学部」とか「○○学科」っていう細かい条件を付けてるような会社の場合は、専門性のある能力を持った人材を求めてるわけだから、ほんとに専門的な研究職の若手が最初から選考に関わってることも多いと思うよ。だから、そういう場合は専門性を押し出してアピールしていけば良い。
 商品開発の即戦力を欲しがっている会社も、やっぱりあるんだよね。入社して1年目で実際に商品開発のプロジェクトに入って、2年目からはもう自分のプロジェクトを持つような会社もある。そういう会社を受ける場合は、今の自分の技術とか能力が、“売れる商品”の開発にどう生かせるかが問われるね。


C太郎 ESを絞る段階で、研究の専門的な内容はどれぐらい見るものなの?


B子 ぶっちゃけ、私は研究内容は見ないね。ただ、上のほう(会社の上司)から「こういう内容の研究をしてる学生が欲しい」とか、具体的な要望がある場合もあるのね。そういうときは、それ以外の学生はプレエントリーで落としたり、書類で落として、上まで上がって行かないようにする。そういえば、「国公立大の大学院卒」っていうふうに学歴で条件を付けるときもあるね。
 でも、私たちが読んでて本当に面白いのがあったら、(指示された条件を満たしていなくても)上の人に「とりあえず読んでみて下さい」って売り込んだりもするよ。


C太郎 たとえば、理系の専門用語とかって、あんま使わないほうがいいの? 文系の職員が選考する場合は、書かれてもわからないよね。


B子 私なんかはもうアレルギーだから(笑) 分からない専門用語とかがあると、読む気なくすよね。


C太郎 じゃあさ、面接なんかでも、とりあえず専門的すぎることは言わないほうがいいのかな。基本的には素人にも分かるような言い方で、かつ面白く自分の研究内容を伝えるようにしておいて、専門的な細かいことは「聞かれたら答える」ぐらいの作戦で行けばいいのかな?


B子 そうだね。聞いてくるってことは、向うが知りたがってるわけだから。向うが突っ込んできたら、どんどん説明すればいいよ。


C太郎 ESってやっぱり、あんまり細かくは読まないものなの?


B子 正直、まずは見た目だね。パッと見が重要。うちの場合、研究職の採用は20人なのに5000通ぐらい応募があるからね。ザッと眺めて、面白そうだったらちゃんと読む。面白くなさそうだったら読まない。写真が汚かったりしたら、もう読まずに捨てるよ。


C太郎 やっぱ何百枚も何千枚も読んでたら、疲れるよね……。


B子 疲れる。だから、視覚に訴えるような書き方をするのがすごく大事。C太郎も言ってたけど、「 」や“ ”をうまく使って強調するとかね。


C太郎 そうそう、俺もマスコミのESを書いてた頃は、自己PRを箇条書きにしてみたり、字の大きさとかレイアウトに気をつかって目立つようにしてたな。俺の周りでも、とくにテレビとか出版社を受けてた奴はすごかったね。


B子 あとね、自己PRなんかを書くときに、自分がどういう人なのかを分かりやすく表すフレーズがあるといいよね。


C太郎 自分のキャッチコピーみたいな?


B子 そうそう。そういうフレーズをカッコでくくったりして何ヵ所かに書いておくと、「あぁなるほど、そういう人なのね」っていうのが、ESを眺めててすぐにわかるよね。


C太郎 A子さんの自己PRはどう?


B子 うーん、他の人と同じような自己PRになっちゃってると思う。正直、普通すぎてあまり印象に残らないと思うよ。せっかく「来年の自分」を売り込むところなのに!
 学生時代に頑張ったことも、「研究室活動」って書いてあるけど、それだけだと弱いよね。そもそも研究職で受けに来る学生は、研究に没頭してる人ばっかりだからね。そういう人たちの中で、どうやって目立つかが問題なわけだから。


C太郎 そっか。やっぱ目立たないとダメだよね。


B子 音楽とか、「色々やってそうな人なんだなぁ〜」っていう印象はあるんだよね。学校を変えてまで研究してるんだから、一生懸命な人なのも分かる。
 だけど、学生時代に「何をやったか」は書いてあるのに、その結果として「自分がどういう性格や能力をもった人間になれたのか」が具体的に書かれていないから分からないんだよね。ぶっちゃけ、この内容だと、他の人でも同じこと書けそうだよね。いろんなことをやってみた結果、自分がどういう人間になったのか、どういうふうに企業の利益に貢献できる人間になったのかがイメージできるように、もっと具体的に書いて欲しい。


C太郎 まぁ確かに、このままだと内容の印象は薄いかもね。インパクトはないか。


B子 ▲▲大の大学院にいるんだから、まぁ学歴で切られることはあり得ないよね。せっかく▲▲大に居るんだから、「▲▲大でしかできないこと」をもっとアピールしたほうがいいよ。あとは「自分にしかできないこと」だね。
 全体的に、A子さんはまだESを書き慣れてないんだなぁっていう印象を受けるのね。もっと練習したほうがいいと思う。字数制限ってあるよね? 400字とかの。まず始めに、字数制限をかなりオーバーするぐらい書くんだよ。とにかくネタを自由に書き出してみる。で、字数オーバーした文章を要約したものを、ESに書く。その中で自分が一番こだわりたいポイント、これだけは絶対に外せないっていうポイントに絞って書く。


C太郎 そうやって内容を洗練させるってこと?


B子 それもあるし、オーバーして書いておくと、残りの部分が面接のときに役立つんだよね。面接官がESを見ていろいろ聞いてきたときに、すぐ答えられるからね。


C太郎 そっか、話のネタが用意できてると楽だよね。面接はESに沿って質問されるわけだし。……あのさ、理系の研究職でも“面白さ”ってけっこう重要なの?


B子  重要、重要。ESも、「お、この人面白そうだな」とか「この人、ちょっと会ってみたいな」って思わせるようなのじゃなきゃダメだよ。
 理系の研究職でも、ゴチゴチにアタマの堅い、見るからに理系研究者っぽい人はダメ。やっぱり商品開発って“遊び心”が大事だからね。X社なんかは、学歴とかは考慮してなくて人物重視で採用してるから、面接でキャラをアピールするのが重要だね。


C太郎 理系でもキャラが大事なの?


B子 うん。研究職だって、自分のキャラを面白いと思わせる必要はある。あと、プレゼン能力もかなり重要だね。商品開発は研究員がやっているわけだけど、研究員がたとえば社長にプレゼンして、具体的にプロジェクトを立ち上げるかどうかを判断してもらうわけでしょ。
 営業担当の職員にプレゼンするときもある。商品開発のためにはやっぱり営業の人たちと協力する必要があって、そういう職員に営業や調査を頼むときにも、自分の研究内容をプレゼンして理解してもらわなきゃダメだからね。


C太郎 ああそうか。やっぱ、研究開発の専門的な内容が分からない人に対しても、分かりやすく説明してアピールできないとダメってことね。


B子 そう。研究職でも、むしろ「この子、営業でもいけるんじゃないの?!」って思わせるぐらいの、明るくて、社交的で、面白い人がいいよ。見た目も大事だね。研究者っぽくないキャラの人のほうが印象に残るし、好まれると思うよ。


C太郎 ああ、その点ではA子さん有利かも。理系っぽいイメージがまったく無くて、文系じゃなかったのが惜しいぐらいだから(笑)


B子 ほんとに? じゃぁ絶対、“研究者っぽくない感じ”をアピールしていったほうがいいよ!


C太郎 なんかさ、A子さん自身は学生時代はほとんど研究に時間を取られてて、とくにネタになるようなことはしてないらしいんだよね。それで、面白い内容の自己PRとかを書くのが大変みたいなんだけど。


B子  今まで書いてあるESの文章のなかからでもいいから、自分にとって一番こだわりのあること、これだけは絶対に削除したくない!ってことを見つけて、それにドラマ性を持たせて書くんだよ。作家でもブログの女王でもいいけど、ああいう人って、日常の何気ないことをすごく面白く読めるように書くでしょ。そういう気持ちで書けばいいよ。
 ちょっと大げさにしてもいいから、ドラマチックにね。もちろん、ヘンな目立ち方をするのはダメなんだけど……。


C太郎 木曜日がS社のESの締め切りで、白紙のA4一枚の課題があって、“挑戦”とか“創造”してる自分の人生をアピールしなきゃいけないらしいんだけど……


B子 あ、それ私が受けたときと変わってないね。私は写真をいっぱい使って、「B子図鑑」を作ったりしたね。


C太郎 通ったの?


B子  ESは通ったよ。面接で落ちたけど。S社はメーカーだけど、広告会社を受けるようなノリで受けたほうが良いよ。面接がかなり重要で、理系の研究職でもキャラが重視されてる感じ。こないだ「ガイアの夜明け」でS社の研究員の社長プレゼンの話をやってたんだよね。かなりユニークで、こだわりが強くて、面白い人だった。その人はウィスキーの商品開発をしていて、社長プレゼンをする話。研究で行きづまったときには行きつけのバーに寄って相談するんだって。


C太郎 S社って、ぶっちゃけ、入るのめちゃくちゃ難しいでしょ? 就職したい企業ランキングでも3位とか4位とかに入るよね。


B子  うん。S社は少数精鋭だしね。あそこは無駄な人件費は絶対に払わないっていうポリシーでやってるみたい。


C太郎 A子さんの志望動機とかはどう?


B子 志望動機もこれだと弱いね。大手のメーカーって、正直「有名だから」っていう理由で受ける学生も多いけど、会社側はやっぱそういうのは嫌がるからね。その人なりのこだわりとかが伝わってくる「志望動機」じゃないと
 こないだT社の社長に会ったんだけど、「商品開発者は『想い』の強さが大事」って言ってた。命がけで社長を口説き落とすぐらいの、強いこだわりをもった人でないと、商品開発はできないねって。「こだわり」だよ。
 O社の志望動機で、「栄養補助食品にも力を入れている」ってあるけど、O社はむしろ栄養補助食品は「輸入」に力を入れてる感じだと思うよ。●●●ーメイトとかは「製造」してるけど。
 この「志望動機」の内容だと、ぶっちゃけ他の人でも書けそうだよね……。印象には残りにくいと思う。


C太郎 企業研究が足りないのかな? 会社の業務内容とか戦略とかをよく知らないと、こだわった内容は書けないし。


B子 そうだね。企業のホームページなんかもよく読んだほうがいいと思う。商品展開の路線とかもわかるしね。O社でいえば、大衆薬品を拡大していくのかどうか、とか。私は昔から、食品とか薬品の、商品をチェックするのが好きなんだよね。だからいろんな会社の商品展開を、店をまわって見てるよ


C太郎 他社の商品もチェックしていくべきだよね?


B子 ライバル会社の動きは要チェックだね。あそこの会社はこういう商品を出して、けっこう売れてるけど、それに対してこっちの会社はどうするのか……とか。


C太郎 かなり熱意をもって、詳しくならないとね。


B子 私がS社を受けたとき、会社側から何も求められてないのに、企画書を書いてきて「プレゼンさせてください」って言ってる人がいたよ。その人が受かったかどうかは知らないけど。うちの会社でもこないだ、求めてないのに企画書を書いてきた学生がいたよ。その人はコンピュータとかIT関係の職種を希望してる人で、うちの会社のHPの改善案を書いてきたんだよね。その企画書は、社長がいまも大事に取ってるよ。


C太郎 すごいな(笑) 具体的に企画できるぐらいのこだわりがあれば強いよね


B子 会社を褒めるよりも、逆に疑問を投げかけるような内容のほうが印象に残るよ。たとえば●●●ーメイトのネタでいくなら、この前、ドリンクのコーンポタージュ味が出たんだよね。でもそれがすんごいマズイの。●●●ーメイトってやっぱり売れてるし、そういうブランドイメージの強い商品は、シリーズで新しいのを出していけば絶対売れるんだよね。でもあんなにマズイのを出しちゃったら、ブランドイメージが傷つくでしょ。
 「コーンポタージュ味は『●●●ーメイト』ブランドの破壊になります。だから早くやめた方がいいですよ!」って、そういう疑問を投げかける提案をしたほうがいいよね。


C太郎 ああ、それは思いつかなかったポイントだな。


B子 とにかく、O社の場合でいえば、●●●ーメイトを超えるものを作ってもらいたいわけだから。メーカー側は、商品開発をする人には、とにかく既存の製品を超えるものを開発できる力を求めるわけ。私がN社を受けたときは、研究職の人には、「■■■■ードルを超えてください」って言ってたよ。

*1:ちなみに、推測できないように書きすぎて、もはやどこの会社だったかも忘れてしまったw

文系の大学院生が就活に苦戦する理由と対策

「文系の院生」は就活で不利?

 とある就活サイトの人から、リレーブログみたいなものへの参加を依頼されたので書きました。この記事は主に企業への就職の話ですが、面接対策の部分は公務員であれ何であれ同じようなことが言えると思います。
(もう一本、研究開発職の就活に関する記事も書いてあり、そっちでは人事部の裏話的なものを載せています。)


 ちょうど1年くらい前、「『頭のいい』女子はいらないのか——ある女子国立大院生の就活リアル」という記事(リンク)にはてなブックマークが400個ぐらい付いて話題になっていた。記事は「女だから」という理由で就活で苦労するという話なのだが、ツイッターのタイムラインではなぜか、「女だからというより、『文系の院生は使えない』からだろ。とくに社会学はダメだ!」みたいな話になっていて、以下のようなまとめまで出てきていた。
togetter.com


 「文系の院卒」の就職率は相対的に悪いとよく言われる(なんか調査もあった気がする)。しかし私が経験したり見聞きしたりした範囲から言うと、後述するように「文系の院卒には準備不足な奴が多い」というイメージは多少あるものの、「優秀なのに、文系院卒であることがネックになって落ちた」みたいな例は殆どなさそうに思える。民間でもそうだし、公務員の場合なんかは全く不利にならない。


 事務職・企画職・総合職の採用面接*1でいうと、最低限のコミュニケーション能力があるかどうか、頭の回転はどうか、常識的に求められる程度の準備をしてきている感じがするか(←後述するがここで差がつくことが多い)、人柄はどうかなどをみていることがほとんどで、「文系の院生である」という肩書上のスペックで評価が下げられるという印象はない。後述するように、上がりもしないところが問題ではあるのだが。
 ましてや、社会学が何であるかについてほとんどのビジネスマンは知らないし、興味もないだろう。


 私は去年まで十年ぐらい企業*2で働いていたのだが、今は大学に転職して就活生を送り出す側になってしまった。まだ企業側の感覚もある程度残っている気がするので、今のうちに就活について思うところを書いておこうと思う。
 私は文系の学部を出て、企業で企画職・事務職を経験した後、工学の大学院を出て工学部の教員になっているという中途半端な人間で、それぞれの立場を深くは知らないので信憑性に欠ける気はするが、そのおかげでよく見えるようになったことも1つや2つはあるかも知れない。


 なおこのエントリでは、文系の修士課程に在籍する学生が事務職や企画職に応募するケースを念頭に話を進める。
 
 

「学歴フィルター」は存在する

 そういえば今年の春頃、「学歴フィルター」というのが話題になっていた。
news.yahoo.co.jp


 たとえば、リクナビやマイナビのような就活サイトにいわゆるFラン大学生として登録すると、会社説明会が「満員」で参加不可になっており、一流大学所属に変更してみると表示が「空席あり」に変わるみたいな話だ。
 実際、上の記事でも書かれているが、学歴フィルターというのは間違いなくある程度は存在している
 昔、知り合いからきいた話なのだが、企業の人事部の採用担当はリクナビとかマイナビのような就活仲介サービスを通じて、登録している学生たちに会社説明会や入社試験の案内を送ったりする。で、何年も前の話なので今はどうだか知らないが、その説明会の案内メッセージを学生に送ろうとすると1件1件いちいちリクナビ等に課金されるので*3、採用担当が確保している予算の範囲内に費用を抑えるため、適当に絞り込みを行いたいと考えるらしい。だからそのシステムも、適当に学生の属性を設定すると、その属性に該当する学生にのみ案内を送ることができる仕様になっていると聞いた。


 最近はそういう露骨な仕組みではないのかも知れないが、冷静に考えたら、何らかの形で学歴フィルタリングぐらいはされていると想像したほうがいい。
 というのも大手企業の場合、エントリーシートを出してくる学生だけでも毎年数千人になる。会社説明会の申し込みなんかはもっと多いだろう。これだけの規模になると、採用担当側からしても、初期段階でいかに効率的に学生を絞り込むかがとても重要な課題になる。その際に、とりあえず大学のランクで案内先を絞ってみようと思うのは、良いか悪いかは別にして*4、不自然な発想とは言えない。学部で絞る場合もありそうだ。もちろんそのフィルタリングのせいで優秀な人材を取りこぼすこともあるだろうが、毎年100人とか採っている企業の場合、気にするほどの影響はないだろう。
 なお学歴フィルターと言っても、偏差値の高い大学から順に優先されるとは限らない。就職人気度がある程度以上に達している有名企業は高学歴な学生から狙うのだとしても、中堅以下の企業の場合、一流大の学生ばかりを狙っても意外と来てくれなかったり、内定を出しても辞退されたり、入社しても定着しなかったりするから、あえて避けるという判断もされる。


 ところで肝心の文系院生の話に戻ると、「人数が多すぎるからとりあえずフィルタリングする」という段階で、「文系大学院在席者」を弾いている企業ってあるのだろうか?
 あるのかも知れないが、少なくとも大企業ではほぼ無いのではと想像する。私がいた会社では文系大学院在籍者がふつうに面接まで受けていたし、採用もされている。他の会社の例でも、文系院卒の社員は(大学の同級性で院進した割合とさほど変わらない程度には)見かけるし、面接に進んでいる話はもっとよく聞くから、事前に切られているという印象は、個人的には全然ない。
 
 

面接まで行けば書面上のスペックはあまり関係ない

 「文系院生」が弾かれているのかはともかく、上記のとおり説明会案内などの段階で学歴フィルターが働くことは、私は珍しくないと思っている。エントリーシート審査の段階でフィルタリングする企業も、けっこうあるかも知れない。
 ただ、とにかく面接まで進んでしまえば、「文系院生」であるかどうかは関係ないし、そればかりか大学のランクもほとんど関係ないと私は思っている。有名大学に在籍していることは多少の下駄になる(最低限の賢さを持っていると安心してもらえる)可能性はあるのだが、面接で相手の学歴を気にしながら判断するというケースは実際あまり想像できない。ましてや、「文系の大学院」に在席していることが不利になるのかどうかというと、全くならないと思う。


 というのも、技術職や研究職は別として、事務職や企画職の面接では、学生が大学で何をやってるかなんてあまり判断材料にならないのだ。
 大学での「勉強」や「サークル活動」や「アルバイト」の話は、新卒採用の面接における定番トピックではある。しかしそれは、それぐらいしか話題のない学生が多いから一応聞いているだけであって、企業で長年働いている人間からすれば、はっきりいって「全く興味ない」と言ってよい。
 この、「学生の勉強・バイト・サークルの話なんて、社会人は全く興味ない」(けどそれしか話題がないから面接で一応聞いている)というのは、文系院生に限らず全ての就活生に強く言っておきたい点だ。
 可能な範囲で、それ以外の話題を用意したほうが印象に残ることは間違いない。もし学外で何か活動していた経験があるなら、それを膨らませて話題にしたいところだ。バイトでも、金を稼ぐことではなく活動を経験することを主目的とするものなら話のいいネタになる。留学してた場合は、外国でいろいろ頑張ったという話をしておけば、無難に「ああ、あの◯◯に留学してた子ね」みたいなイメージを持ってもらえる。


 で、就職すればすぐに分かることだが、周りの社員を見渡してみると、その人が20歳そこそこの一時期に何を勉強していたかなんて関係なく、様々な仕事をして、様々な評価を得ている人がほとんどだ。だから、「大学で何を専攻してるか」とか「大学院に行ってるかどうか」が、その後の職業能力に大きく響くと思っている面接官なんて、ほとんどいないはずだ。
 ちなみに私自身は企業にいた頃から、修士の2年間であっても大学院で「研究」のサイクルを回したことがある経験は企画職においては貴重だと思っていたので、文系であっても院生・院卒に対しては好印象を持つほうで、今もそれは正しいと思っている。しかし私みたいなのは恐らく少数派だ。
 だからまぁ、大学院で学んでいることがプラスに評価されないのは非常に問題なのだが、かといってマイナスになるわけでもなく、「大半のサラリーマンのおっさんにとって、そこはどうでもいい」というのが実態ではないかと思う。
 もちろん中には「文系院生」にネガティブな偏見を持っているおっさんもいるし、学歴至上主義のおっさんもいるんだけど、そう多くはない。また、ごく普通の中小企業を受ける場合なんかは、大学院に行ってますと言うと「うちはお前がくるような会社じゃねぇ」という意味で敬遠されるケースはあると思うのでそこは注意が必要だ。
 
 

重要なのは「ストーリーをでっち上げる」技術

 就活に成功した学生の話を色々聞いてみると分かるが、「その会社を受けにきた経緯」として相手が理解しやすい手短なストーリーをでっち上げるスキルを、だいたいみんな持っている。そして、履歴書やESに書いた事柄はいずれも面接で話題になる可能性があるから、とにかくどこを突かれても「ああ、なるほどね」ととりあえず理解させる程度のストーリーをちゃんと考えている。
 これは就活において最も重要な準備だと私は思うのだが、これができていない学生はとても多い。


 「志望動機」は面接で必ず聞かれるだろう。その際、単に「御社の◯◯のビジネスに大変興味がありまして」みたいな話をしていてはダメだ。「めっちゃ興味あるんです!」みたいにその度合いをアピールしても、面接官の頭には全く入らない。また、「御社のビジネスはこういう点で素晴らしいと思うから」系の話もダメだ。これは特に気をつけて欲しいのだが、「優れた会社だから受けに来ました」なんて言われても、面接官にはまったく響かないのである。
 そうじゃなく、「あ、なるほど、そういう経緯で君はこの会社や業種を受けに来てるんだね」と思わせられるような「ストーリー」を組み立てて、志望理由を説明できないといけないのだ。「経緯」とか「エピソードのつながり」とか「話の流れ」が大事なわけ。しかしたぶん、こう言ってもわからない学生も多いだろうとは思う。うーん伝えるのが難しい……。


 志望動機のストーリーというのは、履歴書に書いた他の情報(たとえば所属している学部)とストレートに繋がるものではなくてもよい。たとえば逆に、「大学では◯◯を専攻してるんですが、実は結果的にそれにはあまり興味を持てませんでして(笑)、ここ最近はずっと個人的にこういうことを調べてて、その関連で御社の▲▲事業に関心を持ったんです」みたいに、「関係ない」ということをあえて積極的に説明するストーリーだってあり得ると思う。
 また、美しいストーリーや面白いストーリーであるかどうかは、意外と重要ではない。それよりも、「なるほど、まぁ、ありそうな経緯だな」と腹落ちさせることがまず大事なのだ。文系だろうが理系だろうが、学部生だろうが院生だろうが、学部や専攻が何であろうが、何のバイトをして何のサークルに入ってようが、とにかく「それはありそうだなと思えるストーリー」を考えることから全ては始まるのだ。


 院生だと、「大学院ではどんな研究してるんですか?」という話を振られることは文系でも多いだろう。で、研究と志望動機を結びつけるストーリーはもちろん用意しておかなければならないのだが、その内容は色々あり得る。
 「研究の具体的内容」については、あえて触れないほうが話を作りやすい場合だってある。たとえば、入社後はマーケティング調査とかをする仕事に興味ありますということにしておいて、「大学院では◯◯の研究をしてたんですが、論文を書く際に、先行研究とか公的な統計情報とかを徹夜しながら死ぬほど調べました。そういう、調べて何かを明らかにするという作業が自分は好きだし向いているんだと分かりまして〜」みたいな言及の仕方をしたっていいだろう。
 これはまぁ、企業の志望動機というより部署や業務内容の志望動機だが*5、実際に調べ物をろくにしてない人でも言えるし、会社の仕事に調べ物はつきものなので、どこの部署を希望するにしても関係なく使えそうだ。大して面白い話ではないが。


 また、「なぜ大学院に進もうと思ったのか」も聞かれる可能性は高く、そこにもストーリーが必要だ。これはぜひ覚えておいてほしいのだが、日本の文系サラリーマンは大学院がどういうところか知らないので、実際は修士課程なんて単にモラトリアムで進学しただけの院生も多いのに、「院生」=「ホンネでは研究者志望の人たち」と思い込んでいる場合がけっこうある。だから、「なぜ大学院に進もうと思ったのか」という質問は、「院生なのになぜ民間企業を受けに来てるのか」という疑問をも含んでいる。
 文系サラリーマンからみると、修士であっても「大学院生なのに民間企業を受けに来きている」ということ自体がけっこう謎というか、「よく分からない存在」になってしまっていて、これが文系院生の就活における最大のネックとなっている側面はある。だからそういう「謎」感があることを前提に、その謎感を払拭するようなストーリーを説明してあげる必要がある。
 私が文系院生だったら、自分からまず「院生なのでよく『研究者志望なの?』って聞かれるんですけども〜」という前置きをして話を始めると思う。この言い方であれば、面接官が持っている「謎」感にまず理解を示すことで、安心というか分かってる感を与えることができるし、相手が院生に対する偏見の持ち主ではなかった場合も失礼にはあたらない。その上で、「もともとは研究職というのも少し考えてたんですが、大学院に入ってから◯◯(人でも知識でもよい)との出会いがあって、民間就職したいという思いが強くなりまして〜」という話にするか、「もともと研究職志望では全くなく、修士を出たら就職するつもりだったんですが〜(何か院に行った理由を続ける)」というパターンでいくかは、人にもよるし状況次第だ。


 就活において、「謎な感じ」をなくすことは全ての出発点である。たとえば有名企業の場合、「有名だから受けに来ている」という学生も多く、採用する側もそれは知ってるからその点では謎はないのだが、「本当にうちの仕事に興味があるのか」が分からないという意味では、やはり謎である。褒められようとか、目立とうとか、そんなことを考える前に、まず「謎が残らない学生」になっておかないと、いくら頑張っても無駄である。「不思議ちゃんの未知の魅力に賭ける」みたいなことは、現実の企業ではほぼ無いと思ったほうがよい。「実はうちの社員なのではないか」と錯覚するほど違和感のない学生というのは、滅多にいるものではないが、目指すべき方向性としてはそっちである。
 
 

失敗する原因はたぶん「準備不足」

 理系に比べると、文系の場合は大学院に進学する割合が低いから、面接を受けにくる学生のなかで多少目立つとは言える。目立つということは、上で述べた「謎」感の解消もそうなのだが、「納得のいく説明を求めるポイント」が少し増えるわけで、「腹落ち」までのハードルという意味では少しだけ不利だとも言えるのかもしれない。
 しかし、たとえば面接官に「あなたは大学院で◯◯を専攻してるよね。それってうちの会社の仕事とは全然関係なさそうな気がするけど、いいの?」と聞かれて、相手に「なるほど」と言わせる回答が即座にできないのは、ハッキリいってただの準備不足だと言わざるを得ない。そして、そこさえクリアすれば何も不利ではないのだ。


 学生時代にやっていた活動の延長上にあるような企業を受ける場合は、理由を「でっち上げる」必要はない。しかしたいていの人は、1社や2社ではなく、数社から十数社(40社ぐらいという人も珍しくはない)を幅広く受けるだろうから、そういう工夫はどこかで必ず必要になる。
 そのストーリーでっち上げの工夫というのは、大して高度なものではないのだが、意外とできない人、やらない人が多い。私が就活生に一番言いたいのはこれだ。
 何か強いこだわりを持っていて、相手にあわせてストーリーをでっち上げるなんてことには抵抗があるという人もいるだろうけど、それよりは単に「いいストーリーを思いつかない」人、さらにそれよりも「そういうストーリーの準備が必要だと分かってない」人が多いように見える。


 履歴書やESというのは、面接官にどういう質問をさせたいか、面接官とどういう話がしたいかを考えて「誘導する」ように書くべきものだと学生時代に教わったのだが、たぶんそのとおりだ。これは、会社に入ってから営業提案とか社内稟議の書類を作る場合だって同じ話である。
 そしてその際に、もちろん「面白い話」や「すごい話」になっていればそれに越したことは無いのだが、それには能力や特殊な経験が必要だ。でもそれ以前にまず、「ストーリーとして流れが不自然ではない話」にする必要があり、これは準備さえすればできることなのだが、その努力をサボって脱落するパターンが半分ぐらいあるように思う。


 たとえば、ものすごくローカルな企業(や市役所)を受ける時に、「あえてその地域で就職したいと思った理由」を全く考えてなかったら話にならない。特にその地域の出身者でないのであれば、「なんでわざわざこんなところで就職するの?」と聞かれるのは当然なのであって、事前に「なるほど」と思わせる回答を考えておかないといけない。でも案外、その程度の準備もしてない就活生が、けっこうな割合でいるのだ。


 就活の面接では「コミュニケーション能力」が問われるとよく言われるが、そのアドバイスはあまり役に立たない。コミュニケーション能力なんて、短期間では大して向上しないからだ。
 それより私が言っておきたいのは、合否を分ける、コミュ力と同じぐらい重要な要素があって、それは「準備してきてる感」だ。「俺が学生だったら、このぐらいは準備して面接を受けるだろうな」という感覚的な基準が面接官の側にはあって、その水準の準備を「してきてない感」が感じられると、その学生の評価は一気に下がるのである。これについては対策が可能なのだから、気をつけてほしい。
 「入社後はどんな部署で働きたいですか」とか「競合他社ではなくうちの会社に入りたいのはなぜですか」という質問をすると、その学生がうちの会社のことをどれだけ調べて来ているかというレベルは一瞬で分かる。学生が思っている以上に、マジで一瞬で分かる。ここで一定のレベルを下回ってしまうと、どれだけコミュニケーション能力があっても高評価にはなりづらい。「いや、嘘でもいいから、そこは何か考えてからくるでしょ普通……」って思ってしまうのだ。


 こういうことは就活対策をする過程で誰かに教わったり、就活セミナーに行ってきた同級生から聞かされることが多いと思う。ただ、文系の院生は少数派=外れ者ではあって、学部3〜4年生の時にみんなと一緒にそういう「最低限の準備」をする経験をしておらず、そのせいで「準備の必要性」をあまり認識していないパターンはけっこうあるはずだ。文系院生に不利な点があるとすれば、肩書ではなく、まずそこだろう。 
  

就活はたいていの人が思うより多様

 私が書いてるこのエントリについても言えることなのだが、就活や採用というものについて1人の人間が知っている側面は非常に限られているので、ほとんどのアドバイスは話半分に聴くべきだ。
 どういう人材が求められるかは、業種によっても、職種によっても、会社の規模によっても、会社の文化によっても、その時会社が抱えている課題によっても、さらには会社内の部署によっても、その部署にいる社員のパーソナリティによっても、異なってくる。私も含めて大抵の人は、自分が知っている狭い範囲の経験に基づいて語っているのだが、だいたい人間は自分の視野の広さを過信しがちで、自分の考えが一般的に当てはまると勘違いするものなので、注意が必要だ。


 就活には、結局「やってみないとわからん」面が結構ある(スキルが絶望的に低かったり、神レベルで高かったりすると別だろうけど)。上記のような「準備」を全くしてなかったら落ちるということは分かるが、それなりの準備をしているのであれば、あとは運だと思って数をこなすしかないと思う。動いたもん勝ちというのは、けっこう正しい。


 私の印象では、準備を十分にしない学生は、数をこなすことにも後ろ向きな傾向がある。「企業の人はこう思っているはず」「私に向いてるのはこういう仕事のはず」「あの会社はこういう人材を求めているはず」みたいな思い込みを勝手に持っているせいで、選択肢を必要以上に絞り込んでしまっている。「こういう業界や職種には私は向いてない」みたいな思い込みが多くて、なかなか視界が広がってこないのだが、非常にもったいない。
 そういえば去年まで働いてた会社に、東大卒でアメリカでMBAを取った先輩がいて、その人からはいろいろ教わって勉強になったのだが、そんな人でも「この会社の中にこんな仕事があるとは、入る前は想像してなかった」みたいなことを言っていた。会社というのはそういうもんで、外から見たってよく分からないのである。
 何十年も働いている社会人ですら、自分の会社や業界以外については、どんな人がどんな仕事をしているのかなんて大して知らない。ましてや学生にそんなものが想像できるわけがない。だから、特殊な専門業種にこだわるのでなければ、ある程度は盲目になって色々受けてみるというのは大事なことだと思う。


 ところで、ついでにもう一本、就活エントリを書いておきました。こっちは文系事務職ではなく、研究・開発職の話です。
 blog.statsbeginner.net


【2018/12/10 追記】
「アカリク アドベントカレンダー2018」に掲載されました。
大学院生向けの就活情報をまとめたサイトで、けっこう役に立つのでは?
https://adventcalendar.acaric.jp

*1:「専門性を生かしたい」とか思ってる人は自分で間口を狭めてるだけだから、考察の対象外とし、ここでは「学部卒の奴らと同等に就職したい」と思っている文系院生のみを想定してるので、主に事務職・総合職の採用について考える。

*2:古臭い業界の、巨大企業。

*3:1件100円ぐらいかかると聞いた気がするけどうろ覚え。でもとにかく、けっこう高いという話だった。

*4:私自身の会社員経験では、周りを見ていて大学のランクと仕事で活躍できるかどうかはあまり関係がなかったので、フィルタリングは良いことだとは思わない。

*5:内定までの段階で部署なんか決まらないのだが、面接の話題として、どんな部署で働きたいと思うかはよく聞かれる。

Python3でのメール送信時に日本語の差出人名を使う

以前のエントリで、Pythonからのメールの送信を試しましたが、


www.statsbeginner.net


この時は文中にも書いているとおり、差出人名を日本語表示するのがうまく出来ませんでした。
ところがその問題は、下記の方法で解決しました。


teratail.com


要するに、'差出人名 <アドレス>'という文字列を用意する時に、まるごとMIMEエンコードしてはダメで、「差出人名」のところだけがエンコードされるようにしなければならない。
それは前回のエントリ時点でも分かっていたんですが、なんか書き方が間違ってたようです。
どうやら、まず差出人名の文字列を.encode()メソッドでエンコードした上で、それをHeader()関数に与える際もHeader()関数の引数にエンコードを指定し、さらに、Headerオブジェクトそのものに.encode()メソッドを書き加えるということをしなければならなかったようです。
ただ、1個めの.encode()は要するに、Header()関数の引数としてエンコードされたバイト文字列を渡しているわけですが、べつにここにstr型で渡しても問題なく作動しました。
最後の.encode()は、これをつけることでRFCに沿ってMIMEエンコードされた文字列をstr型で受け取ることができるということのようです(説明)。これをつけないとこの部分がemail.header.Headerクラスのままになるので、あとで%sするときに不都合が起きるようです。


ということで、下記のように、

sender = '%s <%s>'%(Header('差出人名'.encode('iso-2022-jp'),'iso-2022-jp').encode(), メアド)


というように書いて、これをMIMEオブジェクトに与えて送信したら、ちゃんと表示されました。
一件落着です。


あと、何回か使ってみて、送信エラーが起きる理由は大きくわけて、

  1. 本文や名前(文中に宛名を差し込みする時)の日本語文字に'iso-2022-jp'でエンコードできないテキストが含まれている場合
  2. 送信途中でネットの回線が切れた場合

ですね。
なんかもうべつにUTF8で良い気はしてきました。