20 décembre 2021
Fonctions primitives et structures de données de base.
Exemples : fonction sum et données de type matrix:
pryr::otype(sum)
## [1] "base"
pryr::otype(matrix(1))
## [1] "base"
Langage orienté objet.
Classes déclaratives.
MonPrenom <- "Eric" class(MonPrenom) <- "Prenom"
Les méthodes S3 sont liées aux fonctions, pas aux objets.
# Affichage par défaut MonPrenom
## [1] "Eric" ## attr(,"class") ## [1] "Prenom"
print.Prenom <- function(x) cat("Le prénom est", x)
# Affichage modifié
MonPrenom
## [1] "Eric" ## attr(,"class") ## [1] "Prenom"
print est une méthode générique (“un générique”) déclaré dans base.
help(print) pryr::otype(print)
Son code se résume à une déclaration UseMethod("print"):
## function (x, ...) 
## UseMethod("print")
## <bytecode: 0x7fb4258e1e20>
## <environment: namespace:base>
Il existe beaucoup de méthodes S3 pour print:
head(methods("print"))
## [1] "print.acf" "print.AES" ## [3] "print.all_vars" "print.anova" ## [5] "print.ansi_string" "print.ansi_style"
Chacune s’applique à une classe. print.default est utilisée en dernier ressort et s’appuie sur le type (R de base), pas la classe (S3).
typeof(MonPrenom)
## [1] "character"
pryr::otype(MonPrenom)
## [1] "S3"
Un objet peut appartenir à plusieurs classes.
class(MonPrenom) <- c("PrenomFrancais", "Prenom")
inherits(MonPrenom, what = "PrenomFrancais")
## [1] TRUE
inherits(MonPrenom, what = "Prenom")
## [1] TRUE
Le générique cherche une méthode pour chaque classe, dans l’ordre.
print.PrenomFrancais <- function(x) cat("Prénom français:",
    x)
MonPrenom
## [1] "Eric" ## attr(,"class") ## [1] "PrenomFrancais" "Prenom"
S3 est le langage courant de R.
Presque tous les packages sont écrits en S3.
Les génériques sont partout mais passent inaperçu:
library("entropart")
.S3methods(class = "SpeciesDistribution")
## [1] autoplot plot ## see '?methods' for accessing help and source code
# help(InternalMethods)
S4 structure les classes :
slots pour les données ;
constructeur explicite.
setClass("Personne", slots = list(Nom = "character",
    Prenom = "character"))
Moi <- new("Personne", Nom = "Marcon", Prenom = "Eric")
pryr::otype(Moi)
## [1] "S4"
Les méthodes appartiennent toujours aux fonctions:
setMethod("print", signature = "Personne", function(x,
    ...) {
    cat("La personne est:", x@Prenom, x@Nom)
})
print(Moi)
## La personne est: Eric Marcon
S4 est plus rigoureux que S3.
Quelques packages sur CRAN : Matrix, sp, odbc,… et beaucoup sur Bioconductor.
RC a été introduit dans R 2.12 (2010) avec le package methods.
Les méthodes appartiennent aux classes, comme en C++.
library("methods")
PersonneRC <- setRefClass("PersonneRC", 
    fields = list(Nom = "character", Prenom = "character"),
    methods = list(print = function() cat(Prenom, Nom)))
MoiRC <- new("PersonneRC", Nom = "Marcon", Prenom ="Eric")
pryr::otype(MoiRC)
## [1] "RC"
MoiRC$print()
## Eric Marcon
R6 perfectionne RC mais n’est pas inclus dans R.
Les attributs et les méthodes peuvent être publics ou privés.
Une méthode initialize() est utilisée comme constructeur.
library(R6)
PersonneR6 <- R6Class("PersonneR6", public = list(Nom = "character",
    Prenom = "character", initialize = function(Nom = NA,
        Prenom = NA) {
        self$Nom <- Nom
        self$Prenom <- Prenom
    }, print = function() cat(self$Prenom, self$Nom)))
