Lorsque j'entreprends un projet R de toute complexité, mes scripts deviennent rapidement longs et déroutants.
Quelles pratiques puis-je adopter pour que mon code soit toujours un plaisir de travailler? Je pense à des choses comme
- Placement des fonctions dans les fichiers source
- Quand diviser quelque chose dans un autre fichier source
- Que doit contenir le fichier maître
- Utiliser des fonctions comme unités organisationnelles (si cela en vaut la peine étant donné que R rend difficile l'accès à l'état global)
- Pratiques d'indentation / saut de ligne.
- Traiter (comme {?
- Mettez des choses comme)} sur 1 ou 2 lignes?
En gros, quelles sont vos règles empiriques pour organiser de gros scripts R?
r
package
conventions
code-organization
project-organization
Dan Goldstein
la source
la source
ProjectTemplate
package.Réponses:
La réponse standard est d'utiliser des packages - voir le manuel Writing R Extensions ainsi que différents didacticiels sur le Web.
Ça te donne
R CMD check
Le simple fait d'exécuter du
source()
code fonctionne pour des extraits de code très courts. Tout le reste doit être dans un package - même si vous ne prévoyez pas de le publier car vous pouvez écrire des packages internes pour les référentiels internes.En ce qui concerne la partie «comment éditer», le manuel de R Internals a d'excellents standards de codage R dans la section 6. Sinon, j'ai tendance à utiliser les valeurs par défaut en mode ESS d'Emacs .
Mise à jour 2008-Août-13: David Smith vient blogué sur le Google R Guide de style .
la source
J'aime mettre différentes fonctionnalités dans leurs propres fichiers.
Mais je n'aime pas le système de paquets de R. C'est assez difficile à utiliser.
Je préfère une alternative légère, pour placer les fonctions d'un fichier dans un environnement (ce que toutes les autres langues appellent un «espace de noms») et l'attacher. Par exemple, j'ai créé un groupe de fonctions 'util' comme ceci:
Tout cela est dans un fichier util.R . Lorsque vous le sourcez, vous obtenez l'environnement «util» afin que vous puissiez appeler
util$bgrep()
et autres; mais de plus, l'attach()
appel le rend si justebgrep()
et un tel travail directement. Si vous ne mettez pas toutes ces fonctions dans leur propre environnement, elles pollueraient l'espace de noms de premier niveau de l'interpréteur (celui quils()
s'affiche).J'essayais de simuler le système de Python, où chaque fichier est un module. Ce serait mieux d'avoir, mais cela semble correct.
la source
sys.source
:MyEnv <- attach(NULL, name=s_env); sys.source(file, MyEnv)
. Je déclare même (dans son propre environnement!) Au démarrage une fonctionsys.source2
qui cherchera si un environnement du même nom est déjà là et alimente celui-ci au lieu d'en créer un nouveau. Cela rend l'ajout de fonctions personnelles rapide, facile et assez organisé :-)Cela peut sembler un peu évident, surtout si vous êtes un programmeur, mais voici comment je pense aux unités logiques et physiques de code.
Je ne sais pas si c'est votre cas, mais quand je travaille en R, je commence rarement avec un grand programme complexe en tête. Je commence généralement par un script et je sépare le code en unités logiquement séparables, souvent en utilisant des fonctions. La manipulation des données et le code de visualisation sont placés dans leurs propres fonctions, etc. Et ces fonctions sont regroupées dans une section du fichier (manipulation des données en haut, puis visualisation, etc.). En fin de compte, vous voulez réfléchir à la manière de faciliter la maintenance de votre script et de réduire le taux de défauts.
Le niveau de grain fin / grossier de vos fonctions variera et il existe diverses règles empiriques: par exemple, 15 lignes de code, ou "une fonction doit être chargée d'effectuer une tâche identifiée par son nom", etc. Votre kilométrage variera . Étant donné que R ne prend pas en charge l'appel par référence, je suis généralement différent de rendre mes fonctions trop fines lorsqu'il s'agit de passer des trames de données ou des structures similaires. Mais cela peut être une surcompensation pour certaines erreurs de performance stupides lorsque j'ai commencé avec R.
Quand extraire les unités logiques dans leurs propres unités physiques (comme les fichiers source et les groupes plus importants comme les packages)? J'ai deux cas. Premièrement, si le fichier devient trop volumineux et que le défilement parmi des unités logiquement non liées est une gêne. Deuxièmement, si j'ai des fonctions qui peuvent être réutilisées par d'autres programmes. Je commence généralement par placer une unité groupée, disons des fonctions de manipulation de données, dans un fichier séparé. Je peux ensuite me procurer ce fichier à partir de n'importe quel autre script.
Si vous allez déployer vos fonctions, vous devez commencer à penser aux packages. Je ne déploie pas de code R en production ou pour une réutilisation par d'autres pour diverses raisons (brièvement: la culture de l'organisation préfère d'autres langages, des préoccupations concernant les performances, la GPL, etc.). De plus, j'ai tendance à constamment affiner et ajouter à mes collections de fichiers source, et je préfère ne pas traiter les packages lorsque j'apporte un changement. Vous devriez donc consulter les autres réponses liées aux packages, comme celles de Dirk, pour plus de détails à ce sujet.
Enfin, je pense que votre question n'est pas nécessairement particulière à R. Je recommanderais vraiment de lire Code Complete de Steve McConnell qui contient beaucoup de sagesse sur ces problèmes et les pratiques de codage en général.
la source
Je suis d'accord avec les conseils de Dirk! À mon humble avis, organiser vos programmes depuis de simples scripts jusqu'aux packages documentés est, pour la programmation en R, comme passer de Word à TeX / LaTeX pour l'écriture. Je recommande de jeter un œil au très utile Créer des packages R: un tutoriel de Friedrich Leisch.
la source
Ma réponse concise:
Je pense que R est de plus en plus utilisé en production, donc le besoin de code réutilisable est plus grand qu'auparavant. Je trouve l'interprète beaucoup plus robuste qu'avant. Il ne fait aucun doute que R est 100-300x plus lent que C, mais généralement le goulot d'étranglement est concentré autour de quelques lignes de code, qui peuvent être déléguées à C / C ++. Je pense que ce serait une erreur de déléguer les forces de R dans la manipulation des données et l'analyse statistique à un autre langage. Dans ces cas, la pénalité de performance est faible et, en tout cas, vaut largement les économies réalisées sur les efforts de développement. Si le temps d'exécution seul était le problème, nous serions tous assembleurs d'écriture.
la source
J'avais l'intention de comprendre comment écrire des paquets mais je n'ai pas investi de temps. Pour chacun de mes mini-projets, je garde toutes mes fonctions de bas niveau dans un dossier appelé «functions /», et je les source dans un espace de noms séparé que je crée explicitement.
Les lignes de code suivantes créeront un environnement nommé "myfuncs" sur le chemin de recherche s'il n'existe pas déjà (en utilisant attach), et le rempliront avec les fonctions contenues dans les fichiers .r dans mon répertoire 'functions /' (en utilisant sys.source). Je mets généralement ces lignes en haut de mon script principal destiné à "l'interface utilisateur" à partir de laquelle les fonctions de haut niveau (invoquant les fonctions de bas niveau) sont appelées.
Lorsque vous apportez des modifications, vous pouvez toujours le ressourcer avec les mêmes lignes, ou utiliser quelque chose comme
pour évaluer les ajouts / modifications dans l'environnement que vous avez créé.
C'est kludgey je sais, mais évite d'avoir à être trop formel à ce sujet (mais si vous en avez l'occasion, j'encourage le système de paquets - j'espère que je migrerai de cette façon à l'avenir).
En ce qui concerne les conventions de codage, c'est la seule chose que j'ai vue concernant l'esthétique (je les aime et je les suis vaguement mais je n'utilise pas trop d'accolades dans R):
http://www1.maths.lth.se/help/R/RCC/
Il existe d'autres "conventions" concernant l'utilisation de [, drop = FALSE] et <- comme opérateur d'affectation suggéré dans diverses présentations (généralement keynote) à useR! conférences, mais je ne pense pas qu’aucune d’entre elles soit stricte (bien que [, drop = FALSE] soit utile pour les programmes dans lesquels vous n’êtes pas sûr de l’entrée que vous attendez).
la source
Comptez-moi comme une autre personne en faveur des colis. J'admets être assez médiocre sur l'écriture de pages de manuel et de vignettes jusqu'à ce que je le doive (c'est-à-dire être publié), mais c'est un moyen très pratique de regrouper les sources. De plus, si vous prenez au sérieux la maintenance de votre code, les points soulevés par Dirk entrent tous en jeu.
la source
Je suis également d’accord. Utilisez la fonction package.skeleton () pour commencer. Même si vous pensez que votre code ne sera peut-être plus jamais exécuté, cela peut vous motiver à créer un code plus général qui pourrait vous faire gagner du temps plus tard.
Quant à accéder à l'environnement global, c'est facile avec l'opérateur << -, bien que déconseillé.
la source
N'ayant pas encore appris à écrire des packages, je me suis toujours organisé en sourcing de sous-scripts. C'est similaire aux classes d'écriture mais pas aussi impliquées. Ce n'est pas un programme élégant mais je trouve que je construis des analyses au fil du temps. Une fois que j'ai une grande section qui fonctionne, je la déplace souvent vers un script différent et je la recherche simplement car elle utilisera les objets de l'espace de travail. Peut-être ai-je besoin d'importer des données de plusieurs sources, de les trier toutes et de trouver les intersections. Je pourrais mettre cette section dans un script supplémentaire. Cependant, si vous souhaitez distribuer votre «application» à d'autres personnes, ou si elle utilise une entrée interactive, un package est probablement une bonne voie. En tant que chercheur, j'ai rarement besoin de distribuer mon code d'analyse mais j'ai SOUVENT besoin de l'augmenter ou de le peaufiner.
la source
J'ai également cherché le Saint Graal du bon flux de travail pour monter un grand projet R. J'ai trouvé l'année dernière ce package appelé rsuite , et c'était certainement ce que je cherchais. Ce package R a été explicitement développé pour le déploiement de grands projets R, mais j'ai trouvé qu'il pouvait être utilisé pour des projets R de petite, moyenne et grande taille. Je vais donner des liens vers des exemples du monde réel dans une minute (ci-dessous), mais je veux d'abord expliquer le nouveau paradigme de la construction de projets R avec
rsuite
.Remarque. Je ne suis ni le créateur ni le développeur de
rsuite
.Nous avons mal fait des projets avec RStudio; l'objectif ne doit pas être la création d'un projet ou d'un package mais d'une plus grande portée. Dans rsuite, vous créez un super-projet ou un projet maître, qui contient les projets R standard et les packages R, dans toutes les combinaisons possibles.
En ayant un super-projet R, vous n'avez plus besoin d'Unix
make
pour gérer les niveaux inférieurs des projets R en dessous; vous utilisez des scripts R en haut. Laisse moi te montrer. Lorsque vous créez un projet maître rsuite, vous obtenez cette structure de dossiers:Le dossier
R
est l'endroit où vous placez vos scripts de gestion de projet, ceux qui les remplacerontmake
.Le dossier
packages
est le dossierrsuite
contenant tous les packages qui composent le super-projet. Vous pouvez également copier-coller un package qui n'est pas accessible depuis Internet, et rsuite le construira également.le dossier
deployment
est l'endroit oùrsuite
écriront tous les binaires de package qui ont été indiqués dans lesDESCRIPTION
fichiers de packages . Ainsi, cela rend, en soi, vous projetez totalement reproductible dans le temps.rsuite
est livré avec un client pour tous les systèmes d'exploitation. Je les ai tous testés. Mais vous pouvez également l'installer en tant queaddin
pour RStudio.rsuite
vous permet également de créer uneconda
installation isolée dans son propre dossierconda
. Ce n'est pas un environnement mais une installation physique Python dérivée d'Anaconda dans votre machine. Cela fonctionne avec les RSystemRequirements
, à partir desquels vous pouvez installer tous les packages Python de votre choix, à partir de n'importe quel canal conda de votre choix.Vous pouvez également créer des référentiels locaux pour extraire les packages R lorsque vous êtes hors ligne, ou souhaitez créer le tout plus rapidement.
Si vous le souhaitez, vous pouvez également créer le projet R sous forme de fichier zip et le partager avec des collègues. Il fonctionnera, à condition que vos collègues aient la même version R installée.
Une autre option consiste à créer un conteneur de l'ensemble du projet dans Ubuntu, Debian ou CentOS. Ainsi, au lieu de partager un fichier zip avec la génération de votre projet, vous partagez le
Docker
conteneur entier avec votre projet prêt à être exécuté.J'ai beaucoup expérimenté
rsuite
pour rechercher une reproductibilité totale, et éviter de dépendre des paquets que l'on installe dans l'environnement global. C'est faux car dès que vous installez une mise à jour de package, le projet, le plus souvent, cesse de fonctionner, en particulier les packages avec des appels très spécifiques à une fonction avec certains paramètres.La première chose que j'ai commencé à expérimenter était avec les
bookdown
ebooks. Je n'ai jamais eu la chance d'avoir un livre pour survivre à l'épreuve du temps plus de six mois. Donc, ce que j'ai fait, c'est convertir le projet de livre original pour suivre lersuite
cadre. Maintenant, je n'ai pas à m'inquiéter de la mise à jour de mon environnement R global, car le projet a son propre ensemble de packages dans ledeployment
dossier.La prochaine chose que j'ai faite a été de créer des projets d'apprentissage automatique, mais de la
rsuite
manière. Un projet maître, orchestrant au sommet, et tous les sous-projets et packages doivent être sous le contrôle du maître. Cela change vraiment la façon dont vous codez avec R, vous rendant plus productif.Après cela, j'ai commencé à travailler dans un nouveau package appelé
rTorch
. Cela a été possible, en grande partie, grâce àrsuite
; cela vous permet de penser et de faire les choses en grand.Un conseil cependant. L'apprentissage
rsuite
n'est pas facile. Parce que cela présente une nouvelle façon de créer des projets R, cela semble difficile. Ne vous effrayez pas aux premières tentatives, continuez à gravir la pente jusqu'à ce que vous y arriviez. Cela nécessite une connaissance approfondie de votre système d'exploitation et de votre système de fichiers.J'espère qu'un jour
RStudio
nous permettra de générer des projets orchestrants comme lersuite
fait depuis le menu. Ça serait génial.Liens:
Repo RSuite GitHUb
bookdown r4ds
keras et tutoriel brillant
moderndive-book-rsuite
interprétable_ml-rsuite
IntroMachineLearningWithR-rsuite
clark-intro_ml-rsuite
hyndman-bookdown-rsuite
statistique_rethinking-rsuite
fread-benchmarks-rsuite
dataviz-rsuite
tutoriel-segmentation-de-détail-h2o
tutoriel-de-désabonnement-client-telco
sclerotinia_rsuite
la source
R est OK pour une utilisation interactive et de petits scripts, mais je ne l'utiliserais pas pour un grand programme. J'utiliserais un langage grand public pour la plupart de la programmation et l'envelopperais dans une interface R.
la source
Rcpp
package, y compris du code C ++ dans les programmes R devient assez simple. Ainsi, la réécriture de certaines parties du code R peut être intégrée assez facilement dans R. De plus, l'avènement de RStudio a introduit un IDE pour R, bien que peut-être pas encore aussi puissant que Visual Studio.