[1] 7920
2026/05/01
今回はtidyverseパッケージ群の関数を本格的に使い始める回である.新しく登場する関数・演算子が多いので,まずは全体像を把握しておこう.
| 関数・演算子 | パッケージ | 役割 |
|---|---|---|
read_csv() |
readr |
CSVファイルをtibble形式で読み込む |
%>%(パイプ演算子) |
magrittr |
左の結果を右の関数の第一引数に渡す |
filter() |
dplyr |
条件に合う行を抽出する |
select() |
dplyr |
指定した列のみを選択する |
mutate() |
dplyr |
新しい列を追加する |
group_by() |
dplyr |
データをグループ化する |
ungroup() |
dplyr |
グループ化を解除する |
summarize() |
dplyr |
グループごとに集計する |
lag() |
dplyr |
一期前の値を参照する |
drop_na() |
tidyr |
欠損値を含む行を削除する |
readrのread_csv()関数を用いたデータの読み込みread_csv()関数の特徴tibbleで返す..(ピリオド)に変換したり,うっかりprint()関数で表示すると膨大な行数全てを表示してしまったりと,様々な不都合な側面があり,tibbleはそれらを改良したものである1.X.1, X.2, X.3などのように)変換しない.read_csv()関数の型推論の柔軟性'data.frame': 21 obs. of 3 variables:
$ date : chr "2020-04-01" "2020-04-02" "2020-04-03" "2020-04-06" ...
$ firm1: num -0.03948 0.00598 0.05579 0.04193 -0.02019 ...
$ firm2: num 0.07696 -0.00725 -0.0173 0.00217 0.07555 ...
spc_tbl_ [21 × 3] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
$ date : Date[1:21], format: "2020-04-01" "2020-04-02" ...
$ firm1: num [1:21] -0.03948 0.00598 0.05579 0.04193 -0.02019 ...
$ firm2: num [1:21] 0.07696 -0.00725 -0.0173 0.00217 0.07555 ...
- attr(*, "spec")=
.. cols(
.. date = col_date(format = ""),
.. firm1 = col_double(),
.. firm2 = col_double()
.. )
- attr(*, "problems")=<externalptr>
read_csv()関数で読み込んだdate列が日付型 (Date)になっていることが確認できる.他方,基本パッケージのread.csv()関数で読み込むと,この列は文字型 (chr)と認識されていたので,read_csv()関数の方がより正確に型推論できていることが分かる.[1] "numeric"
[1] "numeric"
firm_ID列とindustry_ID列は,いずれもカテゴリカル変数にも関わらず,数値型 (numeric)になっている.factor()関数を使ってきちんとファクター型に変換しておこう.# A tibble:6 x 11以下を見てみると,各変数の下にはそれぞれの変数のデータ型が記述されており,firm_IDとindustry_IDの下にある<fct>は,ファクター型を意味する.それ以外の列の<dbl>はdouble(倍精度浮動小数点数)型を意味し,実数を表すのに用いられる数値型の一種である.summary()関数を用いてみよう. year firm_ID industry_ID sales
Min. :2015 1 : 6 3 :1760 Min. : 205.3
1st Qu.:2016 2 : 6 10 :1702 1st Qu.: 16103.3
Median :2018 3 : 6 7 :1334 Median : 40430.7
Mean :2018 4 : 6 1 :1143 Mean : 166007.0
3rd Qu.:2019 5 : 6 9 : 667 3rd Qu.: 118313.8
Max. :2020 7 : 6 8 : 429 Max. :3496433.0
(Other):7884 (Other): 885
OX NFE X
Min. :-353606.7 Min. :-285383.87 Min. :-357624.8
1st Qu.: 399.3 1st Qu.: -66.43 1st Qu.: 383.3
Median : 1602.9 Median : -1.19 Median : 1586.1
Mean : 7968.9 Mean : 64.02 Mean : 7904.9
3rd Qu.: 5260.5 3rd Qu.: 41.36 3rd Qu.: 5204.6
Max. : 398034.5 Max. : 331035.25 Max. : 572588.7
NA's :1
OA FA OL
Min. : 216.5 Min. :2.884e+02 Min. :3.504e+01
1st Qu.: 12559.9 1st Qu.:6.835e+03 1st Qu.:3.965e+03
Median : 30799.2 Median :1.910e+04 Median :1.087e+04
Mean : 152272.8 Mean :8.019e+04 Mean :5.026e+04
3rd Qu.: 93469.2 3rd Qu.:5.212e+04 3rd Qu.:3.311e+04
Max. :7987936.2 Max. :2.925e+07 Max. :2.818e+06
FO
Min. : 43.6
1st Qu.: 3757.4
Median : 11125.2
Mean : 70680.6
3rd Qu.: 35446.0
Max. :7026923.6
summary()関数は,数値型(整数型や倍精度浮動小数点数型)が代入された場合,各データセットに含まれる各変数の平均や中央値,分位点を返す.TRUEとFALSEは,通称論理型 (logical)と呼ばれるデータ型である.その特徴は,TRUEとFALSEの二つのみで構成される点にある.この二つを算術関数の引数として用いると,TRUEが1,FALSEが0と解釈されるので,sum()関数の引数にcomplete.cases(financial_data)を代入することで,欠損が無い観測値数を数え上げてくれる.tidyrに含まれるdrop_na()関数は,第二引数を省略した場合,入力されたデータフレームに対し,欠損値が存在しない行のみを抽出して返す.financial_dataにアクセスできなくなってしまうからである.したがって,本来であれば元データを上書きする代わりに,新しいデータフレームにprocessed_financial_dataなどの別の変数名を付すのが望ましい.しかし,ここでは後々の説明が冗長になるのを防ぐために,あえてfinancial_dataに上書きする書き方を選んで いる.dplyrのパイプ演算子の使い方目標
%>%は,左側で処理されたデータフレームを,右側の関数の第一引数として受け渡す役割を果たす.パイプ演算子%>%の入力は,RStudio上で以下のショートカットキーを利用すると便利である.
%>% と |> の違いRには2種類のパイプ演算子がある.
%>%
magrittrパッケージ由来であり,RStudioでも広く利用されている.|>
%>%はmagrittr由来,|>は base R の機能である.|>も使えることを知っておくとよい.%>%を用いる利点%>%は「データを次の関数に渡す」だけのものであるが,それを使うと頭の中でイメージした処理の流れをそのままコードにできる という利点がある.financial_data内のsales列の自然対数の中央値を計算して,結果を表示する方法を考えてみよう.[1] 10.6074
パイプ演算子の利点
firm_ID,year,salesの三列を選択し,こうして出来上がった新たなデータフレームをfinancial_data_2015として定義しよう.financial_data_2015を作らなくても,目標を達成するだけであれば,filter()関数を適用した後のデータをggplot()関数に引き渡してあげれば良い.ggplot2でヒストグラムを描くには,geom_histogram()関数を用いる.aes()引数には,\(x\)軸の値としてlog(sales)を指定する.scale_y_continuous(expand = c(0,0))はヒストグラムが\(x\)軸にぴったりくっ付くよう調整する役割を果たす.mutate()関数を使って新たな列の追加(教科書第4.6節)\[ \begin{align} ROE_{t} = \frac{X_{t}}{\mathit{BE}_{t-1}} \label{eq:ch04_ROE} \end{align} \]
目標
financial_dataに\(t\)期末の株主資本BE列を追加する.financial_dataに\(t-1\)期末の株主資本を表すlagged_BE列を追加する.financial_dataにROE列を追加ROEをヒストグラムに可視化する.ただし,作図に利用するのは,ROEが-0.2から0.4の観測値のみ,ビン幅は0.01に指定すること.また,\(x\)軸のラベルはROE Interval,\(y\)軸のラベルはFrequencyとすること.BE列の追加dplyrでは新しい列を追加するのにmutate()関数を用いる.lagged_BE列の追加ROE列を追加mutate()関数を使って,ROE列を追加しよう.dplyr 1.1.0以降であれば,別の書き方も
group_by() → mutate() → ungroup() の流れで書いていた..by 引数を使うことで,一時的にグループ化した処理を利用して簡潔に書けるようになった..by = firm_IDはこのmutate()の中でだけ効くため,グループ化を持ち越さずに処理できる.したがって,わざわざungroup()を書く必要がない.ROEのヒストグラムggplot2を利用し,ROEをヒストグラムにより描画しよう.geom_histogram()関数のbreaks引数により\(x\)軸の範囲とビン幅を調整している.seq()関数は等差数列を作成するための関数であり,第一引数に始点,第二引数に終点,第三引数に等差数列の差分を取る(教科書84頁).ROEを描画することを考え,ビン幅に相当する等差数列の差分は0.01としてみよう.breaks引数で指定した範囲外の観測値(ROEが-0.2未満や0.4超の企業)はヒストグラムに描画されない点に注意しよう.つまり,breaks引数はビン幅の設定と同時に,描画対象のデータ範囲の指定も兼ねている.summarize関数の使い方目標
tidyrに含まれるdrop_na()関数は,第二引数で指定した変数(この場合であればROE列)に欠損値が存在しない行のみを抽出して返す(教科書152頁).group_by()関数を用いて,年度yearに基づいてグループ化.summarize()関数1を用いて,各グループ(年度)ごとに平均ROEを計算し,mean_ROE列に保存する.
summarize()関数を適用することにより,グループ化は解除される.ただし,summarize()関数は1つのグループしか解除しないため,複数の変数でグループ化した場合は注意が必要である.以下の例で確認してみよう.# A tibble: 50 × 3
# Groups: year [5]
year industry_ID mean_ROE
<dbl> <fct> <dbl>
1 2016 1 0.0786
2 2016 2 0.107
3 2016 3 0.0771
4 2016 4 0.0723
5 2016 5 0.0908
6 2016 6 0.0812
7 2016 7 0.0555
8 2016 8 0.0874
9 2016 9 0.0863
10 2016 10 0.0646
# ℹ 40 more rows
.groups引数を指定していないため,yearによるグループ化が残ったままになっている.これを防ぐには,以下のように.groups = "drop"を指定し,明示的にグループ化を解除する.# A tibble: 50 × 3
year industry_ID mean_ROE
<dbl> <fct> <dbl>
1 2016 1 0.0786
2 2016 2 0.107
3 2016 3 0.0771
4 2016 4 0.0723
5 2016 5 0.0908
6 2016 6 0.0812
7 2016 7 0.0555
8 2016 8 0.0874
9 2016 9 0.0863
10 2016 10 0.0646
# ℹ 40 more rows
# 年度ごとにROEの平均値を求め,折れ線グラフにより描画
financial_data %>%
drop_na(ROE) %>%
group_by(year) %>% # 年でグループ化
summarize(mean_ROE = mean(ROE)) %>% # 各年のROEの平均値を計算
ggplot() + # ggplot()関数にデータを引き渡す
geom_line(aes(x = year, y = mean_ROE)) +
# 折れ線グラフを描くにはgeom_line()関数を用いる
labs(x = "Year", y = "Mean ROE") + # 両軸のラベルを設定
theme_classic() # グラフ全体の体裁を設定Exercise 1
firm_IDが350の企業の売上高を折れ線グラフで表示せよ.ただし,\(y\)軸は売上高sales,\(x\)軸は年度year を取ることとする.Exercise 2
ROE_first_quintileという変数に保存せよ.
quantile()関数を用いる.この関数は第一引数にデータセット,第二引数に求めたい分位点の値をパーセントでなく小数表示で代入する.また,データセットに欠損値が含まれている場合,na.rm = TRUE を追加する必要がある.na.rmはremove NA values の略を意味する.ROE_first_quintileより小さい企業は何社あるか答えよ.ただし,ROEが欠損している企業はカウントしないこと.financial_dataをそのまま使用する.set.seed()関数の引数には,自分の学籍番号の末尾4桁の数字(末尾の英字を除く)を入力すること.# 全期間にわたってデータが揃っている企業を対象に絞る
target_firms <- financial_data %>%
count(firm_ID) %>%
filter(n == max(n)) %>%
pull(firm_ID)
# 自分の学籍番号の末尾4桁の数字を入力(例: 学籍番号が2001234Bの場合は1234)
set.seed(1234)
# 自分だけの分析条件を生成
my_firm <- sample(intersect(1:500, target_firms), 1) # 分析対象の企業ID
my_year <- sample(2015:2020, 1) # 分析対象の年度
my_n <- sample(3:8, 1) # 抽出する企業数
cat("対象企業:", my_firm, "\n")
cat("対象年度:", my_year, "\n")
cat("抽出企業数:", my_n, "\n")問題
financial_dataから,準備で生成したmy_year年度のデータのみをfilter()で抽出し,さらにselect()でfirm_ID,sales,Xの3列だけを表示せよ.パイプ演算子%>%を使って一連の処理として書くこと.head()で確認し,1行目のsalesの値を報告せよ.問題
financial_dataに対し,mutate()を使って以下の定義に従い売上高純利益率profit_marginを新しい列として追加せよ.ただし,\(i\)は企業,\(t\)は年度を表す.\[\text{profit\_margin}_{i,t} = \frac{X_{i,t}}{\text{sales}_{i,t}}\]my_firmの企業について,全年度のyear,sales,X,profit_marginを表示せよ.問題
financial_dataをyearでグループ化し,年度ごとのsalesの平均値を計算してmean_salesと名付けたデータフレームを作成せよ..groups = "drop"を忘れないこと.my_year年度のmean_salesの値を報告せよ.問題
financial_dataをfirm_IDでグループ化した上で,lag()を使って前年度の売上高lagged_salesを作成し,さらに以下の定義に従って売上高成長率sales_growthを計算せよ.ただし,\(i\)は企業,\(t\)は年度を表す.\[\text{sales\_growth}_{i,t} = \frac{\text{sales}_{i,t} - \text{sales}_{i,t-1}}{\text{sales}_{i,t-1}}\]lag()による欠損値をdrop_na(sales_growth)で除去した上で,my_firmの企業のyear,sales,sales_growthを表示し,売上高成長率が最も高かった年度を答えよ.(ヒント!)
group_by(firm_ID)を忘れずに.グループ化しないとlag()が異なる企業のデータを参照してしまう.group_by() → mutate() → drop_na() → filter() と繋げて書いてみよう.2025 経営データ分析(会計)