MoiR6 <- PersonneR6$new(Nom = "Marcon", Prenom = "Eric")
MoiR6$print()
## Eric Marcon
Très peu utilisés, plutôt considérés comme des exercices de style.
S6 permet de programmer rigoureusement en objet.
Les performances sont inférieures à celles de S3.
Pas d’obligation mais cohérence à assurer.
Nommage des objets :
CamelCase : les mots sont compactés, les majuscules assurent la lisibilité ;
tiret_bas : les espaces sont remplacés par des _, pas de majuscule.
Les points sont interdits : séparateurs des génériques. Hélas : data.frame, t.test().
Utiliser des noms clairs, pas de valeur=12 ou TarbrInv.
Utiliser impérativement <- et réserver = aux arguments de fonctions.
a <- b <- 12 a
## [1] 12
b
## [1] 12
(a <- runif(1)) * (rnorm(1) -> b)
## [1] -0.0374763
Entourer <- par des espaces pour éviter la confusion avec -.
Respecter l’espacement standard du code autant que possible. knitr avec l’option tidy=TRUE met en forme automatiquement le code des documents RMarkdown.
Aller à la ligne entre les commandes, éviter ;.
Les accolades commencent sur la ligne de la commande, se terminent sur une ligne seule.
Indenter avec deux espaces. Tabulations interdites.
if (a > b) {
    print("Plus grand")
} else {
    print("Plus petit")
}
## [1] "Plus grand"
Dans le code, commenter toute ligne non évidente (de l’ordre de 2 sur 3). Commenter le pourquoi, pas le comment sauf extraordinaire.
Le commentaire précède la ligne de code ou va en fin de ligne.
# Calcul de la surface
if (is.null(Largeur)) {
    # Longueur seulement: carré
    Longueur^2
} else {
    # Vrai rectangle. Formule de xxx(1920).
    Longueur * Largeur
}
Bien choisir la langue des commentaires. Accents interdits dans les packages.
Commentaires de blocs par :
# Première partie #### x <- 1 # Deuxième partie #### y <- 2
Ces blocs sont repliables dans RStudio (menu Edit / Folding).
Les fonctions du package base sont toujours disponibles. Les autres non.
Les packages chargés par défaut peuvent être déchargés: utils, graphics, stats
Bonne pratique :
usage interactif : taper le nom de la fonction seulement : fonction()
code à conserver : préciser le package (une fonction peut être masquée par un autre package) : package::fonction().
Principes :
library("package") charge loadNamespace() et attache attachNamespace() un package
le package exporte des fonctions : package::fonction()
les fonctions sont accessibles par leur nom fonction()
si nouveaupackage exporte nouveaupackage::fonction(), la nouvelle fonction masque l’ancienne.
R démarre dans l’environnement vide.
Chaque package chargé crée un environnement fils.
La console se trouve dans l’environnement global, fils du dernier package chargé.
search()
## [1] ".GlobalEnv" "package:R6" ## [3] "package:entropart" "package:devEMF" ## [5] "package:forcats" "package:stringr" ## [7] "package:dplyr" "package:purrr" ## [9] "package:readr" "package:tidyr" ## [11] "package:tibble" "package:ggplot2" ## [13] "package:tidyverse" "package:kableExtra" ## [15] "package:stats" "package:graphics" ## [17] "package:grDevices" "package:utils" ## [19] "package:datasets" "package:methods" ## [21] "Autoloads" "package:base"
Le code d’une fonction appelée de la console s’excute dans un environnement fils de .GlobalEnv
environment()
## <environment: 0x7fb42d8ed318>
f <- function() environment() f()
## <environment: 0x7fb42dbb20a8>
parent.env(f())
## <environment: 0x7fb42d8ed318>
La recherche part de l’environnement global (ou de celui d’une fonction appelée) et descend la colonne de droite.
Les packages doivent être attachés pour y être.
Un package chargé est dans la colonne centrale: son espace de noms est accessible mais ses objets ne sont pas inclus dans la recherche.
pryr peut être chargé sans être attaché :
unloadNamespace("pryr")
isNamespaceLoaded("pryr")
## [1] FALSE
loadNamespace("pryr")
## <environment: namespace:pryr>
search()
## [1] ".GlobalEnv" "package:R6" ## [3] "package:entropart" "package:devEMF" ## [5] "package:forcats" "package:stringr" ## [7] "package:dplyr" "package:purrr" ## [9] "package:readr" "package:tidyr" ## [11] "package:tibble" "package:ggplot2" ## [13] "package:tidyverse" "package:kableExtra" ## [15] "package:stats" "package:graphics" ## [17] "package:grDevices" "package:utils" ## [19] "package:datasets" "package:methods" ## [21] "Autoloads" "package:base"
isNamespaceLoaded("pryr")
## [1] TRUE
La fonction otype() ne peut pas être trouvée mais elle peut être utilisée :
tryCatch(otype(1), error = function(e) print(e))
## <simpleError in otype(1): could not find function "otype">
pryr::otype(1)
## [1] "base"
loadNamespace() n’est jamais utilisé :
Appeler package::fonction() charge le package,
Attacher un package le charge.
Les objets non exportés par un package sont accessible dans son espace de nom avec trois :
package:::fonction()
Les autres aussi, mais c’est inutile :
stats:::sd(rnorm(100))
## [1] 0.9734397
Les méthodes S3 ne sont normalement pas exportées, seul le générique l’est.
names(formals(plot))
## [1] "x" "y" "..."
tryCatch(names(formals(entropart::plot.SpeciesDistribution)),
    error = function(e) print(e))
