私は仕事でいくつかのコードをより速く実行することを任されており、並列計算で障害に遭遇しました。並行して実行したいオリジナルの for ループがあります。for ループを使用せずにコードを再現し、代わりに lapply() を使用するのが最も簡単に思えますが、これはループと同じくらい長く実行されます。parLapply() を使用してコードを書き直すと、lapply() と元の for ループの結果とは異なる結果になりますが、はるかに迅速な結果が得られます。どちらも同等です。このプログラムの目的は、各国の各満期レベルでのキャッシュ スプレッド (スプレッド カーブ) を計算することです。
「bonddata.csv」リンク: http://www.mediafire.com/download/hfcdbryhedpso77/bonddata.csv 「weocountries.csv」リンク: http://www.mediafire.com/download/7x15csw7lwwataj/weocountries.csv
必要なデータとライブラリの読み込み:
library(reshape2)
library(ggplot2)
library(Rblpapi)
library(xts)
library(YieldCurve)
library(parallel)
library(snow)
library(countrycode)
library(gridExtra)
library(compare)
#Read in the data
countries<-read.csv("weocountries.csv",stringsAsFactors=FALSE,na.strings="")
bonddata <- read.csv("bonddata.csv")
bonddata$iso <- as.character(bonddata$iso)
bonddata$maturity <- as.Date(as.character(bonddata$maturity))
rownames(bonddata) <- as.character(bonddata$X)
bonddata$X <- NULL
bonddata <- na.omit(bonddata)
キャッシュ スプレッドを計算する関数の作成:
calcspreadcurve<-function(data,maturities){
numbonds<-nrow(data)
if(numbonds<=3){
ForceIntercept<-.5*min(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*maturities)+ForceIntercept
return(fits)
}
else {
mod<-try(Nelson.Siegel(data$spread,12*data$averagelife),TRUE)
if(is.numeric(mod)){
fits<-as.vector(NSrates(xts(mod,Sys.Date()),12*maturities))
} else {
ForceIntercept<-.8*mean(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*maturities)+ForceIntercept
}
if(min(fits)<0){
ForceIntercept<-.8*mean(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*maturities)+ForceIntercept
}
if(mean(fits)>2*mean(data$spread)){
ForceIntercept<-.8*mean(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*maturities)+ForceIntercept
}
return(fits)
}
}
# Calculate standardized USD spread curves for all countries
bondcountries<-unique(bonddata$iso)
maturities<-c(1,2,5,10,20,30,50,100)
元のコード:
#Original for loop
cashspreads<-NULL
for(i in 1:length(bondcountries)){
curve<-calcspreadcurve(bonddata[bonddata$iso==bondcountries[i],],maturities)
cashspreads<-rbind(cashspreads,curve)
}
rownames(cashspreads)<-sapply(bondcountries,function(x) countries$ISO3[which(countries$ISO2==x)])
colnames(cashspreads)<-c("1Y","2Y","5Y","10Y","20Y","30Y","50Y","100Y")
lapply() コード:
#What loop is doing (lapply)
cashspreads2 <- t(as.data.frame(lapply(split(bonddata,bonddata$iso),function(data,m=maturities){
numbonds<-nrow(data)
if(numbonds<=3){
ForceIntercept<-.5*min(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*m)+ForceIntercept
return(fits)
}
else {
mod<-try(Nelson.Siegel(data$spread,12*data$averagelife),TRUE)
if(is.numeric(mod)){
fits<-as.vector(NSrates(xts(mod,Sys.Date()),12*m))
} else {
ForceIntercept<-.8*mean(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*m)+ForceIntercept
}
if(min(fits)<0){
ForceIntercept<-.8*mean(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*m)+ForceIntercept
}
if(mean(fits)>2*mean(data$spread)){
ForceIntercept<-.8*mean(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*m)+ForceIntercept
}
return(fits)
}
})))
rownames(cashspreads2)<-countrycode(rownames(cashspreads2),"iso2c","iso3c")
colnames(cashspreads2) <- c("1Y","2Y","5Y","10Y","20Y","30Y","50Y","100Y")
parLapply() コード:
#Run in parallel (parLapply)
cl <- makeCluster(type="SOCK",detectCores()-1)
cashspreads3 <- t(as.data.frame(parLapply(cl,split(bonddata,bonddata$iso),function(data,m=c(1,2,5,10,20,30,50,100)){
numbonds<-nrow(data)
if(numbonds<=3){
ForceIntercept<-.5*min(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*m)+ForceIntercept
return(fits)
}
else {
mod<-try(Nelson.Siegel(data$spread,12*data$averagelife),TRUE)
if(is.numeric(mod)){
fits<-as.vector(NSrates(xts(mod,Sys.Date()),12*m))
} else {
ForceIntercept<-.8*mean(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*m)+ForceIntercept
}
if(min(fits)<0){
ForceIntercept<-.8*mean(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*m)+ForceIntercept
}
if(mean(fits)>2*mean(data$spread)){
ForceIntercept<-.8*mean(data$spread)
mod<-lm(I(data$spread-ForceIntercept)~0+log(100*data$averagelife))
fits<-mod$coefficients*log(100*m)+ForceIntercept
}
return(fits)
}
})))
stopCluster(cl)
rownames(cashspreads3)<-countrycode(rownames(cashspreads3),"iso2c","iso3c")
colnames(cashspreads3) <- c("1Y","2Y","5Y","10Y","20Y","30Y","50Y","100Y")
データフレームの比較:
compare(cashspreads[order(rownames(cashspreads)),],cashspreads2[order(rownames(cashspreads2)),])
compare(cashspreads[order(rownames(cashspreads)),],cashspreads3[order(rownames(cashspreads3)),])
コードが適切に実行された場合、結果のデータフレーム "cashspreads" および "cashspreads2" は、データフレーム "cashspreads3" と比較できません。
これが同じデータフレームを生成しない理由について何か考えはありますか?