Slovník | Vyhledávání | Mapa webu
 
Základy informatiky pro biologyAnalýza dat v R Propojení C a R C++ funkce v R

Logo Matematická biologie

C++ funkce v R

Pro urychlení výpočtu v R je přeprogramování důležitých částí kódu do C ++ jednodušší než do C. Balík Rcpp ulehčuje propojení C++ a R. Kromě bezpečnejší práce s pamětí poskytuje širokou paletu datových typů využívaných v R např. různe typy matic a vektorů nebo obecný typ seznam.

Na přeprogramování do C ++ jsou zvláště vhodné:

  • Cykly, v nichž pozdější iterace závisí na předešlých
  • Rekurzívní výpočty
  • Výpočty využívající známé C++ implementace

Ukážeme si teď jak propojit C++ a R. Začneme načtením balíku Rcpp

> library(Rcpp)

Propojení budeme demonstrovat na příkladu jednoduché funkce add(), která vrací součet tří čísel. V jazyku C++ funkce vypadá takhle:

int add(int x, int y, int z){

int sum = x + y + z;

return(sum);

}

Způsob propojení 1:

Jako první způsob propojení C++ a R použijeme funkcii cppFunction(), kterou přímo zadávame v jazyku C++. Argumentem funkce je kód funkce napsané v jazyku C++, tedy jednoduše výše uvedený kód v uvozovkách:

> cppFunction('int add(int x, int y, int z){

int sum = x + y + z;

return(sum);

}')


V prostředí R tak byl vytvořen objekt add, který je funkcí:

add

function (x, y, z)
.Primitive(".Call")(<pointer: 0x00000000658c1770>, x, y, z)

S tímhle objektem můžeme tedy pracovat jako s jinými funkcemi R. Např:

add(1,2,3)

[1] 6

Způsob propojení 2:

Druhým způsobem je použití funkce sourceCpp(). Tahle funkce načte kód funkce z externího souboru. V textovém editoru vytvoříme soubor add.cpp, ve kterém definujeme funkci add. Soubor musí obsahovat řádky:

#include <Rcpp.h> 

using namespace Rcpp; 

// [[Rcpp::export]] 

První dva řádky přípojí definice balíku Rcpp. Třetí řádek (// [[Rcpp::export]]) označí funkci na export. Protože je možné v jednom souboru definovat více funkcí, je potřebné tenhle příkaz uvést před každou, kterou chceme exportovat do R (funkce bude pak z R přímo přístupná). Pak následuje defince funkce. Pro rozlišení od předchozího příkladu je funkce nazvaná addCpp, její obsah však zůstává stejný:

int addCpp(int x, int y, int z){

int sum = x + y + z;

return(sum);

}

Soubor pak uložíme do pracovního adresáře R a načteme pomocí funkce sourceCpp():

> sourceCpp("add.cpp")

a dále zavoláme již jako funkci R z názvem addCpp():

addCpp(1,2,3)

[1] 6

Teď si ukážeme jak se výpočet zrychlí použitím implementace funkce v jazyku C++. Nejdřív v C++ vytvoříme funkci meanCpp pro výpočet průměru a načteme ji do R první metodou (tedy s pomocí funkce cppFunction()):

> cppFunction('double meanCpp(NumericVector x){ 
int n = x.size(); 
double total = 0; 
for(int i = 0; i < n; ++i) { 
  total += x[i]; 

return total / n; 
}')

Pro porovnání rychlosti funkce pro průměr napsané v C++ (meanCpp) a základní funkce R (mean) použijeme microbenchmark()z knihovny microbenchmark:

library(microbenchmark) 

Vytvoříme vektor náhodných čísel:
x <- rnorm(1e5)

a porovnáme rychlost obou funkcí:
microbenchmark(mean(x), meanCpp(x))

Unit: microseconds
       expr     min      lq      mean  median       uq     max neval
    mean(x) 184.736 185.877 199.24535 187.017 202.4115 415.466   100
 meanCpp(x)  89.709  90.848  95.34892  91.609  96.1700 150.906   100

Ve výstupu vidíme, že výpočet pomoci funkce meanCpp trva v průměru 95 mikrosekund, zatímco funkce mean z R potřebuje pro stejný výpočet přibližně dvojnásobek času (199 mikrosekund).

 
vytvořil Institut biostatistiky a analýz Lékařské fakulty Masarykovy univerzity