## <simpleError: 'plot.SpeciesDistribution' is not an exported object from 'namespace:entropart'>
names(formals(entropart:::plot.SpeciesDistribution))
## [1] "x" "..." "Distribution" ## [4] "type" "log" "main" ## [7] "xlab" "ylab"
Les packages s’appuient sur d’autres packages.
Ils peuvent les importer : ggplot2 importe plyr.
Ou en dépendre : ggplot2 dépend de reshape.
Un package qui exporte une méthode S3 dépend forcément du package contenant le générique.
Type de données = “mode”.
Réel
typeof(1.1)
## [1] "double"
 Entier : forcer le type en précisant L
typeof(1L)
## [1] "integer"
Logique
typeof(TRUE)
## [1] "logical"
Complexe
# help(complex) typeof(sqrt(-1 + (0+0i)))
## [1] "complex"
Caractère
typeof("Bonjour")
## [1] "character"
Brut
# help(raw) typeof(raw(1))
## [1] "raw"
is.character("Bonjour")
## [1] TRUE
is.double(1.2)
## [1] TRUE
is.logical(1 > 0)
## [1] TRUE
Attention à is.integer() :
is.integer(1)
## [1] FALSE
typeof(1)
## [1] "double"
is.numeric() est vrai pour les réels et les entiers.
5 structures de données :
| Atomique | Récursif | |
|---|---|---|
| Unidimensionnel | vector | list | 
| Bidimensionnel | matrix | data.frame | 
| n-dimensionnel | array | 
is.atomic() teste la structure d’une variable.
(MonVecteur <- 1:3)
## [1] 1 2 3
Tous les éléments sont du même type :
c(1, TRUE, "a")
## [1] "1" "TRUE" "a"
(MaMatrice <- matrix(1:6, nrow = 2))
## [,1] [,2] [,3] ## [1,] 1 3 5 ## [2,] 2 4 6
La multiplication matricielle est très performante
MaMatrice %*% matrix(1:3, ncol = 1)
## [,1] ## [1,] 22 ## [2,] 28
(MonTableau <- array(1:12, dim = c(2, 3, 2)))
## , , 1 ## ## [,1] [,2] [,3] ## [1,] 1 3 5 ## [2,] 2 4 6 ## ## , , 2 ## ## [,1] [,2] [,3] ## [1,] 7 9 11 ## [2,] 8 10 12
(MaListe <- list(Premier = 1:2, Deuxieme = "a"))
## $Premier ## [1] 1 2 ## ## $Deuxieme ## [1] "a"
identical(MaListe[[2]], MaListe$Deuxieme)
## [1] TRUE
Les types de données sont uniques par colonne.
(Mondf <- data.frame(Article = c("Pommes", "Poires"),
    Prix = c(2, 3)))
