0. はじめに

このページはKAKENHIデータベースからダウンロードできるCSVファイルの「研究代表者」列から以下の情報を抽出する方法を紹介していきます。


- 研究者番号の取得
- 研究者の職名の取得
- 所属部局の取得


1. 下準備

必要なパッケージとデータは以下の通りです。今回は2019年度の全採択課題を用います(kaken_2019_20191201.csv)。

# パッケージの読み込み
library(data.table)   # 高速なデータインポートのため
library(dplyr)        # データの整理のため
library(DT)           # 集計表の出力のため
library(stringr)      # 文字列操作のため

# インストールされていない場合は、以下のコマンドの「#」を外して実行
# install.packages("data.table")
# install.packages("dplyr")
# install.packages("DT")
# install.packages("stringr")


# 使用するデータのインポート
d <- fread("kaken_2019_20191201.csv")


2. パターンの確認

まず、研究代表者列に入っているデータのパターンを確認しておきます。個人情報満載なのでサイト上ではコードを実行しませんが、概ね、以下のようなパターンでデータが格納されているのではないかと思われます。


「苗字 名前 所属機関, 所属部局, 職名 (研究者番号)」


d %>% select("研究代表者")  %>%
  datatable()


3. 研究者番号の抽出

研究者番号のパターンは「数字8桁」であり、これを正規表現で表すと「\\d{8}」になります。以下のコードではstr_extract関数により、研究代表者列からこのパターンを抽出しています。なお、研究者番号保有者に限定するため、研究種目から「奨励研究」を除外し、また、研究代表者列が空白でないデータのみを対象にしています。

d %>% 
  
  # 奨励研究を削除
  filter(研究種目 == "奨励研究") %>%  
  
  # 研究代表者の列のみ抽出
  select(研究代表者) %>%
  
  # 研究代表者が空白でない行だけ抽出
  filter(!(研究代表者 == "")) %>%
  
  # 研究代表者列から8桁の数字を抽出し、Res.ID列に格納
  mutate(Res.ID = str_extract(研究代表者, "\\d{8}")) %>%
  
  datatable()


4. 職名の抽出

次に、研究者の職名を抽出します。研究代表者列は「苗字 名前 所属機関, 所属部局, 職名 (研究者番号)」の形式でデータが入っているので、「最後のコンマの直後から「(」の直前まで」が職名を表していると考えられます。この部分を一気に取り出すのは難しいので、以下の2段階に分けて職名を抽出します。


1. 最後のコンマの直後から末尾までの文字列を取得
2. 「(研究者番号)」の削除

なお、1段階目の処理については、全体を「先頭から最後のコンマまで」のパートとそれ以降のパートに分割し、str_replace関数を用いて2つ目のパートで上書きするような処理を行なっています。

d %>% 
  filter(研究種目 != "奨励研究") %>%  
  select(研究代表者) %>%
  filter(!(研究代表者 == "")) %>%
  
  # 最後のコンマ直後の文字列から末尾までを取得
  mutate(職名 = str_replace(研究代表者, "(^.+,)(.+$)", "\\2")) %>%
  
  # 「(研究者番号)」の削除
  mutate(職名 = str_replace(職名, "\\(\\d{8}\\)", "")) %>%
  
  # 前後の空白を削除
  mutate(職名 = str_trim(職名, side = "both")) %>%
  
  # 職名の列のみ選択
  select(職名) %>%
  
 # 可視化
  datatable()


5. 所属部局の抽出

最後に、所属部局を抽出します。所属部局は2つのコンマに挟まれた部分の文字列が該当し、正規表現を用いると「(?<=,).+(?=,)」となります。以下のコードでは、str_extract関数を用いてこの正規表現にマッチする文字列を抽出しています。

d %>% 
  filter(研究種目 != "奨励研究") %>%  
  select(研究代表者) %>%
  filter(!(研究代表者 == "")) %>%
  
  # 「最後のコンマの直後から末尾まで」の文字列を取得
  mutate(所属部局 = str_extract(研究代表者, "(?<=,).+(?=,)")) %>%
  
  # 前後の空白を削除
  mutate(所属部局 = str_trim(所属部局, side = "both")) %>%
  
 # 可視化
  datatable()


6. 例外処理

職名と所属部局の抽出の例では、研究代表者列にはコンマが2つ含まれていることを前提とし、コンマの位置を手掛かりに抽出を行なってきました。この前提は正しかったのでしょうか。以下のコードでは研究代表者列の各値に含まれるコンマの数を取得し、コンマの数ごとに何行のデータがあるのかを集計しています。

d %>% 
  filter(研究種目 != "奨励研究") %>%  
  select(研究代表者) %>%
  filter(!(研究代表者 == "")) %>%
  
  # 研究代表者に含まれるコンマの数をN_comma列に格納
  mutate(N_comma = str_count(研究代表者, ",")) %>%
  
  # コンマの数によってデータのグループ化
  group_by(N_comma) %>%
  
  # 各グループの行数を集計
  summarize(N = n()) %>%
  
 # 可視化
  datatable()

残念ながら今まで対象としてきたデータにはコンマが1つしかないデータが存在しているようです。これらのデータについては上記で紹介してきた方法は適用できませんので、例外処理を行います。以下のコードは所属部局を取得するコードを改変したものです。あらかじめ研究代表者列に含まれるコンマの数を取得しておき、コンマの数が2の場合は上記の処理を、それ以外の場合は「NA」を格納しています。


d %>% 
  filter(研究種目 != "奨励研究") %>%  
  select(研究代表者) %>%
  filter(!(研究代表者 == "")) %>%
  
  # 研究代表者に含まれるコンマの数をN_comma列に格納
  mutate(N_comma = str_count(研究代表者, ",")) %>%

  # コンマの数が2つの時には「最後のコンマ直後から末尾まで」の文字列を取得、それ以外は「NA」
  mutate(所属部局 = ifelse(N_comma == 2, str_extract(研究代表者, "(?<=,).+(?=,)"), NA)) %>%
  
  # 前後の空白を削除
  mutate(所属部局 = str_trim(所属部局, side = "both")) %>%
  
 # 可視化
  datatable()