Kiedy podejmuję się projektu R o dowolnej złożoności, moje skrypty szybko stają się długie i mylące.
Jakie praktyki mogę zastosować, aby praca z moim kodem była zawsze przyjemna? Myślę o takich rzeczach jak
- Umieszczanie funkcji w plikach źródłowych
- Kiedy coś rozbić do innego pliku źródłowego
- Co powinno znajdować się w pliku głównym
- Używanie funkcji jako jednostek organizacyjnych (czy jest to warte zachodu, biorąc pod uwagę, że R utrudnia dostęp do stanu globalnego)
- Praktyki dotyczące wcięć / łamania linii.
- Treat (like {?
- Umieścić rzeczy takie jak)} w 1 lub 2 wierszach?
Zasadniczo, jakie są twoje praktyczne zasady organizowania dużych skryptów R?
r
package
conventions
code-organization
project-organization
Dan Goldstein
źródło
źródło
ProjectTemplate
pakiet.Odpowiedzi:
Standardową odpowiedzią jest użycie pakietów - zobacz podręcznik Writing R Extensions, a także różne samouczki w Internecie.
To daje Ci
R CMD check
Samo przejechanie
source()
kodu działa w przypadku naprawdę krótkich fragmentów. Wszystko inne powinno znajdować się w pakiecie - nawet jeśli nie planujesz go publikować, ponieważ możesz pisać wewnętrzne pakiety dla wewnętrznych repozytoriów.Jeśli chodzi o część „jak edytować”, podręcznik R Internals zawiera doskonałe standardy kodowania R w rozdziale 6. W przeciwnym razie zwykle używam wartości domyślnych w trybie ESS Emacsa .
Aktualizacja 2008-sierpień-13: David Smith właśnie napisał na blogu o przewodniku Google R. Style Guide .
źródło
Lubię umieszczać różne funkcje we własnych plikach.
Ale nie podoba mi się system pakietów R. Jest raczej trudny w użyciu.
Wolę lekką alternatywę, aby umieścić funkcje pliku w środowisku (co każdy inny język nazywa „przestrzenią nazw”) i dołączyć go. Na przykład utworzyłem grupę funkcji „util” w ten sposób:
To wszystko jest w pliku util.R . Kiedy je pozyskujesz, otrzymujesz środowisko „util”, dzięki czemu możesz dzwonić
util$bgrep()
i tak dalej; ale co więcej,attach()
wezwanie sprawia, że jest to sprawiedliwebgrep()
i takie działa bezpośrednio. Gdybyś nie umieścił wszystkich tych funkcji w ich własnym środowisku, zanieczyszczałyby przestrzeń nazw najwyższego poziomu interpretera (tę, która sięls()
wyświetla).Próbowałem zasymulować system Pythona, w którym każdy plik jest modułem. Byłoby lepiej, ale to wydaje się w porządku.
źródło
sys.source
:MyEnv <- attach(NULL, name=s_env); sys.source(file, MyEnv)
. Deklaruję nawet (w swoim własnym środowisku!) Podczas uruchamiania funkcję,sys.source2
która wyszuka, jeśli środowisko o tej samej nazwie już tu jest i podaje je zamiast tworzyć nowe. To sprawia, że dodawanie osobistych funkcji jest szybkie, łatwe i trochę zorganizowane :-)Może się to wydawać trochę oczywiste, zwłaszcza jeśli jesteś programistą, ale oto jak myślę o logicznych i fizycznych jednostkach kodu.
Nie wiem, czy tak jest w Twoim przypadku, ale kiedy pracuję w R, rzadko zaczynam od dużego złożonego programu. Zwykle zaczynam od jednego skryptu i rozdzielam kod na logicznie rozdzielone jednostki, często używając funkcji. Kod do manipulacji danymi i wizualizacji jest umieszczany w swoich własnych funkcjach itp. I takie funkcje są zgrupowane w jednej sekcji pliku (manipulacja danymi na górze, potem wizualizacja, itd.). Ostatecznie chcesz pomyśleć o tym, jak ułatwić sobie utrzymanie skryptu i obniżyć odsetek błędów.
Jak drobnoziarnisty / gruboziarnisty sprawisz, że Twoje funkcje będą się różnić i istnieją różne ogólne zasady: np. 15 linii kodu lub „funkcja powinna być odpowiedzialna za wykonanie jednego zadania, które jest identyfikowane przez jej nazwę”, itp. Twój przebieg będzie różny . Ponieważ R nie obsługuje wywołania przez referencję, zwykle jestem bardzo zróżnicowany, jeśli chodzi o zbyt drobnoziarniste działanie moich funkcji, gdy wymaga to przekazywania ramek danych lub podobnych struktur. Ale może to być nadmierna rekompensata za niektóre głupie błędy w wydajności, kiedy zaczynałem z R.
Kiedy wyodrębnić jednostki logiczne do ich własnych jednostek fizycznych (takich jak pliki źródłowe i większe grupy, takie jak pakiety)? Mam dwie sprawy. Po pierwsze, jeśli plik staje się zbyt duży i przewijanie między logicznie niepowiązanymi jednostkami jest irytujące. Po drugie, jeśli mam funkcje, które mogą być ponownie wykorzystane przez inne programy. Zwykle zaczynam od umieszczenia jakiejś zgrupowanej jednostki, powiedzmy funkcji manipulacji danymi, w oddzielnym pliku. Mogę następnie pobrać ten plik z dowolnego innego skryptu.
Jeśli zamierzasz wdrożyć swoje funkcje, musisz zacząć myśleć o pakietach. Nie wdrażam kodu R w środowisku produkcyjnym ani do ponownego wykorzystania przez innych z różnych powodów (pokrótce: kultura organizacji preferuje inne języki, obawy o wydajność, GPL itp.). Ponadto mam tendencję do ciągłego udoskonalania i dodawania do moich kolekcji plików źródłowych i wolałbym nie zajmować się pakietami, gdy wprowadzam zmianę. Więc powinieneś sprawdzić inne odpowiedzi dotyczące pakietu, takie jak Dirk, aby uzyskać więcej informacji na ten temat.
Wreszcie, myślę, że twoje pytanie niekoniecznie jest skierowane do R. Naprawdę poleciłbym przeczytanie Code Complete autorstwa Steve'a McConnella, który zawiera wiele mądrości na temat takich zagadnień i ogólnie praktyk kodowania.
źródło
Zgadzam się z radą Dirka! IMHO, organizowanie programów od prostych skryptów do udokumentowanych pakietów jest, dla programowania w języku R, jak przejście z programu Word na TeX / LaTeX do pisania. Polecam przyjrzeć się bardzo przydatnemu Tworzenie pakietów języka R: samouczek autorstwa Friedricha Leischa.
źródło
Moja zwięzła odpowiedź:
Uważam, że R jest coraz częściej używany w produkcji, więc zapotrzebowanie na kod wielokrotnego użytku jest większe niż wcześniej. Uważam, że tłumacz jest znacznie bardziej wytrzymały niż wcześniej. Nie ma wątpliwości, że R jest 100-300x wolniejsze niż C, ale zwykle wąskie gardło koncentruje się wokół kilku wierszy kodu, które można przekazać do C / C ++. Myślę, że byłoby błędem delegowanie mocnych stron języka R w manipulacji danymi i analizie statystycznej na inny język. W takich przypadkach spadek wydajności jest niski, a w każdym razie wart oszczędności wysiłku programistycznego. Gdyby liczył się sam czas wykonania, wszyscy pisalibyśmy w asemblerze.
źródło
Chciałem dowiedzieć się, jak pisać pakiety, ale nie zainwestowałem czasu. Dla każdego z moich mini-projektów przechowuję wszystkie funkcje niskiego poziomu w folderze o nazwie „functions /” i umieszczam je w oddzielnej przestrzeni nazw, którą jawnie tworzę.
Poniższe wiersze kodu utworzą środowisko o nazwie „myfuncs” w ścieżce wyszukiwania, jeśli jeszcze nie istnieje (za pomocą dołączania), i zapełnią je funkcjami zawartymi w plikach .r w moim katalogu „functions /” (używając sys.source). Zwykle umieszczam te wiersze na górze mojego głównego skryptu przeznaczonego dla „interfejsu użytkownika”, z którego wywoływane są funkcje wysokiego poziomu (wywołujące funkcje niskiego poziomu).
Kiedy wprowadzasz zmiany, zawsze możesz ponownie źródłować je z tymi samymi wierszami lub użyć czegoś podobnego
do oceny dodatków / modyfikacji w utworzonym środowisku.
Wiem, że to niezdarne, ale pozwala uniknąć zbyt formalnego podchodzenia do tego (ale jeśli będziesz miał okazję, zachęcam do korzystania z systemu pakietów - mam nadzieję, że będę migrować w ten sposób w przyszłości).
Jeśli chodzi o konwencje kodowania, to jedyna rzecz, jaką widziałem w odniesieniu do estetyki (lubię je i luźno podążam, ale nie używam zbyt wielu nawiasów klamrowych w R):
http://www1.maths.lth.se/help/R/RCC/
Istnieją inne „konwencje” dotyczące używania [, drop = FALSE] i <- jako operator przypisania sugerowany w różnych prezentacjach (zwykle w przemówieniu) w useR! konferencje, ale nie sądzę, aby żadna z nich była ścisła (chociaż [, drop = FALSE] jest przydatne w przypadku programów, w których nie jesteś pewien oczekiwanego wkładu).
źródło
Policz mnie jako osobę opowiadającą się za pakietami. Przyznam się, że jestem dość kiepski w pisaniu stron podręcznika i winiet, dopóki nie będę musiał (tj. Zostanę wydany), ale jest to naprawdę wygodny sposób na pakowanie kodu źródłowego. Dodatkowo, jeśli poważnie myślisz o utrzymaniu kodu, wszystkie punkty, które porusza Dirk, wchodzą w grę plya.
źródło
Również się zgadzam. Aby rozpocząć, użyj funkcji package.skeleton (). Nawet jeśli uważasz, że Twój kod może już nigdy nie zostać uruchomiony, może to zmotywować Cię do stworzenia bardziej ogólnego kodu, który pozwoli Ci zaoszczędzić czas później.
Jeśli chodzi o dostęp do globalnego środowiska, jest to łatwe z operatorem << -, chociaż jest to odradzane.
źródło
Ponieważ nie nauczyłem się jeszcze pisać pakietów, zawsze organizowałem je poprzez pozyskiwanie skryptów podrzędnych. Jest podobny do lekcji pisania, ale nie jest tak zaangażowany. Nie jest to programowo eleganckie, ale uważam, że gromadzę analizy w czasie. Kiedy już mam dużą działającą sekcję, często przenoszę ją do innego skryptu i po prostu ją umieszczam, ponieważ będzie ona używać obiektów obszaru roboczego. Być może muszę zaimportować dane z kilku źródeł, posortować je wszystkie i znaleźć skrzyżowania. Mógłbym umieścić tę sekcję w dodatkowym skrypcie. Jeśli jednak chcesz rozpowszechniać swoją „aplikację” dla innych osób lub używa ona interaktywnych danych wejściowych, pakiet jest prawdopodobnie dobrą trasą. Jako badacz rzadko muszę rozpowszechniać mój kod analizy, ale CZĘSTO muszę go ulepszać lub poprawiać.
źródło
Szukałem również świętego Graala odpowiedniego przepływu pracy do złożenia dużego projektu R. Znalazłem w zeszłym roku ten pakiet o nazwie rsuite i na pewno tego właśnie szukałem. Ten pakiet języka R został specjalnie opracowany do wdrażania dużych projektów języka R, ale odkryłem, że może być używany do projektów o mniejszym, średnim i dużym rozmiarze. Dam linki do rzeczywistych przykładów światowych w minutę (poniżej), ale najpierw chcę wyjaśnić nowy paradygmat budowania projektów R z
rsuite
.Uwaga. Nie jestem twórcą ani programistą
rsuite
.Z RStudio źle robiliśmy projekty; celem nie powinno być stworzenie projektu lub pakietu, ale szerszy zakres. Zamiast tego tworzysz super-projekt lub projekt główny, który zawiera standardowe projekty języka R i pakiety języka R we wszystkich możliwych kombinacjach.
Posiadając super-projekt R nie potrzebujesz już Uniksa
make
do zarządzania niższymi poziomami projektów R poniżej; używasz skryptów R na górze. Pokażę ci. Tworząc główny projekt oprogramowania rsuite, otrzymujesz następującą strukturę folderów:Folder
R
to miejsce, w którym umieszczasz skrypty zarządzania projektami, te, które zostaną zastąpionemake
.Folder
packages
to folder, w którymrsuite
znajdują się wszystkie pakiety składające się na super-projekt. Możesz także skopiować i wkleić pakiet, który nie jest dostępny z Internetu, a rsuite również go zbuduje.folder
deployment
, gdziersuite
będzie zapisywać wszystkie pliki binarne pakiety, które zostały wskazane w pakietachDESCRIPTION
plików. Zatem to sprawia, że projekcja jest całkowicie odtwarzalna w czasie.rsuite
zawiera klienta dla wszystkich systemów operacyjnych. Przetestowałem je wszystkie. Ale możesz także zainstalować go jakoaddin
dla RStudio.rsuite
umożliwia także tworzenie izolowanejconda
instalacji w swoim własnym folderzeconda
. To nie jest środowisko, ale fizyczna instalacja Pythona pochodząca z programu Anaconda na twoim komputerze. Działa to razem z RSystemRequirements
, z których możesz zainstalować wszystkie pakiety Pythona, które chcesz, z dowolnego kanału Conda.Możesz także tworzyć lokalne repozytoria, aby pobierać pakiety R, gdy jesteś w trybie offline lub chcesz zbudować całość szybciej.
Jeśli chcesz, możesz również skompilować projekt R jako plik zip i udostępnić go współpracownikom. Będzie działać, pod warunkiem, że Twoi koledzy mają zainstalowaną tę samą wersję R.
Inną opcją jest zbudowanie kontenera całego projektu w systemie Ubuntu, Debian lub CentOS. Dlatego zamiast udostępniać plik zip z kompilacją projektu, udostępniasz cały
Docker
kontener z projektem gotowym do uruchomienia.Dużo eksperymentowałem,
rsuite
szukając pełnej odtwarzalności i unikając zależności pakietów, które instaluje się w środowisku globalnym. Jest to błędne, ponieważ gdy tylko zainstalujesz aktualizację pakietu, projekt najczęściej przestaje działać, szczególnie te pakiety z bardzo określonymi wywołaniami funkcji z określonymi parametrami.Pierwszą rzeczą, którą zacząłem eksperymentować, były
bookdown
ebooki. Nigdy nie miałem tyle szczęścia, że udało mi się przetrwać próbę czasu dłuższą niż sześć miesięcy. Tak więc przekonwertowałem oryginalny projekt bookdown na zgodny zrsuite
ramami. Teraz nie muszę się martwić aktualizacją mojego globalnego środowiska R, ponieważ projekt ma własny zestaw pakietów wdeployment
folderze.Następną rzeczą, jaką zrobiłem, było tworzenie projektów uczenia maszynowego, ale
rsuite
przeszkadzało. Główny, aranżacyjny projekt u góry, a wszystkie podprojekty i pakiety mają być pod kontrolą głównego. Naprawdę zmienia sposób programowania w R, zwiększając produktywność.Potem zacząłem pracować w nowej paczce o nazwie
rTorch
. Było to możliwe w dużej mierze dziękirsuite
; pozwala myśleć i osiągać sukcesy.Jedna rada. Nauka
rsuite
nie jest łatwa. Ponieważ przedstawia nowy sposób tworzenia projektów R, wydaje się trudne. Nie przejmuj się pierwszymi próbami, kontynuuj wspinaczkę po zboczu, aż się uda. Wymaga zaawansowanej wiedzy o systemie operacyjnym i systemie plików.Spodziewam się, że pewnego dnia
RStudio
będziemy mogli generować projekty aranżacyjne, takie jakrsuite
z menu. Byłoby świetnie.Spinki do mankietów:
Repozytorium RSuite GitHUb
r4ds bookdown
keras i błyszczący tutorial
moderndive-book-rsuite
interpretable_ml-rsuite
IntroMachineLearningWithR-rsuite
clark-intro_ml-rsuite
hyndman-bookdown-rsuite
statystyczne_rethinking-rsuite
fread-benchmarks-rsuite
dataviz-rsuite
samouczek-segmentacji-handlu-h2o
telco-customer-churn-tutorial
sclerotinia_rsuite
źródło
R jest OK do użytku interaktywnego i małych skryptów, ale nie użyłbym go do dużego programu. Używałbym głównego języka do większości programowania i opakowałbym go w interfejs R.
źródło
Rcpp
pakietu, w tym kodu C ++ w programach języka R, staje się dość proste. Zatem przepisanie pewnych fragmentów kodu R może zostać łatwo zintegrowane z R. Ponadto wraz z pojawieniem się RStudio wprowadzono IDE dla języka R, choć może nie tak potężne jak Visual Studio.