## Article Prix ## 1 Pommes 2 ## 2 Poires 3
identical(Mondf[, 1], Mondf$Article)
## [1] TRUE
Elements fondamentaux du langage.
Toute opération repose sur des fonctions y compris + :
(`+`)
## function (e1, e2)  .Primitive("+")
Les fonctions primitives sont écrites en C : ce sont les plus rapides.
Les fonctions internes aussi, mais doivent être appelées par un mécanisme spécial, moins efficace :
cbind
## function (..., deparse.level = 1) ## .Internal(cbind(deparse.level, ...)) ## <bytecode: 0x7fb428153878> ## <environment: namespace:base>
La majorité des fonctions est écrite en R.
Leur type est closure par opposition à primitive.
apply
## function (X, MARGIN, FUN, ..., simplify = TRUE) 
## {
##     FUN <- match.fun(FUN)
##     simplify <- isTRUE(simplify)
##     dl <- length(dim(X))
##     if (!dl) 
##         stop("dim(X) must have a positive length")
##     if (is.object(X)) 
##         X <- if (dl == 2L) 
##             as.matrix(X)
##         else as.array(X)
##     d <- dim(X)
##     dn <- dimnames(X)
##     ds <- seq_len(dl)
##     if (is.character(MARGIN)) {
##         if (is.null(dnn <- names(dn))) 
##             stop("'X' must have named dimnames")
##         MARGIN <- match(MARGIN, dnn)
##         if (anyNA(MARGIN)) 
##             stop("not all elements of 'MARGIN' are names of dimensions")
##     }
##     d.call <- d[-MARGIN]
##     d.ans <- d[MARGIN]
##     if (anyNA(d.call) || anyNA(d.ans)) 
##         stop("'MARGIN' does not match dim(X)")
##     s.call <- ds[-MARGIN]
##     s.ans <- ds[MARGIN]
##     dn.call <- dn[-MARGIN]
##     dn.ans <- dn[MARGIN]
##     d2 <- prod(d.ans)
##     if (d2 == 0L) {
##         newX <- array(vector(typeof(X), 1L), dim = c(prod(d.call), 
##             1L))
##         ans <- forceAndCall(1, FUN, if (length(d.call) < 2L) newX[, 
##             1] else array(newX[, 1L], d.call, dn.call), ...)
##         return(if (is.null(ans)) ans else if (length(d.ans) < 
##             2L) ans[1L][-1L] else array(ans, d.ans, dn.ans))
##     }
##     newX <- aperm(X, c(s.call, s.ans))
##     dim(newX) <- c(prod(d.call), d2)
##     ans <- vector("list", d2)
##     if (length(d.call) < 2L) {
##         if (length(dn.call)) 
##             dimnames(newX) <- c(dn.call, list(NULL))
##         for (i in 1L:d2) {
##             tmp <- forceAndCall(1, FUN, newX[, i], ...)
##             if (!is.null(tmp)) 
##                 ans[[i]] <- tmp
##         }
##     }
##     else for (i in 1L:d2) {
##         tmp <- forceAndCall(1, FUN, array(newX[, i], d.call, 
##             dn.call), ...)
##         if (!is.null(tmp)) 
##             ans[[i]] <- tmp
##     }
##     ans.list <- !simplify || is.recursive(ans[[1L]])
##     l.ans <- length(ans[[1L]])
##     ans.names <- names(ans[[1L]])
##     if (!ans.list) 
##         ans.list <- any(lengths(ans) != l.ans)
##     if (!ans.list && length(ans.names)) {
##         all.same <- vapply(ans, function(x) identical(names(x), 
##             ans.names), NA)
##         if (!all(all.same)) 
##             ans.names <- NULL
##     }
##     len.a <- if (ans.list) 
##         d2
##     else length(ans <- unlist(ans, recursive = FALSE))
##     if (length(MARGIN) == 1L && len.a == d2) {
##         names(ans) <- if (length(dn.ans[[1L]])) 
##             dn.ans[[1L]]
##         ans
##     }
##     else if (len.a == d2) 
##         array(ans, d.ans, dn.ans)
##     else if (len.a && len.a%%d2 == 0L) {
##         if (is.null(dn.ans)) 
##             dn.ans <- vector(mode = "list", length(d.ans))
##         dn1 <- list(ans.names)
##         if (length(dn.call) && !is.null(n1 <- names(dn <- dn.call[1])) && 
##             nzchar(n1) && length(ans.names) == length(dn[[1]])) 
##             names(dn1) <- n1
##         dn.ans <- c(dn1, dn.ans)
##         array(ans, c(len.a%/%d2, d.ans), if (!is.null(names(dn.ans)) || 
##             !all(vapply(dn.ans, is.null, NA))) 
##             dn.ans)
##     }
##     else ans
## }
## <bytecode: 0x7fb428924a28>
## <environment: namespace:base>
Arguments : passés à la fonction.
args(apply)
## function (X, MARGIN, FUN, ..., simplify = TRUE) ## NULL
Corps : le code de la fonction
deparse(body(apply))[1:3]
## [1] "{"                               
## [2] "    FUN <- match.fun(FUN)"       
## [3] "    simplify <- isTRUE(simplify)"
Environnement : l’ensemble des objets déclarés et un pointeur vers l’environnement parent.
environment(apply)
## <environment: namespace:base>
ls(environment(apply))[1:2]
## [1] "-" "-.Date"
parent.env(environment(apply))
## <environment: R_GlobalEnv>
Une fonction est exécutée dans son propre environnement :
environment()
## <environment: 0x7fb42d8ed318>
f <- function() environment() f()
## <environment: 0x7fb42925b890>
Son environnement parent est celui du code qui l’a appelé :
parent.env(f())
## <environment: 0x7fb42d8ed318>
Code R standard.
Surface <- function(Longueur, Largeur) {
    return(Longueur * Largeur)
}
Surface(Longueur = 2, Largeur = 3)
## [1] 6
Retourne un résultat avec return() ou la dernière valeur calculée.
Volume <- function(Longueur, Largeur) {
    return(Longueur * Largeur * Hauteur)
}
Longueur <- 5
Hauteur <- 10
Volume(Longueur = 2, Largeur = 3)
## [1] 60
Variables locales (définies dans l’environnement de la fonction) : Longueur et Largeur.
Variables manquantes recherchées dans les environnnements parents : Hauteur.
Evaluation tardive (lazy) de Hauteur.
Nommés. Appel par leur nom ou dans leur ordre :
c(Surface(Largeur = 3, Longueur = 2), Surface(Longueur = 2,
    Largeur = 3))
