Cóż, jest stary dobry. Użyj źródła, Luke! --- Sam R ma mnóstwo (bardzo wydajnych) kodów C, które można przestudiować, a CRAN ma setki pakietów, niektóre od autorów, którym ufasz. To dostarcza prawdziwych, sprawdzonych przykładów do przestudiowania i dostosowania.
Ale jak podejrzewał Josh, skłaniam się bardziej w stronę C ++, a tym samym Rcpp . Zawiera również wiele przykładów.
Edycja: były dwie książki, które okazały się pomocne:
- Pierwszym z nich jest " S Programming " Venablesa i Ripleya, mimo że jest już dość długi (a od lat krążą plotki o drugiej edycji). W tamtym czasie nie było po prostu nic innego.
- Drugi w „ Oprogramowaniu do analizy danych ” Chambersa, który jest znacznie nowszy i ma o wiele ładniejszy wygląd R-centryczny - i dwa rozdziały o rozszerzaniu R. Wspomniano o C i C ++. Poza tym John niszczy mnie za to, co zrobiłem z trawieniem, więc sam jest wart ceny wstępu.
To powiedziawszy, John coraz bardziej lubi Rcpp (i wnosi wkład), ponieważ uważa, że dopasowanie między obiektami R i obiektami C ++ (przez Rcpp ) jest bardzo naturalne - i pomaga w tym ReferenceClasses.
Edycja 2: Odnosząc się do pytania Hadleya, bardzo gorąco zachęcam do rozważenia C ++. Jest tyle schematycznych bzdur, że masz do czynienia z C - bardzo żmudne i łatwe do uniknięcia . Spójrz na winietę wprowadzającą Rcpp . Innym prostym przykładem jest ten post na blogu, w którym pokazuję, że zamiast martwić się o 10% różnic (w jednym z przykładów Radforda Neala), możemy uzyskać osiemdziesięciokrotny wzrost w C ++ (na co jest oczywiście wymyślonym przykładem).
Edycja 3: Jest złożoność polegająca na tym, że możesz napotkać błędy C ++, które są, delikatnie mówiąc, trudne do zrozumienia. Ale aby po prostu użyć Rcpp zamiast go rozszerzać, prawie nigdy nie powinieneś go potrzebować. I chociaż ten koszt jest niezaprzeczalny, jest on znacznie przyćmiony korzyścią wynikającą z prostszego kodu, mniej schematu, braku ochrony / ochrony, braku zarządzania pamięcią itp. Doug Bates wczoraj stwierdził, że uważa C ++ i Rcpp za znacznie bardziej podobne do pisania R niż pisanie w C ++. YMMV i tak dalej.
ggplot
?Hadley,
Zdecydowanie możesz napisać kod C ++, który jest podobny do kodu C.
Rozumiem, co mówisz, że C ++ jest bardziej skomplikowany niż C.To jest, jeśli chcesz opanować wszystko: obiekty, szablony, STL, metaprogramowanie szablonów itp. ... większość ludzi nie potrzebuje tych rzeczy i może po prostu polegać na innych do tego. Wdrożenie Rcpp jest bardzo skomplikowane, ale to, że nie wiesz, jak działa Twoja lodówka, nie oznacza, że nie możesz otworzyć drzwi i chwycić świeżego mleka ...
Z wielu twoich wkładów w R, uderza mnie to, że uważasz R za nieco nudne (manipulacja danymi, grafika, manipulowanie ciągami, itp ...). Przygotuj się na wiele innych niespodzianek dzięki wewnętrznemu C API R. Jest to bardzo żmudne.
Od czasu do czasu czytam instrukcje R-exts lub R-ints. To pomaga. Ale w większości przypadków, gdy naprawdę chcę się czegoś dowiedzieć, sięgam do źródeł R, a także do źródeł pakietów napisanych np. Przez Simona (zwykle jest tam wiele do nauczenia się).
Rcpp ma na celu wyeliminowanie tych żmudnych aspektów interfejsu API.
Możesz samodzielnie ocenić, co uważasz za bardziej skomplikowane, zaciemnione itp ... na podstawie kilku przykładów. Ta funkcja tworzy wektor znaków za pomocą C API:
Używając Rcpp, możesz napisać tę samą funkcję, co:
lub:
Jak powiedział Dirk, na kilku winietach są inne przykłady. Zwykle kierujemy również ludzi do naszych testów jednostkowych, ponieważ każdy z nich testuje bardzo określoną część kodu i nie wymaga wyjaśnień.
Jestem tutaj oczywiście stronniczy, ale poleciłbym zapoznać się z Rcpp zamiast uczyć się C API R, a następnie przejść do listy mailingowej, jeśli coś jest niejasne lub wydaje się nie do wykonania z Rcpp.
W każdym razie koniec prezentacji.
Myślę, że wszystko zależy od tego, jaki kod chcesz ostatecznie napisać.
Romain
źródło
@hadley: niestety nie mam na myśli konkretnych zasobów, które pomogłyby w rozpoczęciu pracy z C ++. Wziąłem to z książek Scotta Meyersa (Efektywny C ++, Bardziej efektywny C ++ itd.), Ale nie są to tak naprawdę to, co można nazwać wprowadzeniem.
Do wywoływania kodu w C ++ używamy prawie wyłącznie interfejsu .Call. Zasada jest dość prosta:
Więc funkcja .Call zostaje zadeklarowana w taki sposób w jakimś pliku nagłówkowym:
i zaimplementowano w ten sposób w pliku .cpp:
Niewiele więcej trzeba wiedzieć o R API używającym Rcpp.
Większość ludzi chce mieć do czynienia tylko z wektorami numerycznymi w Rcpp. Robisz to za pomocą klasy NumericVector. Istnieje kilka sposobów tworzenia wektorów numerycznych:
Z istniejącego obiektu, który przekazujesz z R:
Z podanymi wartościami za pomocą funkcji :: create static:
O podanym rozmiarze:
Kiedy już masz wektor, najbardziej użyteczną rzeczą jest wyodrębnienie z niego jednego elementu. Odbywa się to za pomocą operatora [], z indeksowaniem opartym na 0, więc na przykład sumowanie wartości wektora numerycznego wygląda mniej więcej tak:
Ale z cukrem Rcpp możemy teraz zrobić to znacznie przyjemniej:
Jak powiedziałem wcześniej, wszystko zależy od rodzaju kodu, który chcesz napisać. Zobacz, co ludzie robią w pakietach, które opierają się na Rcpp, sprawdź winiety, testy jednostkowe, wróć do nas na listę mailingową. Zawsze chętnie pomożemy.
źródło
@jbremnant: Zgadza się. Klasy Rcpp implementują coś zbliżonego do wzorca RAII. Podczas tworzenia obiektu Rcpp konstruktor podejmuje odpowiednie środki, aby zapewnić, że bazowy obiekt R (SEXP) jest chroniony przed modułem odśmiecania pamięci. Destruktor cofa ochronę. Jest to wyjaśnione w winiecie Rcpp-intrduction . Podstawowa implementacja opiera się na funkcjach R API R_PreserveObject i R_ReleaseObject
W rzeczywistości istnieje spadek wydajności z powodu hermetyzacji C ++. Staramy się ograniczyć to do minimum, stosując wstawianie itp. Kara jest niewielka, a jeśli weźmiesz pod uwagę zysk w zakresie czasu potrzebnego na napisanie i utrzymanie kodu, nie jest to aż tak istotne.
Wywoływanie funkcji R z klasy Rcpp Function jest wolniejsze niż bezpośrednie wywoływanie funkcji eval za pomocą interfejsu API języka C. Dzieje się tak, ponieważ podejmujemy środki ostrożności i opakowujemy wywołanie funkcji w blok tryCatch, aby przechwytywać błędy języka R i promować je do wyjątków C ++, aby można było je rozwiązać za pomocą standardowego try / catch w C ++.
Większość ludzi chce używać wektorów (szczególnie NumericVector), a kara jest bardzo mała w przypadku tej klasy. Katalog examples / ConvolveBenchmarks zawiera kilka wariantów słynnej funkcji splotu z R-exts, a winieta ma wyniki wzorcowe. Okazuje się, że Rcpp sprawia, że jest szybszy niż kod benchmarku korzystający z R API.
źródło