Paramètres

J’ai mis les données sur Github afin de pouvoir répliquer le notebook facilement.

Le code ci dessous importe la data, formate les variables dates et arrange les variables stock et markingdate par ordre croissant.

library(tidyverse)
## ── Attaching packages ────────────────────────────────── tidyverse 1.2.1 ──
## ✔ ggplot2 3.0.0     ✔ purrr   0.3.2
## ✔ tibble  2.1.3     ✔ dplyr   0.8.1
## ✔ tidyr   0.8.3     ✔ stringr 1.3.1
## ✔ readr   1.1.1     ✔ forcats 0.3.0
## ── Conflicts ───────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following object is masked from 'package:base':
## 
##     date
nbStart <- dmy('01/01/2018')
nbEnd <- dmy('31/12/2018')

PATH <- "https://raw.githubusercontent.com/thomaspernet/data_csv_r/master/data/CSAV_data.csv"
####
df <-  read.csv(PATH, sep = ';') %>%
  mutate(MarkingDate = dmy(MarkingDate),
         DateDiv = dmy(DateDiv),
         PayDate = dmy(PayDate)) %>%
  filter(MarkingDate >=nbStart &  MarkingDate <=nbEnd) %>%
  arrange(Stock, MarkingDate)
head(df)
ABCDEFGHIJ0123456789
 
 
Stock
<fctr>
MarkingDate
<date>
DateDiv
<date>
Amount
<dbl>
Yield
<dbl>
PayDate
<date>
1A2018-01-192028-05-250.198408270.73140762028-05-27
2A2018-01-272018-03-270.660698520.92566782018-03-29
3A2018-03-072020-10-150.986370980.13417402020-10-17
4A2018-03-092027-03-090.048102760.54381152027-03-11
5A2018-03-162027-03-090.121002460.52502032027-03-11
6A2018-05-082024-12-180.528283460.47225052024-12-20

1- Bonus Create Bucket

Ici, on souhaite créer une variable bucket, qui est un index si la MarkingDate est entre deux dates. Pour cela, on va utiliser la fonction findInterval.

C’est assez simple, il suffit de créer un vecteur de date qui va spliter la columne MarkingDate. Par exemple, on souhaite créer un bucket index pour un intervalle tous les trois mois. On créer un vecteur de date:

date_bucket <- c(ymd("2018-03-01"), ymd("2018-06-01"), ymd("2018-09-01"))

Note que j’utilise lubridate pour créer les dates, cela facilite la manipulation. Ensuite, je vais grouper les MarkingDate selon si elles sont dans les intervalles. Par exemple, si une date est entre le premier intervalle, alors le bucket est 0, si la date est entre le deuxième intervalle, alors bucket est égale a 1 et ainsi de suite. Toutes les dates au delà du dernier intervalle vont avoir un index max + 1. Dans notre example, il y a 3 intervalles, toutes les dates au delà du dernier intervalle auront la valeur 3

Attention, il faut que les date soient dans un ordre croissant, c’est pour cela que j’utilise arrange()

Pour pus d’info sur la fonction, ici

date_bucket <- c(ymd("2018-03-01"), ymd("2018-06-01"), ymd("2018-09-01"))

df <- df %>% arrange(MarkingDate) %>%
  mutate(bucket = findInterval(MarkingDate, 
                                  date_bucket)
                )
df
ABCDEFGHIJ0123456789
Stock
<fctr>
MarkingDate
<date>
DateDiv
<date>
Amount
<dbl>
Yield
<dbl>
PayDate
<date>
bucket
<int>
B2018-01-062021-06-090.985671120.030327962021-06-110
E2018-01-082025-01-160.908368000.043555722025-01-180
A2018-01-192028-05-250.198408270.731407652028-05-270
E2018-01-252020-01-240.163320930.563450472020-01-260
A2018-01-272018-03-270.660698520.925667772018-03-290
E2018-02-132030-08-070.212406800.064266552030-08-090
A2018-03-072020-10-150.986370980.134173992020-10-171
A2018-03-092027-03-090.048102760.543811532027-03-111
E2018-03-132027-05-130.427070060.849267642027-05-151
A2018-03-162027-03-090.121002460.525020342027-03-111