## [1] 6 6
c(Surface(Longueur = 2, 3), Surface(2, 3))
## [1] 6 6
Et même (mais illisible) :
Surface(3, Longueur = 2)
## [1] 6
Donner des noms explicites aux arguments. Le premier s’appelle souvent x dans les génériques.
Donner autant que possible des valeurs par défaut aux arguments.
Surface <- function(Longueur, Largeur = Longueur) {
    return(Longueur * Largeur)
}
Surface(Longueur = 2)
## [1] 4
Nommer tous les arguments à partir du deuxième lors de l’appel :
x <- runif(10, min = 5, max = 10) mean(x, na.rm = FALSE)
## [1] 7.98672
Ne jamais abréger les noms des arguments ou T pour TRUE.
Les génériques prévoient tous des arguments libres avec ... :
names(formals(plot))
## [1] "x" "y" "..."
Les méthodes ont la même signature que les génériques :
names(formals(entropart:::plot.SpeciesDistribution))
## [1] "x" "..." "Distribution" ## [4] "type" "log" "main" ## [7] "xlab" "ylab"
La méthode plot pour la classe SpeciesDistribution accepte tous arguments à la place de ... et les utilise dans une de ses lignes de code :
deparse(entropart:::plot.SpeciesDistribution)[15:16]
## [1] " graphics::plot(Ns, type = type, log = log, main = main, xlab = xlab, " ## [2] " ylab = ylab, axes = FALSE, ...)"
Tous les arguments non reconnus par plot.SpeciesDistribution sont passés à plot().
Les ... ne sont pas réservés aux génériques :
f <- function(x) x
g <- function(y, ...) f(...)
g("Rien", x = "Argument x passé à f par g")
## [1] "Argument x passé à f par g"
Mais il faut que tout argument soit reconnu par une fonction :
tryCatch(g("Rien", z = 2), error = function(e) print(e))
## <simpleError in f(...): unused argument (z = 2)>
Les opérateurs de R sont en fait des fonctions:
identical(2 + 2, `+`(2, 2))
## [1] TRUE
Les opérateurs définis par l’utilisateur sont obligatoirement entre % :
`%+%` <- function(a, b) paste(a, b) "Nouvelle" %+% "chaîne"
## [1] "Nouvelle chaîne"
La plupart des fonctions de R sont vectorielles :
x1 <- runif(3) x2 <- runif(3) sqrt(x1)
## [1] 0.9474360 0.4972275 0.7683883
x1 + x2
## [1] 1.783015 1.201093 1.069724
Raisonner en termes de vecteurs plutôt que de scalaires.
Ecrire des fonctions vectorielles sur leur premier argument :
entropart::lnq
## function (x, q) 
## {
##     if (q == 1) {
##         return(log(x))
##     }
##     else {
##         Log <- (x^(1 - q) - 1)/(1 - q)
##         Log[x < 0] <- NA
##         return(Log)
##     }
## }
## <bytecode: 0x7fb42f106278>
## <environment: namespace:entropart>
Exceptions à la règle : fonctions d’un vecteur, résultat scalaire.
sum(x1)
## [1] 1.735291
sapply() applique une fonction à chaque élément d’un vecteur ou d’une liste.
x1 <- runif(1000) identical(sqrt(x1), sapply(x1, FUN = sqrt))
## [1] TRUE
Fonctions similaires :
library("microbenchmark")
mb <- microbenchmark(sqrt(x1), sapply(x1, FUN = sqrt),
    lapply(x1, sqrt), vapply(x1, sqrt, FUN.VALUE = 0))
