ミクロデータへのマクロデータへの紐付けはデータ分析では良くある作業です。例えば企業の財務データを、その年のインフレ率で割り引く作業があります。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")]