1- nb de markind dates sur une periode (01/01/18 à 31/12/18)

On extrait uniquement les valeurs uniques par groupe

df %>% 
  group_by(Stock) %>%
  select(Stock, MarkingDate) %>%
  unique()
ABCDEFGHIJ0123456789
Stock
<fctr>
MarkingDate
<date>
B2018-01-06
E2018-01-08
A2018-01-19
E2018-01-25
A2018-01-27
E2018-02-13
A2018-03-07
A2018-03-09
E2018-03-13
A2018-03-16

Intervalle

  • Intervalle max entre deux dates de marking consécutives +
  • intervalle aux limites entre a- (01/01/18 et 1ere date de arking) et
  • b- entre (dernière date de marking et 31/12/18) + les cas où il n’y a pas d’observation

on prend seulement le lag

#### No upper/lower bounds
df %>% group_by(Stock) %>%
select(Stock, MarkingDate) %>%
mutate(diff_days = MarkingDate - lag(MarkingDate, 1))
ABCDEFGHIJ0123456789
Stock
<fctr>
MarkingDate
<date>
diff_days
<time>
B2018-01-06NA days
E2018-01-08NA days
A2018-01-19NA days
E2018-01-2517 days
A2018-01-278 days
E2018-02-1319 days
A2018-03-0739 days
A2018-03-092 days
E2018-03-1328 days
A2018-03-167 days

On séléctionne par groupe uniquement la première et dernière date

#### Upper/lower bounds   

df %>% group_by(Stock) %>%
  select(Stock, MarkingDate) %>%
  filter(row_number() %in% c(1, n())) %>%
  mutate(diff_days_limits = ifelse(row_number() == 1,
                                   MarkingDate - nbStart,
                                   nbEnd - MarkingDate))
ABCDEFGHIJ0123456789
Stock
<fctr>
MarkingDate
<date>
diff_days_limits
<dbl>
B2018-01-065
E2018-01-087
A2018-01-1918
D2018-07-06186
B2018-07-17167
E2018-08-21132
D2018-10-1973
A2018-11-2635

intervalle avec nombre d’obs

  • Intervalle max contenant 4 observations

On souhaite avoir les dates non pas en lag mais en forward; Pour aller vers l’avant, on utilise lead

df %>% group_by(Stock) %>%
  select(Stock, MarkingDate) %>%
  mutate(diff_days =lead(MarkingDate, 4) - MarkingDate)
ABCDEFGHIJ0123456789
Stock
<fctr>
MarkingDate
<date>
diff_days
<time>
B2018-01-06NA days
E2018-01-0888 days
A2018-01-1956 days
E2018-01-2582 days
A2018-01-27101 days
E2018-02-1383 days
A2018-03-07149 days
A2018-03-09147 days
E2018-03-13119 days
A2018-03-16164 days
  • intervalle aux limites entre (01/01/18 et les 5 ères dates de marking)

On séléctionne uniquement les 5 premières valeurs par groupe

df %>% group_by(Stock) %>%
  select(Stock, MarkingDate) %>%
  filter(row_number() %in% c(seq(1,5))) %>%
  mutate(diff_days = MarkingDate - nbStart)
ABCDEFGHIJ0123456789
Stock
<fctr>
MarkingDate
<date>
diff_days
<time>
B2018-01-065 days
E2018-01-087 days
A2018-01-1918 days
E2018-01-2524 days
A2018-01-2726 days
E2018-02-1343 days
A2018-03-0765 days
A2018-03-0967 days
E2018-03-1371 days
A2018-03-1674 days
  • entre (4 dernières dates de marking et 31/12/18)

On séléctionne les 4 dernières valeurs par groupe

df %>% group_by(Stock) %>%
  select(Stock, MarkingDate) %>%
  filter(row_number() %in% c(seq(n() - 3, n()))) %>%
  mutate(diff_days = nbEnd- MarkingDate)