summary(mb)[, c("expr", "median")]
## expr median ## 1 sqrt(x1) 5.2630 ## 2 sapply(x1, FUN = sqrt) 349.7155 ## 3 lapply(x1, sqrt) 295.9830 ## 4 vapply(x1, sqrt, FUN.VALUE = 0) 310.3795
Infiniment plus lent qu’une fonction vectorielle.
lapply() renvoie une liste (économise le temps de simplify2array()) ;vapply() économise le temps de détermination du type du vecteur.Les boucles sont plus rapides !
Boucle <- function(x) {
    Racine <- vector("numeric", length = length(x))
    for (i in 1:length(x)) Racine[i] <- sqrt(x[i])
    return(Racine)
}
Vapply <- function(x) vapply(x, FUN = sqrt, 0)
mb <- microbenchmark(Vapply(x1), Boucle(x1))
summary(mb)[, c("expr", "median")]
## expr median ## 1 Vapply(x1) 302.1195 ## 2 Boucle(x1) 143.2455
Les boucles longues permettent un suivi :
Boucle <- function(x) {
    pgb <- txtProgressBar(min = 0, max = length(x))
    Racine <- vector("numeric", length = length(x))
    for (i in 1:length(x)) {
        Racine[i] <- sqrt(x[i])
        setTxtProgressBar(pgb, i)
    }
    return(Racine)
}
RacineX <- Boucle(x1)
## ==================================================
replicate() répète une instruction.
replicate(3, runif(1))
## [1] 0.9687692 0.2892228 0.2307221
est équivalent à runif(3).
vectorize() rend vectorielle une fonction qui ne l’est pas par des boucles. Ecrire plutôt les boucles.
Données : inventaire d’une parcelle de Paracou, 4 carrés distincts.
Objectif : calculer le nombre d’arbres par espèce, le nombre d’arbres par carré, la biodiversité par carré.
Technique : utiliser les fonctions vectorielles, les fonctions de type apply, éventuellement des boucles.
Lecture des arbres de la parcelle 6 de Paracou
# Lecture des arbres de la parcelle 6 de Paracou
Paracou6 <- read.csv2("data/Paracou6.csv")
Création d’un tableau croisé :
Paracou6X <- as.data.frame.matrix(xtabs(~paste(Family,
    Genus, Species) + SubPlot, data = Paracou6))
Paracou6X[1:2, ]
## 1 2 3 4 ## Anacardiaceae Anacardium spruceanum 0 1 0 2 ## Anacardiaceae Tapirira guianensis 1 2 0 0
as.data.frame.matrix est la méthode de conversion des matrices en dataframes…
apply() applique une fonction aux lignes ou colonnes d’un objet 2D.
colSums() et semblables (colMeans(), rowMeans()) sont optimisées.
mb <- microbenchmark(apply(Paracou6X, 2, sum), colSums(Paracou6X))
summary(mb)[, c("expr", "median")]
## expr median ## 1 apply(Paracou6X, 2, sum) 140.778 ## 2 colSums(Paracou6X) 79.158
colSums(Paracou6X)
## 1 2 3 4 ## 942 872 929 798
apply() ou préparation des données
mb <- microbenchmark(apply(Paracou6X, 2, function(x) x >
    0), colSums(Paracou6X > 0))
summary(mb)[, c("expr", "median")]
## expr median ## 1 apply(Paracou6X, 2, function(x) x > 0) 213.2625 ## 2 colSums(Paracou6X > 0) 100.4080
colSums(Paracou6X > 0)
## 1 2 3 4 ## 189 200 197 177
Estimation de la richesse spécifique avec entropart
library("entropart")
apply(Paracou6X, 2, Richness)
## 1 2 3 4 ## 355 348 315 296
apply()Comparaison avec une boucle
Boucle <- function(Cmnt) {
    Richesse <- vector("numeric", length = ncol(Cmnt))
    for (i in 1:ncol(Cmnt)) Richesse[i] <- Richness(Cmnt[,
        i])
    return(Richesse)
}
Apply <- function(Cmnt) apply(Cmnt, 2, Richness)
mb <- microbenchmark(Boucle(Paracou6X), Apply(Paracou6X))
summary(mb)[, c("expr", "median")]
## expr median ## 1 Boucle(Paracou6X) 5.500392 ## 2 Apply(Paracou6X) 5.629653
apply() clarifie (vectorise) le traitement mais ne l’accélère pas.