IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Cours complet pour débutants pour apprendre la programmation en R


précédentsommairesuivant

5. Fonctions définies par l'usager

Objectifs du chapitre

  • Définir une fonction R, ses divers arguments et, le cas échéant, les valeurs par défaut de ceux-ci.
  • Déboguer une fonction R.
  • Adopter un style de codage correspondant à la pratique reconnue en R.

La possibilité pour l'usager de définir facilement et rapidement de nouvelles fonctions — et donc des extensions au langage — est une des grandes forces de R. Les fonctions personnelles définies dans l'espace de travail ou dans un package sont traitées par le système exactement comme les fonctions internes.

Ce court chapitre passe en revue la syntaxe et les règles pour créer des fonctions dans R. On discute également brièvement de débogage et de style de codage.

Énoncé du problème

Stock Ticker est un jeu canadien datant de 1937 dans lequel on brasse une série de dés pour simuler les mouvements boursiers et les dividendes de six titres financiers.
Pour les fins de cet exercice, nous ne nous intéresserons qu'aux mouvements boursiers, et ce, pour un seul titre — nous ignorerons donc le versement des dividendes.
La valeur du titre est établie à partir de la valeur au tour de jeu précédent et du résultat du lancer de deux dés.

  1. Un premier dé à trois faces détermine la direction du mouvement boursier : hausse, baisse ou nul.
  2. Un second dé à trois faces détermine l'amplitude de la hausse ou de la baisse, le cas échéant. Les valeurs possibles sont 5, 10 et 20.

La valeur de départ du titre est 100.
Par exemple, si les résultats des dés au premier tour de jeu sont « baisse » et 20, la valeur du titre après ce tour sera 80. Si, au tour suivant, les résultats des dés sont « nul » et « 5 », la valeur du titre demeurera de 80. On fournit les résultats de 10 lancers des dés sous forme de data frame :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
> x
   direction amplitude
 1    baisse        20
 2    baisse        10
 3       nul        20
 4       nul        20
 5       nul        20
 6    hausse        20
 7       nul        20
 8    hausse         5
 9    baisse        10
10    hausse        20

Écrire une fonction valeurs() servant à calculer les valeurs successives du titre.
La fonction prend en arguments x, un data frame contenant les résultats des lancers des dés, ainsi que start, la valeur de départ du titre (100 par défaut). La fonction retourne un vecteur contenant les valeurs successives du titre.
Par exemple, avec les données ci-dessus, on obtiendrait :

 
Sélectionnez
> valeurs(x)            # start = 100 par défaut
[1]  80  70  70  70  70  90  90  95  85 105

Le calcul de la valeur du titre étant récursif, l'utilisation d'une boucle est ici inévitable. Comme le nombre de répétitions est connu d'avance (le nombre de valeurs à calculer correspond au nombre de lancers de dés), une boucle for() serait le choix approprié.

5-1. Définition d'une fonction