ABCDEFGHIJ0123456789
Stock
<fctr>
MarkingDate
<date>
diff_days
<time>
B2018-01-06359 days
E2018-04-17258 days
E2018-05-07238 days
D2018-07-06178 days
E2018-07-10174 days
B2018-07-11173 days
B2018-07-17167 days
E2018-08-21132 days
A2018-08-27126 days
D2018-09-17105 days
  • cas ou il y a exactement 4 observations + le cas ou il y a moins de 4 observations
    • Je ne comprends pas très bien

Exclure duplicates

Faire les memes KPI que ci-dessus mais cette fois on ne conservant que les marking dates pour lesquelles les valeurs ont bougé (nos fameux carrés).

L’idée est de séléctionner les index des observations qui ont des duplicates ie valeurs identiques. Ensuite, on peut filtrer la data en séléctionnant uniquement les indexes non duplicates

Attention, j’ai crée à la main des valeurs identiques pour faire un test.

PATH2 <- "https://raw.githubusercontent.com/thomaspernet/data_csv_r/master/data/CSAV_data_square.csv"
##### Ci dessous, test avec 2018-01-19 & 2018-01-27 & 2018-08-03 & 2018-08-27 complétements identiques
df_s <-  read.csv(PATH2, sep = ';') %>%
  mutate(MarkingDate = dmy(MarkingDate),
         DateDiv = dmy(DateDiv),
         PayDate = dmy(PayDate)) %>%
  filter(MarkingDate >=nbStart &  MarkingDate <=nbEnd) %>%
  arrange(Stock, MarkingDate)

Juste pour info, voici les duplicates

### For the record: the duplicates
df_s %>% 
  rownames_to_column() %>%
  group_by(Stock, DateDiv,Amount,Yield,PayDate) %>%
  filter(n() > 1)
ABCDEFGHIJ0123456789
rowname
<chr>
Stock
<fctr>
MarkingDate
<date>
DateDiv
<date>
Amount
<fctr>
Yield
<fctr>
PayDate
<date>
1A2018-01-192018-03-270,5041801750,5296917422018-03-29
2A2018-01-192019-03-060,6170893220,8028798812019-03-08
3A2018-01-192021-02-130,2494047780,2147319832021-02-15
4A2018-01-192028-05-250,1693219670,0629939342028-05-27
5A2018-01-192030-07-250,702497010,8301235812030-07-27
6A2018-01-272018-03-270,5041801750,5296917422018-03-29
7A2018-01-272019-03-060,6170893220,8028798812019-03-08
8A2018-01-272021-02-130,2494047780,2147319832021-02-15
9A2018-01-272028-05-250,1693219670,0629939342028-05-27
10A2018-01-272030-07-250,702497010,8301235812030-07-27

Premièrement, on extrait les duplicated indexes

##### Extract index duplicates
index_duplicates <- df_s %>% 
  rownames_to_column() %>%
  group_by(Stock, DateDiv,Amount,Yield,PayDate) %>%
  filter(n() > 1) %>% 
  ungroup()%>%
  select(rowname) %>%
  mutate(rowname = as.integer(rowname))

index_duplicates$rowname
##  [1]  1  2  3  4  5  6  7  8  9 10 15 16 17 18

Ensuite, on filtre la data de base

###### Extract row index of non duplicates
df_s %>%
  filter(!row_number() %in% index_duplicates$rowname)
ABCDEFGHIJ0123456789
Stock
<fctr>
MarkingDate
<date>
DateDiv
<date>
Amount
<fctr>
Yield
<fctr>
PayDate
<date>
A2018-03-072020-10-150,7514024370,9284304072020-10-17
A2018-03-092027-03-090,8046976780,1152143512027-03-11
A2018-03-162027-03-090,9786943760,607002262027-03-11
A2018-05-082024-12-180,9559589640,3482643552024-12-20
A2018-11-072025-01-090,068719760,1566159672025-01-11
A2018-11-262023-11-030,5810736540,2247948752023-11-05
B2018-01-062021-06-090,2366717270,9133830952021-06-11
B2018-07-112027-01-150,4132328140,926653772027-01-17
B2018-07-172023-02-260,4806672670,3577726052023-02-28
D2018-07-062020-01-230,8086555760,4541758832020-01-25