Code
# tidyverseの読み込み
::p_load(tidyverse)
pacman
# 例に用いる二つのデータフレームを作成
= tibble(firm_ID = c(1, 2),
A stock_price = c(120, 500)) # 株価データが格納されたAを作成
= tibble(firm_ID = c(1, 3),
B DPS = c(5, 10)) # DPSデータが格納されたBを作成
2024/05/10
2024/05/17
join
系関数(教科書コラム5.2)dplyr
にはfull_join()
関数を始め,結合を行うために用いるjoin
系関数が用意されている.A
とDPSデータB
の結合を通じて,それぞれのjoin
系関数の返り値を確認していこう.tibble()
関数を使って二つのデータフレームを手動で作成している.full_join()関数
inner_join()
関数# A tibble: 1 × 3
firm_ID stock_price DPS
<dbl> <dbl> <dbl>
1 1 120 5
left_join()
関数# A tibble: 2 × 3
firm_ID stock_price DPS
<dbl> <dbl> <dbl>
1 1 120 5
2 2 500 NA
simulation_data
フォルダにあるfinancial_data.csv
をデータフレームfinancial_data
として読み込んでみよう.head()
関数により,financial_data
の冒頭6行を表示し,どのようなデータが収録されているか確認してみよう.codes
である場合,読み込みたいfinancial_data.csv
が格納されているsimulation_data
フォルダにアクセスするには,一個上の階層に一度戻る必要があり,それは..
により実現可能である.simulation_data
フォルダに移動 (/simulation_data
)し,/financial_data.csv
で目的のファイルにアクセス可能である.Rows: 22855 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
dbl (6): firm_ID, year, macc, X, TA, CFO
date (1): fiscal_year_end
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# A tibble: 6 × 7
firm_ID fiscal_year_end year macc X TA CFO
<dbl> <date> <dbl> <dbl> <dbl> <dbl> <dbl>
1 8 2004-07-01 2004 12 3125 204270 3319
2 8 2005-07-01 2005 12 3973 197259 4571
3 8 2006-07-01 2006 12 4117 203422 3820
4 8 2007-07-01 2007 12 4277 217386 2367
5 8 2008-03-01 2008 8 4743 218038 5591
6 8 2009-03-01 2009 12 5445 222643 3604
fiscal_year_end
: 決算年月 (YYYY-MM-DD形式)macc
: 決算月数X
: 当期純利益(百万円)TA
: 資産合計(百万円)CFO
: 営業活動によるキャッシュフロー(百万円)X
を基準化分析にあたっては,当期純利益X
そのものの分布ではなく,各企業の規模を統制して各観測値を横並びで比較可能にしたScaled Earnings (SE
)の分布を考えよう.
\[ \underbrace{SE_{i,t}}_{\textbf{企業$i$の年度$t$のScaled Earnings}} = \frac{\overbrace{X_{i,t}}^{\textbf{企業$i$の年度$t$の当期純利益}}}{\text{各企業の規模の代理変数}} \]
この分析では,簡便的に各企業の発行する株式の時価総額 (株価 \(\times\) 発行済株式数)を規模の代理変数と捉え,分析を進めて行こう.
simulation_data
フォルダにあるstock_data.csv
をstock_data
として読み込んでみよう.Rows: 22852 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
dbl (4): firm_ID, year, stock_price, shares_outstanding
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# A tibble: 6 × 4
firm_ID year stock_price shares_outstanding
<dbl> <dbl> <dbl> <dbl>
1 8 2007 412 117800776
2 8 2008 514 117800776
3 8 2009 743 117800776
4 8 2010 718 117800776
5 8 2011 1015 117800776
6 8 2012 958 117800776
stock_price
: 株価shares_outstanding
: 発行済株式数stock_data
に時価総額ME
列の追加1e6
は科学技術分野で一般的に用いられる科学的表記と呼ばれる表記法(教科書157頁)であり,\(1 \times 10^6 (= 1,000,000)\)と等しい.ME
を計算する際,財務データと単位を揃えることを目的として1e6
で除している.(stock_price * shares_outstanding) / 1000000
とはしないこと!SE
列も追加dplyr
のif_else()
関数を使って決算月数が12ヶ月の場合はSE
を計算し,そうでなければ欠損値NA
になるように工夫している.sample
を利用して分析を進めて行こう.SE
が欠損値となっている観測値を除外(\(=\) SE
が計算可能な観測値のみを抽出)し,分析対象となるデータフレームをsample
として定義してみよう.drop_na()
の使い方は,ここを参照.summarize()
関数を使ってみようsample
を用いて,年度ごとにSE
の平均値を算出し,それをMean
列と名付けよう.year
列とMean
列から成るデータフレームをtable_1
として定義しよう.# A tibble: 6 × 2
year Mean
<dbl> <dbl>
1 2005 0.0144
2 2006 0.0126
3 2007 -0.0109
4 2008 0.0337
5 2009 0.0749
6 2010 0.0378
table_1
として定義.year
でグループ化.summarize
関数を適用し,SE
の平均値をmean(SE)
により計算し,それをMean
と命名.quantile()
関数の使い方quantile()
関数を用いる.この関数は第一引数に入力データ(数値ベクトル),第二引数に求めたい分位点の値をパーセントでなく小数表示で代入する(教科書185頁).SE
の第1四分位を求めたいならば,quantile(SE, 0.25)
とすれば良い.write_csv()
関数を使ったデータフレームの出力readr
のwrite_csv()
関数を使って,先に作成したデータフレームtable_1
をtables
フォルダに出力しよう.write_csv()
関数の第一引数はデータフレーム名を入力し,第二引数でファイル名を指定する(教科書184頁).codes
であることを前提にすれば,出力したいtables
フォルダへ移動するには,一個上の階層に一度戻る必要があり,それは..
により実現可能である.tables
フォルダに移動 (/tables
)し,table_1.csv
という名前で出力 (/table_1.csv
)すれば良いので,write_csv()
関数の第二引数は,"../tables/table_1.csv"
と指定する.SE
)のヒストグラムggplot2
を利用し,Scaled Earnings (SE
)のヒストグラムを描画し,利益マネジメントの実態を明らかにしていこう.sample
内のSE
について,-0.2から0.2までのSE
のヒストグラムを描画しよう.
Earnings Interval
,\(y\)軸のラベルはFrequency
とする.SE
のヒストグラムの描画geom_vline()
関数は,vertical(垂直)に直線を引く.xintercept
引数で値を指定し,またlinetype
引数で適当な線種を指定する(dashed
の他にも,dotted
やsolid
など多様にオプションが用意されている).PNG
形式で出力figures
フォルダにfigure_1.png
の名前を付して出力しよう.ggsave()
関数を利用する.第一引数にはファイル名を指定しよう.figures
フォルダのある階層を意識して第一引数を指定しよう.Saving 7 x 5 in image
SE
が正で少なくとも過去1期は損失回避できた企業群だけに絞り,同様のヒストグラムを描画する方法を実践していこう.mutate()
関数とlag()
関数を組み合わせて,一期前のSE
を表すlagged_SE
をデータフレームsample
に追加しよう.
if_else()
関数を用いてyear
とlag(year)
との関係を示す条件式を予め指定し,lagged_SE
の計算式を工夫するのが理想的である.lagged_SE
列が追加できれば,前年度損失回避企業をfilter()
関数により抽出し,パイプ演算子を使って抽出データをggplot()
関数に引き渡して一気にヒストグラムの可視化まで行ってみよう.首藤昭信 (2010)『日本企業の利益調整: 理論と実証』中央経済社.↩︎
---
title: "5 利益分布アプローチによる利益マネジメントの実態分析"
date: 2024/05/10
format:
html: default
revealjs:
output-file: 5_earnings_slide.html
---
## `join`系関数(教科書コラム5.2)
### 二つのデータフレームの結合
- 実証会計・ファイナンスでは,財務データと株式データの結合を典型例として,二つのデータフレームを結合する場面にしばしば遭遇する.
- `dplyr`には`full_join()`関数を始め,結合を行うために用いる`join`系関数が用意されている.
- 以下では,**株価データ`A`とDPSデータ`B`**の結合を通じて,それぞれの`join`系関数の返り値を確認していこう.
```{r}
# tidyverseの読み込み
pacman::p_load(tidyverse)
# 例に用いる二つのデータフレームを作成
A = tibble(firm_ID = c(1, 2),
stock_price = c(120, 500)) # 株価データが格納されたAを作成
B = tibble(firm_ID = c(1, 3),
DPS = c(5, 10)) # DPSデータが格納されたBを作成
```
- 上のコードでは,`tibble()`関数を使って二つのデータフレームを手動で作成している.
------------------------------------------------------------------------
### 完全外部結合`full_join()関数`
![](images/Fig34.png){width="75%"}
------------------------------------------------------------------------
### 内部結合`inner_join()`関数
```{r}
# inner_join()関数による欠損値の処理
A %>% inner_join(B, by = "firm_ID")
```
![](images/Fig32.png){width="80%"}
------------------------------------------------------------------------
### 左結合`left_join()`関数
```{r}
# left_join()関数による欠損値の処理
A %>% left_join(B, by = "firm_ID")
```
![](images/Fig33.png){width="80%"}
## 分布の不連続性(教科書コラム5.3)
### 成績評価チート
![](images/Fig01.png){width="80%"}
------------------------------------------------------------------------
### その他の例
::: columns
::: {.column width="50%"}
- 大相撲の勝ち星 ![](images/Fig02.png){fig-align="center"}
:::
::: {.column width="50%"}
- 食べログ3.6問題 ![](images/Fig03.png){fig-align="center"}
:::
:::
------------------------------------------------------------------------
## 分析の準備
### 財務データの読み込み
- 会計利益の分布に果たして歪みがあるかを検証を進めるため,まずは分析に利用する財務データを読み込むことから始めよう.
::: {.callout-note icon="false"}
#### 目標
- [**目標1:**]{style="color: blue"} `simulation_data`フォルダにある`financial_data.csv`をデータフレーム`financial_data`として読み込んでみよう.
- [**目標2:**]{style="color: blue"} その後,`head()`関数により,`financial_data`の冒頭6行を表示し,どのようなデータが収録されているか確認してみよう.
:::
------------------------------------------------------------------------
### フォルダ構造
- 現在地が`codes`である場合,読み込みたい`financial_data.csv`が格納されている`simulation_data`フォルダにアクセスするには,[**一個上の階層に一度戻る必要があり,それは`..`により実現可能**]{style="color: blue"}である.
- あとは,`simulation_data`フォルダに移動 (`/simulation_data`)し,`/financial_data.csv`で目的のファイルにアクセス可能である.
![](images/Fig24.png){width="80%"}
------------------------------------------------------------------------
### 目標を達成するためのコード例
```{r}
# 財務データの読み込み
financial_data <- read_csv("../simulation_data/financial_data.csv")
# head()関数を用いて冒頭6行の結果のみ表示
head(financial_data)
```
::: columns
::: {.column width="50%"}
- `fiscal_year_end`: 決算年月 (YYYY-MM-DD形式)
- `macc`: 決算月数
- `X`: 当期純利益(百万円)
:::
::: {.column width="50%"}
- `TA`: 資産合計(百万円)
- `CFO`: 営業活動によるキャッシュフロー(百万円)
:::
:::
------------------------------------------------------------------------
### 当期純利益`X`を基準化
- 分析にあたっては,当期純利益`X`そのものの分布ではなく,各企業の規模を統制して各観測値を[**横並びで比較可能にしたScaled Earnings (`SE`)の分布**]{style="color: blue"}を考えよう.
$$
\underbrace{SE_{i,t}}_{\textbf{企業$i$の年度$t$のScaled Earnings}} = \frac{\overbrace{X_{i,t}}^{\textbf{企業$i$の年度$t$の当期純利益}}}{\text{各企業の規模の代理変数}}
$$
- この分析では,簡便的に各企業の発行する[**株式の時価総額 (株価** $\times$ 発行済株式数)を規模の代理変数]{style="color: red"}と捉え,分析を進めて行こう.
------------------------------------------------------------------------
### 株式データの読み込み
- Scaled Earningsのデフレータとなる時価総額を得るため,`simulation_data`フォルダにある`stock_data.csv`を`stock_data`として読み込んでみよう.
```{r}
# 株式データの読み込み
stock_data <- read_csv("../simulation_data/stock_data.csv")
head(stock_data)
```
- `stock_price`: 株価
- `shares_outstanding`: 発行済株式数
### `stock_data`に時価総額`ME`列の追加
![](images/Fig04.png){width="80%"}
```{r}
# mutate()関数を使ってME列の追加
stock_data <- stock_data %>%
mutate(ME = (stock_price * shares_outstanding) / 1e6) # MEを百万円単位で計算
```
------------------------------------------------------------------------
### 単位確認の重要性
- 先のコードで登場した`1e6`は科学技術分野で一般的に用いられる[**科学的表記**]{style="color: red"}と呼ばれる表記法[(教科書157頁)]{style="color: blue"}であり,$1 \times 10^6 (= 1,000,000)$と等しい.
- 会計・ファイナンス研究で頻用される[**財務データは,一般的に百万円単位でデータが収録**]{style="color: blue"}されているため,`ME`を計算する際,財務データと単位を揃えることを目的として`1e6`で除している.
- `(stock_price * shares_outstanding) / 1000000`とはしないこと!
------------------------------------------------------------------------
### 財務データと株式データの結合
![](images/Fig05.png){width="80%"}
------------------------------------------------------------------------
### パイプ演算子を繋げて`SE`列も追加
```{r}
# 財務データと株式データの結合し,SE列も追加
financial_data <- financial_data %>%
left_join(stock_data, by = c("firm_ID", "year")) %>%
mutate(SE = if_else(macc == 12, X / ME, NA))
# 決算月数が12ヶ月ではないものは欠損値に
```
- 上のコードでは,`dplyr`の`if_else()`関数を使って決算月数が12ヶ月の場合は`SE`を計算し,そうでなければ欠損値`NA`になるように工夫している.
![](images/Fig06.png){width="80%"}
------------------------------------------------------------------------
## 利益分布アプローチによる分析
### サンプルの確定
- データの前処理が完了すれば,分析対象を確定させ,新たなデータフレーム`sample`を利用して分析を進めて行こう.
::: {.callout-note icon="false"}
#### 目標
- ここでは,`SE`が欠損値となっている観測値を除外($=$ `SE`が計算可能な観測値のみを抽出)し,分析対象となるデータフレームを`sample`として定義してみよう.
:::
------------------------------------------------------------------------
### 目標を達成するためのコード例
```{r}
# 分析に利用する観測値のみのデータフレームsampleを作成
sample <- financial_data %>%
drop_na(SE) # SEが欠損値のものを削除
```
- `drop_na()`の使い方は,[ここ](#drop_na)を参照.
------------------------------------------------------------------------
### 集計作業の実践 --- `summarize()`関数を使ってみよう
::: {.callout-note icon="false"}
#### 目標
- データフレーム`sample`を用いて,年度ごとに`SE`の平均値を算出し,それを`Mean`列と名付けよう.
- こうして出来た`year`列と`Mean`列から成るデータフレームを`table_1`として定義しよう.
:::
------------------------------------------------------------------------
### 目標を達成するためのコード例
```{r}
# 年度ごとにSEの平均値を計算
table_1 <- sample %>% # 集計結果をtable_1として定義
group_by(year) %>% # 年度でグループ化
summarize(Mean = mean(SE)) # 平均値をMeanと命名
head(table_1) # 内容の確認
```
- [**2行目:**]{style="color: blue"} 以下の処理により作成されるデータフレームを`table_1`として定義.
- [**3行目:**]{style="color: blue"} 年度`year`でグループ化.
- [**4行目:**]{style="color: blue"} `summarize`関数を適用し,`SE`の平均値を`mean(SE)`により計算し,それを`Mean`と命名.
------------------------------------------------------------------------
### 更に一歩進んで,年度ごとに基本統計量を集計
```{r}
# 年度ごとに基本統計量を集計
table_1 <- sample %>%
group_by(year) %>% # 年度毎にグループ化
summarize(N = n(), # 観測値数
Mean = mean(SE), # 平均値
SD = sd(SE), # 標準偏差
Q1 = quantile(SE, 0.25), # 第1四分位
Median = median(SE), # 中央値
Q3 = quantile(SE ,0.75)) # 第3四分位
```
![](images/Fig08.png){width="80%"}
------------------------------------------------------------------------
### `quantile()`関数の使い方
- 分位点を求めるには`quantile()`関数を用いる.この関数は第一引数に入力データ(数値ベクトル),第二引数に求めたい分位点の値をパーセントでなく[**小数表示**]{style="color: red"}で代入する[(教科書185頁)]{style="color: purple"}.
- 例えば,`SE`の第1四分位を求めたいならば,`quantile(SE, 0.25)`とすれば良い.
![](images/Fig09.png){width="80%"}
------------------------------------------------------------------------
### 出力結果のアレンジ --- 桁数の調整
```{r}
#| code-line-numbers: "5"
# 年度ごとに基本統計量を集計(平均値のみ桁数調整)
table_1 <- sample %>%
group_by(year) %>% # 年度毎にグループ化
summarize(N = n(), # 観測値数
Mean = round(mean(SE), 3), # 平均値
SD = sd(SE), # 標準偏差
Q1 = quantile(SE, 0.25), # 第1四分位
Median = median(SE), # 中央値
Q3 = quantile(SE, 0.75)) # 第3四分位
```
![](images/Fig10.png){width="80%"}
------------------------------------------------------------------------
### `write_csv()`関数を使ったデータフレームの出力
```{r}
# table_1の結果を出力
write_csv(table_1, "../tables/table_1.csv")
```
- `readr`の`write_csv()`関数を使って,先に作成したデータフレーム`table_1`を`tables`フォルダに出力しよう.
- `write_csv()`関数の第一引数はデータフレーム名を入力し,第二引数でファイル名を指定する[(教科書184頁)]{style="color: purple"}.
- 現在地が`codes`であることを前提にすれば,出力したい`tables`フォルダへ移動するには,[**一個上の階層に一度戻る必要があり,それは`..`により実現可能**]{style="color: blue"}である.
- あとは,`tables`フォルダに移動 (`/tables`)し,`table_1.csv`という名前で出力 (`/table_1.csv`)すれば良いので,`write_csv()`関数の第二引数は,`"../tables/table_1.csv"`と指定する.
------------------------------------------------------------------------
### Scaled Earnings (`SE`)のヒストグラム
- 締めくくりとして,`ggplot2`を利用し,Scaled Earnings (`SE`)のヒストグラムを描画し,利益マネジメントの実態を明らかにしていこう.
::: {.callout-note icon="false"}
#### 目標
- データフレーム`sample`内の`SE`について,-0.2から0.2までの`SE`のヒストグラムを描画しよう.
- ビン幅は0.005とする.
- $x$軸のラベルは`Earnings Interval`,$y$軸のラベルは`Frequency`とする.
- (余力がある人は)Burgstahler and Dichev (1997)同様,$x = 0$の破線を引き,ベンチマークが一目瞭然で分かるように調整.
:::
------------------------------------------------------------------------
### オリジナル論文のヒストグラム (Fig. 3)
![](images/Fig37.png){fig-align="center"}
### `SE`のヒストグラムの描画
```{r}
# SEのヒストグラムの描画
ggplot(sample) +
geom_histogram(aes(x = SE),
breaks = seq(-0.2, 0.2, 0.005)) +
labs(x = "Earnings Interval", y = "Frequency") +
scale_y_continuous(expand = c(0, 0)) +
theme_classic()
```
### $x = 0$を表す破線の追加
- `geom_vline()`関数は,vertical(垂直)に直線を引く.`xintercept`引数で値を指定し,また`linetype`引数で適当な線種を指定する(`dashed`の他にも,`dotted`や`solid`など多様にオプションが用意されている).
```{r}
#| code-line-numbers: "7"
# SEのヒストグラムの描画
ggplot(sample) +
geom_histogram(aes(x = SE),
breaks = seq(-0.2, 0.2, 0.005)) +
labs(x = "Earnings Interval", y = "Frequency") +
scale_y_continuous(expand = c(0, 0)) +
geom_vline(xintercept = 0, linetype = "dashed") +
theme_classic()
```
### 完成したグラフを`PNG`形式で出力
::: {.callout-note icon="false"}
#### 目標
- こうして描画されたヒストグラムを`figures`フォルダに`figure_1.png`の名前を付して出力しよう.
:::
- **(ヒント1)** 直前に出力したグラフを保存したい場合,`ggsave()`関数を利用する.第一引数にはファイル名を指定しよう.
- **(ヒント2)** `figures`フォルダのある階層を意識して第一引数を指定しよう.
### 目標を達成するためのコード例
```{r}
# ggsave()関数を使ってSEのヒストグラムをfigure_1.pngとして出力
ggsave("../figures/figure_1.png")
```
- 必要に応じてグラフのサイズなどの細部を調整したい場合は,別途引数により調整すれば良い.
```{r}
# 出力サイズを明示的に指定して出力
ggsave("../figures/figure_1.png",
width = 20, # 幅を指定
height = 10, # 高さを指定
units = "cm") # 幅と高さの単位を指定
```
## 練習問題
### 損失回避期間と利益マネジメントのインセンティブ
- Burgstahler and Dichev (1997)や首藤 (2010)[^1]では,過去において[**損失回避期間が長い企業の経営者**]{style="color: red"}ほど,損失を回避するインセンティブが高まり,[**分布の歪みがより顕著**]{style="color: red"}に現れることが明らかにされている.
- ここでは,その検証結果の再現を試みる一環として,[**一期前の`SE`が正で少なくとも過去1期は損失回避できた企業群**]{style="color: blue"}だけに絞り,同様のヒストグラムを描画する方法を実践していこう.
### 前年度損失企業のみを抽出して描画
::: {.callout-note icon="false"}
#### Exercise
- [**目標1:**]{style="color: blue"} 最初に`mutate()`関数と`lag()`関数を組み合わせて,一期前の`SE`を表す`lagged_SE`をデータフレーム`sample`に追加しよう.
- (注意点) [**一行前が必ずしも一期前とは限らない**]{style="color: red"}ため,`if_else()`関数を用いて`year`と`lag(year)`との関係を示す条件式を予め指定し,`lagged_SE`の計算式を工夫するのが理想的である.
- [**目標2:**]{style="color: blue"} `lagged_SE`列が追加できれば,前年度損失回避企業を`filter()`関数により抽出し,パイプ演算子を使って抽出データを`ggplot()`関数に引き渡して一気にヒストグラムの可視化まで行ってみよう.
:::
[^1]: 首藤昭信 (2010)『日本企業の利益調整: 理論と実証』中央経済社.