{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Rcpp入門 その2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "「オリジナルのR」、「RcppArmadillo」、「RcppEigen」で処理速度の比較をしてみたいと思います。\n", "\n", "「RcppArmadillo」、「RcppEigen」を使うのは、恐らく以下のような時だと思います。\n", "\n", "* forループを多用しなくてはいけない時\n", "* ライブラリ固有の関数を使いたい時\n", "\n", "[Rcpp入門](Rcpp_Getting_Started.ipynb)の関数を、1固定ではなく、行番号+列番号とした関数を作成して比較します。\n", "\n", "※ バージョンによっては正常に動作しない場合があります。私が試した環境は、\n", "\n", "* R version 3.4.1\n", "* Rcpp 0.12.12\n", "* RcppArmadillo 0.7.960.1.2\n", "* RcppEigen 0.3.3.3.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Rで作成した関数" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "PlusIJ_R <- function(src)\n", "{\n", " num_row <- nrow(src)\n", " num_col <- ncol(src)\n", " \n", " for(r in 1:num_row)\n", " {\n", " for(c in 1:num_col)\n", " {\n", " src[r, c] = src[r, c] + r + c\n", " }\n", " }\n", " \n", " return(src)\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## RcppArmadilloで作成した関数" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1] '0.12.12'" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "[1] '0.7.960.1.2'" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# パッケージの読込み\n", "library(Rcpp)\n", "library(RcppArmadillo)\n", "\n", "# パッケージのバージョンの確認\n", "packageVersion(\"Rcpp\")\n", "packageVersion(\"RcppArmadillo\")\n", "\n", "# C+11にてコンパイルします\n", "Sys.setenv(\"PKG_CXXFLAGS\"=\"-std=c++11\")" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# C++のコード\n", "code <- '\n", "arma::mat PlusIJ_Arma(arma::mat src)\n", "{\n", " int num_row = src.n_rows;\n", " int num_col = src.n_cols;\n", " \n", " for(int r = 0; r < num_row; r++)\n", " {\n", " for(int c = 0; c < num_col; c++)\n", " {\n", " src(r, c) = src(r, c) + r + 1 + c + 1;\n", " }\n", " }\n", "\n", " return src;\n", "}\n", "'\n", "\n", "# コンパイルとリンクを行います(少し時間がかかります)\n", "cppPlusIJ_Arma <- cppFunction(code, depends=\"RcppArmadillo\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## RcppEigenで作成した関数" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\n", "Attaching package: 'RcppEigen'\n", "\n", "The following objects are masked from 'package:RcppArmadillo':\n", "\n", " fastLm, fastLmPure\n", "\n" ] }, { "data": { "text/plain": [ "[1] '0.12.12'" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "[1] '0.3.3.3.0'" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# パッケージの読込み\n", "library(Rcpp)\n", "library(RcppEigen)\n", "\n", "# パッケージのバージョンの確認\n", "packageVersion(\"Rcpp\")\n", "packageVersion(\"RcppEigen\")\n", "\n", "# C+11にてコンパイルします\n", "Sys.setenv(\"PKG_CXXFLAGS\"=\"-std=c++11\")" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# C++のコード\n", "code <- '\n", "Eigen::MatrixXd PlusIJ_Eigen(Eigen::MatrixXd src)\n", "{\n", " int num_row = src.rows();\n", " int num_col = src.cols();\n", " \n", " for(int r = 0; r < num_row; r++)\n", " {\n", " for(int c = 0; c < num_col; c++)\n", " {\n", " src(r, c) = src(r, c) + r + 1 + c + 1;\n", " }\n", " }\n", "\n", " return src;\n", "}\n", "'\n", "\n", "# コンパイルとリンクを行います(少し時間がかかります)\n", "cppPlusIJ_Eigen <- cppFunction(code, depends=\"RcppEigen\", includes=c(\"#include \"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 比較" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "元データを作成します。" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "src <- matrix(1:100000000, nrow=10000)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Rで作成した関数**" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " user system elapsed \n", " 11.17 0.05 11.23 \n" ] } ], "source": [ "t <- proc.time()\n", "\n", "dst_r <- PlusIJ_R(src)\n", "\n", "print(proc.time() - t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**RcppArmadilloで作成した関数**" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " user system elapsed \n", " 1.92 0.48 2.40 \n" ] } ], "source": [ "t <- proc.time()\n", "\n", "dst_arma <- cppPlusIJ_Arma(src)\n", "\n", "print(proc.time() - t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**RcppEigenで作成した関数**" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " user system elapsed \n", " 1.82 0.51 2.34 \n" ] } ], "source": [ "t <- proc.time()\n", "\n", "dst_eigen <- cppPlusIJ_Eigen(src)\n", "\n", "print(proc.time() - t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**結果のチェック**" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1] \"RcppArmadilloで作成した関数チェック\"\n" ] }, { "data": { "text/html": [ "TRUE" ], "text/latex": [ "TRUE" ], "text/markdown": [ "TRUE" ], "text/plain": [ "[1] TRUE" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "[1] \"RcppEigenで作成した関数チェック\"\n" ] }, { "data": { "text/html": [ "TRUE" ], "text/latex": [ "TRUE" ], "text/markdown": [ "TRUE" ], "text/plain": [ "[1] TRUE" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "print(\"RcppArmadilloで作成した関数チェック\")\n", "all(dst_r == dst_arma)\n", "print(\"RcppEigenで作成した関数チェック\")\n", "all(dst_r == dst_eigen)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "今回の結果としては、以下の順位になりました。\n", "\n", "1. 「RcppArmadillo」 ≒ 「RcppEigen」\n", "1. 「オリジナルのR」\n", "\n", "forループを多用するコードになる場合は積極的に、「RcppArmadillo」や「RcppEigen」を使うべきだと思いました。\n", "\n", "「RcppArmadillo」と「RcppEigen」のどちらを利用するかは、悩みどころです。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----\n", "[ホームへ](https://waku-take-a.github.io/index.html) \n", "[↑Rの記事Topへ](https://waku-take-a.github.io/R.html) \n", "\n", "※ \n", "上記のipynbファイル等は、[こちらに](https://github.com/WAKU-TAKE-A/RTips)あります。 \n", "解凍後、`The jupyter notebook`にアップロードすれば、ローカルな環境で実行することも、編集することもできます。\n", "\n", "<(_ _)>" ] } ], "metadata": { "kernelspec": { "display_name": "R", "language": "R", "name": "ir" }, "language_info": { "codemirror_mode": "r", "file_extension": ".r", "mimetype": "text/x-r-source", "name": "R", "pygments_lexer": "r", "version": "3.4.4" } }, "nbformat": 4, "nbformat_minor": 2 }