On définit une nouvelle fonction avec la syntaxe suivante :

 
Sélectionnez
fun <- function(arguments) expression

  • fun est le nom de la fonction (les règles pour les noms de fonctions étant les mêmes que celles présentées à la section 2.2Conventions pour les noms d'objets pour tout autre objet) ;
  • arguments est la liste des arguments, séparés par des virgules ;
  • expression constitue le corps de la fonction, soit une expression ou un groupe d'expressions réunies par des accolades.

5-2. Retourner des résultats

La plupart des fonctions sont écrites dans le but de retourner un résultat. Or, les règles d'interprétation d'un groupe d'expressions présentées à la section 2.1Commandes R s'appliquent ici au corps de la fonction.

  • Une fonction retourne tout simplement le résultat de la dernière expression du corps de la fonction.
  • On évitera donc que la dernière expression soit une affectation, car la fonction ne retournera alors rien et on ne pourra utiliser une construction de la forme x <- f() pour affecter le résultat de la fonction à une variable.
  • Si on doit retourner un résultat sans être à la dernière ligne de la fonction (à l'intérieur d'un bloc conditionnel, par exemple), on utilise la fonction return. L'utilisation de return à la toute fin d'une fonction est tout à fait inutile et considérée comme du mauvais style en R.
  • Lorsqu'une fonction doit retourner plusieurs résultats, il est en général préférable d'avoir recours à une liste nommée.

5-3. Variables locales et globales

Comme la majorité des langages de programmation, R comporte des concepts de variable locale et de variable globale.

  • Toute variable définie dans une fonction est locale à cette fonction, c'est-à-dire qu'elle :

    • n'apparaît pas dans l'espace de travail ;
    • n'écrase pas une variable du même nom dans l'espace de travail.
  • Il est possible de définir une variable dans l'espace de travail depuis une fonction avec l'opérateur d'affectation <<-. Il est très rare — et généralement non recommandé — de devoir recourir à de telles variables globales.
  • On peut définir une fonction à l'intérieur d'une autre fonction. Cette fonction sera locale à la fonction dans laquelle elle est définie.

Le lecteur intéressé à en savoir plus pourra consulter les sections de la documentation de R portant sur la portée lexicale (lexical scoping). C'est un sujet important et intéressant, mais malheureusement trop avancé pour ce document d'introduction à la programmation en R.

5-4. Exemple de fonction

Le code développé pour l'exemple de point fixe de la section 4.4Algorithme du point fixe peut être intégré dans une fonction ; voir la figure 5.1.

  • Le nom de la fonction est fp.
  • La fonction compte quatre arguments : k, n, start et TOL.
  • Les deux derniers arguments ont respectivement des valeurs par défaut de 0.05 et 10−10.
  • La fonction retourne la valeur de la variable i puisque l'on évalue celle-ci à la dernière ligne (ou expression) de la fonction.

La définition de la fonction devra inclure start = 100 comme deuxième argument afin de spécifier que :

  1. start est un argument de la fonction ;
  2. La valeur par défaut de l'argument est 100.
Fig. 5.1 - Exemple de fonction de point fixe
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
fp <- function(k, n, start = 0.05, TOL = 1E-10)
{
    ## Fonction pour trouver par la méthode du point
    ## fixe le taux d'intérêt pour lequel une série de
    ## 'n' paiements vaut 'k'.
    ##
    ## ARGUMENTS
    ##
    ##     k: la valeur présente des paiements
    ##     n: le nombre de paiements
    ## start: point de départ des itérations
    ##   TOL: niveau de précision souhaité
    ##
    ## RETOURNE
    ##
    ## Le taux d'intérêt

    i <- start
    repeat
    {
        it <- i
        i <- (1 - (1 + it)^(-n))/k
        if (abs(i - it)/it < TOL)
        break
    }
    i
}

5-5. Fonctions anonymes

Il est parfois utile de définir une fonction sans lui attribuer un nom — d'où la notion de fonction anonyme. Il s'agira en général de fonctions courtes utilisées dans une autre fonction. Par exemple, pour calculer la valeur de xy2 pour toutes les combinaisons de x et y stockées dans des vecteurs du même nom, on pourrait utiliser la fonction outer ainsi :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
> x <- 1:3; y <- 4:6
> f <- function(x, y) x * y^2
> outer(x, y, f)
     [,1] [,2] [,3]
[1,]   16   25   36
[2,]   32   50   72
[3,]   48   75  108

Cependant, si la fonction f ne sert à rien ultérieurement, on peut se contenter de passer l'objet fonction à outer sans jamais lui attribuer un nom :

 
Sélectionnez
1.
2.
3.
4.
5.
> outer(x, y, function(x, y) x * y^2)
     [,1] [,2] [,3]
[1,]   16   25   36
[2,]   32   50   72
[3,]   48   75  108

On a alors utilisé dans outer une fonction anonyme.

5-6. Débogage de fonctions

Il est assez rare d'arriver à écrire un bout de code sans bogue du premier coup. Par conséquent, qui dit programmation dit séances de débogage.

Les techniques de débogage les plus simples et naïves sont parfois les plus efficaces et certainement les plus faciles à apprendre. Loin d'un traité sur le débogage de code R, nous offrons seulement ici quelques trucs que nous utilisons régulièrement.

  • Les erreurs de syntaxe sont les plus fréquentes (en particulier l'oubli de virgules). Lors de la définition d'une fonction, une vérification de la syntaxe est effectuée par l'interprète R. Attention, cependant : une erreur peut prendre sa source plusieurs lignes avant celle que l'interprète pointe comme causant problème.
  • Les messages d'erreur de l'interprète ne sont pas toujours d'un grand secours… tant que l'on n'a pas appris à les reconnaître. Un exemple de message d'erreur fréquemment rencontré :

    • valeur manquante là où TRUE / FALSE est requis

      Cette erreur provient généralement d'une commande if dont l'argument vaut NA plutôt que TRUE ou FALSE. La raison : des valeurs manquantes se sont faufilées dans les calculs à notre insu jusqu'à l'instruction if, faisant en sorte que l'argument de if vaut NA alors qu'il ne peut être que booléen.

  • Lorsqu'une fonction ne retourne pas le résultat attendu, placer des commandes print à l'intérieur de la fonction, de façon à pouvoir suivre les valeurs prises par les différentes variables.

    Par exemple, la modification suivante à la boucle de la fonction fp permet d'afficher les valeurs successives de la variable i et de détecter, par exemple, une procédure itérative divergente :

     
    Sélectionnez
    1.
    2.
    3.
    4.
    5.
    6.
    7.
    8.
    repeat
    {
        it <- i
        i <- (1 - (1 + it)^(-n))/k
        print(i)
        if (abs((i - it)/it < TOL))
            break
    }
    
  • Quand ce qui précède ne fonctionne pas, ne reste souvent qu'à exécuter manuellement la fonction. Pour ce faire, définir dans l'espace de travail tous les arguments de la fonction, puis exécuter le corps de la fonction ligne par ligne. La vérification du résultat de chaque ligne permet généralement de retrouver la ou les expressions qui causent problème.

5-7. Styles de codage

Si tous conviennent que l'adoption d'un style propre et uniforme favorise le développement et la lecture de code, il existe plusieurs chapelles dans le monde des programmeurs quant à la « bonne façon » de présenter et, surtout, d'indenter le code informatique.

Par exemple, Emacs reconnaît et supporte les styles de codage suivants, entre autres :

C++/Stroustrup
Sélectionnez
1.
2.
3.
4.
for (i in 1:10)
{
    expression
}
K&R (1TBS)
Sélectionnez
1.
2.
3.
for (i in 1:10){
    expression
}
Whitesmith
Sélectionnez
1.
2.
3.
4.
for (i in 1:10)
    {
    expression
    }
GNU
Sélectionnez
1.
2.
3.
4.
for (i in 1:10)
  {
    expression
  }
  • Pour des raisons générales de lisibilité et de popularité, le style C++, avec les accolades sur leurs propres lignes et une indentation de quatre (4) espaces est considéré comme standard pour la programmation en R.
  • Consulter la documentation de votre éditeur de texte pour savoir s'il est possible de configurer le niveau d'indentation. La plupart des bons éditeurs pour programmeurs le permettent.
  • Surtout, éviter de ne pas du tout indenter le code.

Solution du problème

Il existe bien évidemment une multitude de solutions valides. Celle que nous proposons à la figure 5.2 repose sur deux idées principales :

  1. Le vecteur créé pour accueillir les résultats contient la valeur de départ en première position afin d'éviter de traiter la première boucle comme une exception ; cette valeur de départ est supprimée du vecteur au moment de retourner les résultats ;
  2. Les étiquettes de mouvement du titre sont rapidement converties en valeurs numériques qui permettent de calculer les valeurs successives du titre.

Ensemble, ces deux stratégies permettent d'en arriver à une fonction compacte et efficace.
On remarquera également que la création d'un contenant pour les résultats permet d'éviter le Syndrome de la plaque à biscuits™.

Fig. 5.2 - Fonction valeurs solution du problème du chapitre
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
valeurs <- function(x, start = 100)
{
    ## Création d'un vecteur pour les résultats. La valeur
    ## de départ est placée au début du vecteur pour faire
    ## la boucle. Elle sera supprimée à la fin.
    res <- c(start, numeric(nrow(x)))

    ## Conversion des étiquettes ("hausse", "nul", "baisse")
    ## de la première colonne des données en
    ## valeurs numériques (1, 0, -1).
    d <- (x[, 1] == "hausse") - (x[, 1] == "baisse")

    ## Calcul des valeurs successives du titre.
    for(i in seq(length(res) - 1))
        res[i + 1] <- res[i] + d[i] * x[i, 2]

    ## Résultats sans la valeur de départ
    res[-1]
}

5-8. Exemples

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
### POINT FIXE

## Comme premier exemple de fonction, on réalise une mise en
## œuvre de l'algorithme du point fixe pour trouver le taux
## d'intérêt tel que a_angle{n} = k pour 'n' et 'k' donnés.
## Cette mise en œuvre est peu générale puisqu'il faudrait
## modifier la fonction chaque fois que l'on change la
## fonction f(x) dont on cherche le point fixe.
fp1 <- function(k, n, start = 0.05, TOL = 1E-10)
{
    i <- start
    repeat
    {
        it <- i
        i <- (1 - (1 + it)^(-n))/k
        if (abs(i - it)/it < TOL)
            break
    }
    i
}

fp1(7.2, 10)            # valeur de départ par défaut
fp1(7.2, 10, 0.06)      # valeur de départ spécifiée
i                       # les variables n'existent pas...
start                   # ... dans l'espace de travail

## Généralisation de la fonction 'fp1': la fonction f(x) dont
## on cherche le point fixe (c'est-à-dire la valeur de 'x'
## tel que f(x) = x) est passée en argument. On peut faire
## ça ? Bien sûr, puisqu'une fonction est un objet comme un
## autre en R. On ajoute également à la fonction un argument
## 'echo' qui, lorsque TRUE, fera en sorte d'afficher à
## l'écran les valeurs successives de 'x'.
##
## Ci-dessous, il est implicite que le premier argument, FUN,
## est une fonction.
fp2 <- function(FUN, start, echo = FALSE, TOL = 1E-10)
{
    x <- start
    repeat
    {
        xt <- x

        if (echo)       # inutile de faire 'if (echo == TRUE)'
            print(xt)

        x <- FUN(xt)    # appel de la fonction
        if (abs(x - xt)/xt < TOL)
            break
    }
    x
}

f <- function(i) (1 - (1+i)^(-10))/7.2 # définition de f(x)
fp2(f, 0.05)              # solution
fp2(f, 0.05, echo = TRUE) # avec résultats intermédiaires
fp2(function(x) 3^(-x), start = 0.5) # avec fonction anonyme

## Amélioration mineure à la fonction 'fp2': puisque la
## valeur de 'echo' ne change pas pendant l'exécution de la
## fonction, on peut éviter de refaire le test à chaque
## itération de la boucle. Une solution élégante consiste à
## utiliser un outil avancé du langage R : les expressions.
##
## L'objet créé par la fonction 'expression' est une
## expression non encore évaluée (comme si on n'avait pas
## appuyé sur Entrée à la fin de la ligne). On peut ensuite
## évaluer l'expression (appuyer sur Entrée) avec 'exec'.
fp3 <- function(FUN, start, echo = FALSE, TOL = 1E-10)
{
    x <- start

    ## Choisir l'expression à exécuter plus loin
    if (echo)
        expr <- expression(print(xt <- x))
    else
        expr <- expression(xt <- x)

    repeat
    {
        eval(expr) # évaluer l'expression
        x <- FUN(xt) # appel de la fonction
        if (abs(x - xt)/xt < TOL)
            break
    }
    x
}

fp3(f, 0.05, echo = TRUE) # avec résultats intermédiaires
fp3(function(x) 3^(-x), start = 0.5) # avec une fonction anonyme

### SUITE DE FIBONACCI

## On a présenté au chapitre 4 deux manières différentes de
## pour calculer les 'n' premières valeurs de la suite de
## Fibonacci. On crée d'abord des fonctions à partir de ce
## code. Avantage d'avoir des fonctions : elles sont valides
## pour tout 'n' > 2.
##
## D'abord la version inefficace parce qu'elle souffre du
## Syndrome de la plaque à biscuits décrit au chapitre 4.
fib1 <- function(n)
{
    res <- c(0, 1)
    for (i in 3:n)
        res[i] <- res[i - 1] + res[i - 2]
    res
}
fib1(10)
fib1(20)

## Puis la version qui devrait s'avérer plus efficace parce
## que l'on initialise d'entrée de jeu un contenant de la
## bonne longueur qu'on remplit par la suite.
fib2 <- function(n)
{
    res <- numeric(n)       # contenant créé
    res[2] <- 1             # res[1] vaut déjà 0
    for (i in 3:n)
        res[i] <- res[i - 1] + res[i - 2]
    res
}
fib2(5)
fib2(20)

## A-t-on vraiment gagné en efficacité? Comparons le temps
## requis pour générer une longue suite de Fibonacci avec les
## deux fonctions.
system.time(fib1(10000)) # version inefficace
system.time(fib2(10000)) # version efficace, ~5x plus rapide

## Variation sur un même thème : une fonction pour calculer non
## pas les 'n' premières valeurs de la suite de Fibonacci,
## mais uniquement la 'n'ième valeur.
##
## Mais il y a un mais : la fonction 'fib3' est truffée
## d'erreurs (de syntaxe, d'algorithmique, de conception). À
## vous de trouver les bogues. (Afin de préserver cet
## exemple, copier le code erroné plus bas ou dans un autre
## fichier avant d'y faire les corrections.)
fib3 <- function(nb)
{
    x <- 0
    x1 _ 0
    x2 <- 1
    while (n > 0)
    {
        x <- x1 + x2
        x2 <- x1
        x1 <- x
        n <- n - 1
    }
}
fib3(1)         # devrait donner 0
fib3(2)         # devrait donner 1
fib3(5)         # devrait donner 3
fib3(10)        # devrait donner 34
fib3(20)        # devrait donner 4181

5-9. Exercices

5.1 (solution) La fonction var calcule l'estimateur sans biais de la variance d'une population à partir de l'échantillon donné en argument. Écrire une fonction variance qui calculera l'estimateur biaisé ou sans biais selon que l'argument biased sera TRUE ou FALSE, respectivement. Le comportement par défaut de variance devrait être le même que celui de var. L'estimateur sans biais de la variance à partir d'un échantillon kitxmlcodeinlinelatexdvpX_1,\dots,X_nfinkitxmlcodeinlinelatexdvp est

kitxmlcodelatexdvpS_{n-1}^2 = \frac{1}{n-1}\sum_{i=1}^n (X_i-\hat{X})^2finkitxmlcodelatexdvp

alors que l'estimateur biaisé est

kitxmlcodelatexdvpS_n^2 = \frac{1}{n}\sum_{i=1}^n (X_i-\hat{X})^2finkitxmlcodelatexdvp

où kitxmlcodeinlinelatexdvp\hat{X} = n^{-1}(X_1+\cdots+X_n)finkitxmlcodeinlinelatexdvp.

5.2 (solution) Écrire une fonction matrix2 qui, contrairement à la fonction matrix, remplira par défaut la matrice par ligne. La fonction ne doit pas utiliser matrix. Les arguments de la fonction matrix2 seront les mêmes que ceux de matrix, sauf que l'argument byrow sera remplacé par bycol.

5.3 (solution) Écrire une fonction phi servant à calculer la fonction de densité de probabilité d'une loi normale centrée réduite, soit

kitxmlcodelatexdvp\phi(x) = \frac{1}{\sqrt{2\pi}}e^{-x^2/2},\ -\infty < x < \inftyfinkitxmlcodelatexdvp

La fonction devrait prendre en argument un vecteur de valeurs de x.Comparer les résultats avec ceux de la fonction dnorm.

5.4 (solution) Écrire une fonction Phi servant à calculer la fonction de répartition d'une loi normale centrée réduite, soit

kitxmlcodelatexdvp\Phi(x) = \int_{-\infty}^x \frac{1}{\sqrt{2\pi}}e^{-y^2/2}dy,\ -\infty<x<\inftyfinkitxmlcodelatexdvp

Supposer, pour le moment, que kitxmlcodeinlinelatexdvpx\ge0finkitxmlcodeinlinelatexdvp. L'évaluation numérique de l'intégrale ci-dessus peut se faire avec l'identité

kitxmlcodelatexdvp\Phi(x) = \frac{1}{2}+\phi(x)\sum_{n=0}^\infty\frac{x^{2n+1}}{1\cdot3\cdot5\cdots(2n+1)},\ x\ge0finkitxmlcodelatexdvp

Utiliser la fonction phi de l'exercice 5.3 et tronquer la somme infinie à une grande valeur, 50 par exemple. La fonction ne doit pas utiliser de boucles, mais peut ne prendre qu'une seule valeur de x à la fois. Comparer les résultats avec ceux de la fonction pnorm.

5.5 (solution) Modifier la fonction Phi de l'exercice 5.4 afin qu'elle admette des valeurs négatives. Lorsque kitxmlcodeinlinelatexdvpx<0,\ \Phi(x) = 1 - \Phi(-x)finkitxmlcodeinlinelatexdvp. La solution simple consiste à utiliser une structure de contrôle if ... else, mais les curieux chercheront à s'en passer.

5.6 (solution) Généraliser maintenant la fonction de l'exercice 5.5 pour qu'elle prenne en argument un vecteur de valeurs de kitxmlcodeinlinelatexdvpxfinkitxmlcodeinlinelatexdvp. Ne pas utiliser de boucle. Comparer les résultats avec ceux de la fonction pnorm.

5.7 (solution) Sans utiliser l'opérateur %*%, écrire une fonctionprod.mat qui effectuera le produit matriciel de deux matrices seulement si les dimensions de celles-ci le permettent. Cette fonction aura deux arguments (mat1 et mat2) et devra tout d'abord vérifier si le produit matriciel est possible. Si celui-ci est impossible, la fonction retourne un message d'erreur.

  1. Utiliser une structure de contrôle if ... else et deux boucles.
  2. Utiliser une structure de contrôle if ... else et une seule boucle.

Dans chaque cas, comparer le résultat avec l'opérateur %*%.

5.8 (solution) Vous devez calculer la note finale d'un groupe d'étudiants à partir de deux informations : 1) une matrice contenant la note sur 100 des étudiants à chacune des évaluations, et 2) un vecteur contenant la pondération des évaluations. Un de vos collègues a composé la fonction notes.finales ci-dessous afin de faire le calcul de la note finale pour chacun de ses étudiants. Votre collègue vous mentionne toutefois que sa fonction est plutôt lente et inefficace pour de grands groupes d'étudiants. Modifiez la fonction afin d'en réduire le nombre d'opérations et faire en sorte qu'elle n'utilise aucune boucle.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
notes.finales <- function(notes, p)
{
    netud <- nrow(notes)
    neval <- ncol(notes)
    final <- (1:netud) * 0
    for(i in 1:netud)
    {
        for(j in 1:neval)
        {
            final[i] <- final[i] + notes[i, j] * p[j]
        }
    }
    final
}

