読者です 読者をやめる 読者になる 読者になる

餡子付゛録゛

ソフトウェア開発ツールの便利な使い方を紹介。

Rでミクロデータにマクロデータを紐付ける

R言語

ミクロデータへのマクロデータへの紐付けはデータ分析では良くある作業です。例えば企業の財務データを、その年のインフレ率で割り引く作業があります。Rの演算は各年各企業のデータにインフレ率が無いと演算しにくいので、Excelのvlookup関数で紐付けを済ましている人が多いと思いますが、企業データとインフレ率のデータが別ファイルになっている場合の、Rでの紐付けにトライしてみましょう。

1. データセットのロード

dataset.txtに財務データ、cpi.txtにインフレ率のデータが入っているとします。dataset.txtは、以下のようになっています。

Year Country NAME Y X
2008 JP A社 10 5
2009 JP A社 9 6
2010 JP A社 11 4
2008 JP B社 11 5
2009 JP B社 8 6
2010 JP B社 12 4

cpi.txtは、以下のようになっています。

Year CPI
2008 101.70
2009 100.00
2010 99.60

まずは、データ・ファイルをロードします。

ds <- read.table("dataset.txt", header=TRUE, sep="\t")
cpi <- read.table("cpi.txt", header=TRUE, sep="\t")

データフレームdsとcpiにデータが読み込まれました。

2. 紐付けコード(キーが一つ)

まずは遅い方法ですが、確実な方法です。

CPIs <- c()
for(i in 1:length(ds$Year)){
  CPIs <- c(r, subset(cpi, Year==ds$Year[i])$CPI[1])
}

CPIsが企業データに対応する、同じ長さのインフレ率の集合になります。
サンプル数が1,000ぐらいで、ひっかかるような感じがすると思います。データフレームから毎回抽出しているからです。
リストを用いた以下のコードは、高速に動作します。ただし、CPIデータ側に欠損値があるとデータの長さが合わなくなるので注意が必要です。

h <- as.list(NA)
for(i in 1:length(cpi$Year)){
  key <- cpi$Year[i]
  value <- cpi$CPI[i]
  h[key] <- value
}
CPIs <- as.numeric(unlist(h[ds$Year]))

リスト構造のままでは演算ができないので、unlistされている事に注意してください。
なお実際の調整は、CPIが100倍された指数である事に注意して以下のようになります。

ds$Y <- ds$Y*CPIs/100
ds$X <- ds$X*CPIs/100

3. 紐付けコード(キーが二つ)

クロスカントリー・データを扱う場合、インフレ率が国ごとに違う事になります。こういう場合は、紐付けするキーが二つになります。

CPIs <- c()
for(i in 1:length(ds$Year)){
  CPIs <- c(r, subset(cpi, Year==ds$Year[i] & Country==as.character(ds$Country[i]))$CPI[1])
}

as.character関数を省略すると型があわなくなるので注意が必要です。
高速版は以下のようになります。入れ籠構造のリストの処理は煩雑なので、paste関数を使って紐付けするキーを一つにしています。

h <- as.list(NA)
for(i in 1:length(cpi$Year)){
  key <- paste(cpi$Country[i], cpi$Year[i])
  value <- cpi$CPI[i]
  h[key] <- value
}
CPIs <- as.numeric(unlist(h[paste(ds$Country, ds$Year)]))

4. もっと手抜きをしたい人へ

ループを使いたく無い場合は、以下のようにしても結合できます。

df <- merge(df, cpi, by=c("Year", "ID"), suffixes=c("",".cpi"))

以下はmergeはベクターをby引数に取れないと思っていたときのコードです。コメントで御指摘頂き気づきました。

tc <- "ID_FOR_JOIN"
df[tc] <- paste(df$Year, df$ID)
cpi[tc] <- paste(cpi$Year, cpi$ID)
df <- merge(df, cpi, by=tc, suffixes=c("",".cpi"))
df <- df[setdiff(colnames(df), tc)]

Year.cpiとID.cpi列が気に入らない場合は、以下のように消すこともできます。

df <- df[setdiff(colnames(df), "Year.cpi")]
df <- df[setdiff(colnames(df), "ID.cpi")]

5. Excelのvlookup関数でも同じ

自己否定的な言及になりますが、Excelのvlookup関数でも効果は同じなので、Rで処理する必要はありません。ただし、慣れてしまうとRで統合的にデータ加工ができるので、方法としては知っておいても良いと思います。