Fandom

Scratchpad

Avancer/Retarder ou décaler vers le haut/bas une variable

216,243pages on
this wiki
Add New Page
Discuss this page0 Share

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.

WE Wé wé ...

L'idée c'est

Var1 Var2    Var1 Var2
1    1       1    NA
2    2    => 2    1
3    3       3    2

ou

Var1 Var2    Var1 Var2
1    1       1    2
2    2    => 2    3
3    3       3    NA

le décalage étant ici d'une unité, mais on peut imaginer un décalage de plus d'une unité. Alors bien sûr il y a la fonction lag, mais cette fonction a le mauvais goût de ne s'appliquer qu'à des objets de type série temporelle et ces dernières sont supposées avoir un pas de temps régulier, et tout le monde n'a pas cette chance ...

Une solution simple et de bon goût consiste à utiliser :

DataFrame$Var2 <- c(NA,DataFrame$Var2[-length(DataFrame$Var2)]

Plus dur

Effectuer des décalages relativement à un facteur :

Var1 Var2      Var1 Var2
1    1         1    NA
1    2         1    1
1    3         1    2
2    1     =>  2    NA
2    2         2    1
2    3         2    2

Dans cette idée de décaler/retarder il y a bien une notion d'ordre sinon une notion temporelle qui était implicite dans l'exemple précédent. J'évoque cela maintenant car dans le cas qui nous occupe la première étape consiste évidemment à s'assurer que les données soient triées en fonction du facteur d'intérêt et le cas échéant en fonction d'une seconde variable d'ordre (e.g. année, date, numéro de séquence).

DataFrame <- DataFrame[order(DataFrame$Var1),]

Comme on souhaite opérer par sous-data.frame, on sent poindre tapply et by à l'horizon ce qui implique de s'assurer que cette variable facteur soit effectivement un facteur :

DataFrame$Var1 <- as.factor(as.character(DataFrame$Var1))

Opération qui au demeurant aura également l'avantage d'éventuellement nous débarrasser des niveaux de facteur historiques de cette variable s'il s'avérait qu'elle était déjà un facteur. On peut alors utiliser tapply :

tapply(DataFrame$Var2
      ,DataFrame$Var1
      ,function(x) c(NA,x[-length(x)]))

La dernière ligne est la définition d'une fonction anonyme qui va exister le temps de l'exécution de tapply. By, qui passe à la fonction un data frame entier plutôt qu'un vecteur s'utiliserait de la manière suivante :

by(DataFrame
   ,DataFrame$Var1
   ,function(x) c(NA,x$Var2[-length(x$Var2)]))

L'avantage de by c'est que lorsque la fonction est définie de manière non anonyme, elle permet de faire du debugage en insérant browser(). Dans le même temps il faut faire attention à ne pas terminer la fonction par une affectation ou, de manière plus explicite, à utiliser return().

Le problème avec tapply et by c'est qu'elles renvoient des listes, et pas du même type encore. Du coup pour recoller ça au data frame c'est un vrai casse tête. Et la solution vint d'ici : [1] Utiliser unlist() :

DataFrame$Var3 <- unlist(tapply(DataFrame$Var2
                        ,DataFrame$Var1
                        ,function(x) c(NA,x[-length(x)])) 

Ca marche pareil avec by.

Encore plus dur

Effectuer un décalage relativement à deux facteurs : Effectuer des décalages relativement à un facteur :

Var1 Var2 Var3      Var1 Var2 Var3
1    a    1         1    a    NA
1    a    2         1    a    1
1    a    3         1    a    2
1    b    1         2    b    NA
1    b    2         2    b    1
1    b    3         2    b    2
2    a    1    =>   1    a    NA
2    a    2         1    a    1
2    a    3         1    a    2
2    b    1         2    b    NA
2    b    2         2    b    1
2    b    3         2    b    2

"Fastoche" me direz vous et hop je trie

DataFrame <- DataFrame[order(DataFrame$Var1
                            ,DataFrame$Var2),]

et j't'apllique le biniou vu précédemment :

DataFrame$Var4 <- unlist(tapply(DataFrame$Var3
                        ,list(DataFrame$Var1,DataFrame$Var2)
                        ,function(x) c(NA,x[-length(x)])) 

Erreur, grave erreur. Pour une raison qui m'est inconnue l'ordre d'évaluation dans le list de tapply et inverse de celui du tri. Autrement dit on a consciencieusement trié par Var1-Var2, et le tapply va procéder par Var2-Var1, sont résultats sera du même tonneau et on va coller ensemble des choux et des carottes. Par voie de conséquence et finalement de manière assez simple il faut donc faire :

DataFrame$Var4 <- unlist(tapply(DataFrame$Var3
                        ,list(DataFrame$Var2,DataFrame$Var1)
                        ,function(x) c(NA,x[-length(x)])) 

Et si je veux faire des différences ?

Même combat mais en utilisant :

function(x) x - c(NA,x[-length(x)])

En tombant sur lag on ne peut avoir éviter d'apercevoir diff() qui permer de calculer des différences. On pourrait imaginer d'utiliser quelque chose du genre :

function(x) c(NA, diff(x))

(livré sans garanties)

Also on Fandom

Random wikia