5.9 (solution) Trouver les erreurs qui empêchent la définition de la fonction ci-dessous.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
AnnuiteFinPeriode <- function(n, i)
{{
    v <- 1/1 + i)
    ValPresChaquePmt <- v^(1:n)
    sum(ValPresChaquepmt)
}

5.10 (solution) La fonction ci-dessous calcule la valeur des paramètres d'une loi normale, gamma ou Pareto à partir de la moyenne et de la variance, qui sont connues par l'utilisateur.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
param <- function(moyenne, variance, loi)
{
    loi <- tolower(loi) {
    if (loi == "normale")
        param1 <- moyenne
        param2 <- sqrt(variance)
        return(list(mean = param1, sd = param2))
    }
    if (loi == "gamma") {
        param2 <- moyenne/variance
        param1 <- moyenne * param2
        return(list(shape = param1, scale = param2))
    }
    if (loi == "pareto") {
        cte <- variance/moyenne^2
        param1 <- 2 * cte/(cte-1)
        param2 <- moyenne * (param1 - 1)
        return(list(alpha = param1, lambda = param2))
    }
    stop("La loi doit être une de \"normale\", \"gamma\" ou \"pareto\"")
}

L'utilisation de la fonction pour diverses lois donne les résultats suivants :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
> param(2, 4, "normale")
$mean
[1] 2
$sd
[1] 2
> param(50, 7500, "gamma")
Erreur dans param(50, 7500, "gamma") : Objet "param1" introuvable
> param(50, 7500, "pareto")
Erreur dans param(50, 7500, "pareto") : Objet "param1" introuvable
  1. Expliquer pour quelle raison la fonction se comporte ainsi.
  2. Appliquer les correctifs nécessaires à la fonction pour que celle-ci puisse calculer les bonnes valeurs. (Les erreurs ne se trouvent pas dans les mathématiques de la fonction.) Astuce : tirer profit du moteur d'indentation de votre éditeur de texte pour programmeur.

précédentsommairesuivant

Licence Creative Commons
Le contenu de cet article est rédigé par Vincent Goulet et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2018 Developpez.com.