R avancé et introduction à Git

Données, textes, dates

Données, Texte, Dates

Lire des données

Fichiers plats (.txt, .csv)

Traditionnellement, les fichiers de données de petite taille sont disponibles au format .csv ou .txt

# base R
read.csv()
read.table()
# R package readr
readr::read_csv()
# autres solutions :
data.table::fread()
vroom::vroom()
arrow::read_csv()

Warning

Même s’il est possible d’importer des données directement depuis RStudio, il est primordial de coder les imports pour rendre les études reproductibles.

Fichiers .json

Format omni-présent sur le web. Permet de représenter des données hiérarchiques.

{"employees":[
  { "firstName":"John", "lastName":"Doe" },
  { "firstName":"Anna", "lastName":"Smith" },
  { "firstName":"Peter", "lastName":"Jones" }
]}

Pour lire/écrire les fichiers JSON, on utilisera en priorité la librairie jsonlite.

library(jsonlite)
read_json("some_json_file.json")
?fromJSON()
?toJSON()

Vous rencontrerez aussi les fichiers GeoJSON pour des données SIG.

Lire un fichier parquet

Format parquet, très utilisé pour le traitement des “big data” car très léger.

library(arrow)

data(mtcars)
arrow::write_parquet(mtcars, sink = "mtcars.parquet")
arrow::read_parquet(file = "mtcars.parquet")
  • Stockage orienté colonne
  • Fichier binaire compressé, efficient et typé
  • Devient très courant, format de référence dans les data lake, lisible en python (pandas.read_parquet)

Requêter une base de données

Enfin, de nos jours, beaucoup de données d’analyse résident dans des bases de données, souvent dites relationnelles.

En R, le backend DBI a été développé pour fournir une interface unique à de nombreux systèmes de bases de données ou data warehouse existants : mysql, postgresql, snowflake, etc.

library(DBI)
# Create an ephemeral in-memory RSQLite database
con <- dbConnect(RSQLite::SQLite(), dbname = ":memory:")

dbListTables(con)
dbWriteTable(con, "mtcars", mtcars)
dbListTables(con)
dbListFields(con, "mtcars")

Requêter une base de données

library(DBI)
# Create an ephemeral in-memory RSQLite database
con <- dbConnect(RSQLite::SQLite(), dbname = ":memory:")

dbListTables(con)
character(0)
dbWriteTable(con, "mtcars", mtcars)
dbListTables(con)
[1] "mtcars"
dbListFields(con, "mtcars")
 [1] "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear"
[11] "carb"

Requêter une base de données

On peut requêter directement en SQL

res_sql <- dbSendQuery(con, "SELECT * from mtcars LIMIT 2")
dbFetch(res_sql)
  mpg cyl disp  hp drat    wt  qsec vs am gear carb
1  21   6  160 110  3.9 2.620 16.46  0  1    4    4
2  21   6  160 110  3.9 2.875 17.02  0  1    4    4

Requêter une base de données

Ou laisser {dplyr} faire le travail avec {dbplyr}

library(dplyr)
library(dbplyr)
res_tidy  <- tbl(con, "mtcars")  |> head(n = 2)
res_tidy  |> collect()
# A tibble: 2 × 11
    mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1    21     6   160   110   3.9  2.62  16.5     0     1     4     4
2    21     6   160   110   3.9  2.88  17.0     0     1     4     4
show_query(res_tidy)
<SQL>
SELECT `mtcars`.*
FROM `mtcars`
LIMIT 2

Requêter une base de données

Penser à terminer proprement vos connections aux BDD.

# Close connection
dbClearResult(res_sql)
dbDisconnect(con)

Données ouvertes

Pour explorer des API web, on utilise le package {httr2}.

Ici, on requête l’API Melodi de l’Insee sur les données de prénoms (l’exploration préalable de la doc Swagger peut aider à tester sa requête).

library(httr2)
req <- request("https://api.insee.fr/melodi/data/") |>
    req_url_path_append("DS_PRENOM") |>
    req_url_query(FIRST_NAME = "FOULQUES", TIME_PERIOD = 2024)

resp <- req_perform(req)
resp
<httr2_response>
GET https://api.insee.fr/melodi/data/DS_PRENOM?FIRST_NAME=FOULQUES&TIME_PERIOD=2024
Status: 200 OK
Content-Type: application/json
Body: In memory (989 bytes)

Données ouvertes

La sortie est généralement sous format JSON, que l’on peut ensuite extraire en data.frame.

resp |>
    resp_body_json(simplifyVector = TRUE) |>
    purrr::pluck("observations") |>
    as_tibble()
# A tibble: 2 × 2
  dimensions$GEO $SEX  $TIME_PERIOD $FIRST_NAME measures$OBS_VALUE_NIVEAU$value
  <chr>          <chr> <chr>        <chr>                                 <dbl>
1 2024-REG-52    M     2024         FOULQUES                                  5
2 2024-FRANCE-F  M     2024         FOULQUES                                  5

Note

Si vous avez envie de gratter encore plus le web, aller creuser les outils de scraping comme {rvest}.

Manipulation de dataframes

data.frame

En R, les data.frame sont un élément essentiel du succès du langage pour le traitement des données.

df <- data.frame(col1 = c(1, 2, 3), col2 = c("a", "b", "c"))
class(df)
[1] "data.frame"
str(df, 1)
'data.frame':   3 obs. of  2 variables:
 $ col1: num  1 2 3
 $ col2: chr  "a" "b" "c"

tibble

library(dplyr)

data(starwars)
class(starwars)
[1] "tbl_df"     "tbl"        "data.frame"
head(starwars, 4)
# A tibble: 4 × 14
  name      height  mass hair_color skin_color eye_color birth_year sex   gender
  <chr>      <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
1 Luke Sky…    172    77 blond      fair       blue            19   male  mascu…
2 C-3PO        167    75 <NA>       gold       yellow         112   none  mascu…
3 R2-D2         96    32 <NA>       white, bl… red             33   none  mascu…
4 Darth Va…    202   136 none       white      yellow          41.9 male  mascu…
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
#   vehicles <list>, starships <list>

tibble

class(starwars) <- "data.frame"
head(starwars, 4)
            name height mass hair_color  skin_color eye_color birth_year  sex
1 Luke Skywalker    172   77      blond        fair      blue       19.0 male
2          C-3PO    167   75       <NA>        gold    yellow      112.0 none
3          R2-D2     96   32       <NA> white, blue       red       33.0 none
4    Darth Vader    202  136       none       white    yellow       41.9 male
     gender homeworld species
1 masculine  Tatooine   Human
2 masculine  Tatooine   Droid
3 masculine     Naboo   Droid
4 masculine  Tatooine   Human
                                                                                                                                      films
1                                           A New Hope, The Empire Strikes Back, Return of the Jedi, Revenge of the Sith, The Force Awakens
2                    A New Hope, The Empire Strikes Back, Return of the Jedi, The Phantom Menace, Attack of the Clones, Revenge of the Sith
3 A New Hope, The Empire Strikes Back, Return of the Jedi, The Phantom Menace, Attack of the Clones, Revenge of the Sith, The Force Awakens
4                                                              A New Hope, The Empire Strikes Back, Return of the Jedi, Revenge of the Sith
                            vehicles                starships
1 Snowspeeder, Imperial Speeder Bike X-wing, Imperial shuttle
2                                                            
3                                                            
4                                             TIE Advanced x1

tibble

class(starwars) <- "data.frame"
head(starwars, 4)

tibble

  • tibble surcharge les data.frame classiques
  • meilleur print, meilleurs “défauts”
class(starwars[, 1])
class(as.tibble(starwars)[, 1])

tibble

  • tibble surcharge les data.frame classiques
  • meilleur print, meilleurs “défauts”
class(starwars[, 1])
[1] "character"
class(as_tibble(starwars)[, 1])
[1] "tbl_df"     "tbl"        "data.frame"
  • tibble renvoie une data.frame à une colonne
  • data.frame renvoie un vecteur

dplyr

dplyr

starwars %>%
    filter(species == "Droid")

dplyr

starwars %>%
    filter(species == "Droid")
# A tibble: 6 × 14
  name   height  mass hair_color skin_color  eye_color birth_year sex   gender  
  <chr>   <int> <dbl> <chr>      <chr>       <chr>          <dbl> <chr> <chr>   
1 C-3PO     167    75 <NA>       gold        yellow           112 none  masculi…
2 R2-D2      96    32 <NA>       white, blue red               33 none  masculi…
3 R5-D4      97    32 <NA>       white, red  red               NA none  masculi…
4 IG-88     200   140 none       metal       red               15 none  masculi…
5 R4-P17     96    NA none       silver, red red, blue         NA none  feminine
6 BB8        NA    NA none       none        black             NA none  masculi…
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
#   vehicles <list>, starships <list>

dplyr

starwars %>%
    select(name, ends_with("color"))

dplyr

starwars %>%
    select(name, ends_with("color"))
# A tibble: 87 × 4
   name               hair_color    skin_color  eye_color
   <chr>              <chr>         <chr>       <chr>    
 1 Luke Skywalker     blond         fair        blue     
 2 C-3PO              <NA>          gold        yellow   
 3 R2-D2              <NA>          white, blue red      
 4 Darth Vader        none          white       yellow   
 5 Leia Organa        brown         light       brown    
 6 Owen Lars          brown, grey   light       blue     
 7 Beru Whitesun Lars brown         light       blue     
 8 R5-D4              <NA>          white, red  red      
 9 Biggs Darklighter  black         light       brown    
10 Obi-Wan Kenobi     auburn, white fair        blue-gray
# ℹ 77 more rows

dplyr

starwars %>%
    mutate(name, bmi = mass / ((height / 100)^2)) %>%
    select(name:mass, bmi)

dplyr

starwars %>%
    mutate(name, bmi = mass / ((height / 100)^2)) %>%
    select(name:mass, bmi)
# A tibble: 87 × 4
   name               height  mass   bmi
   <chr>               <int> <dbl> <dbl>
 1 Luke Skywalker        172    77  26.0
 2 C-3PO                 167    75  26.9
 3 R2-D2                  96    32  34.7
 4 Darth Vader           202   136  33.3
 5 Leia Organa           150    49  21.8
 6 Owen Lars             178   120  37.9
 7 Beru Whitesun Lars    165    75  27.5
 8 R5-D4                  97    32  34.0
 9 Biggs Darklighter     183    84  25.1
10 Obi-Wan Kenobi        182    77  23.2
# ℹ 77 more rows

dplyr

starwars %>%
    arrange(desc(mass))

dplyr

starwars %>%
    arrange(desc(mass))
# A tibble: 87 × 14
   name     height  mass hair_color skin_color eye_color birth_year sex   gender
   <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
 1 Jabba D…    175  1358 <NA>       green-tan… orange         600   herm… mascu…
 2 Grievous    216   159 none       brown, wh… green, y…       NA   male  mascu…
 3 IG-88       200   140 none       metal      red             15   none  mascu…
 4 Darth V…    202   136 none       white      yellow          41.9 male  mascu…
 5 Tarfful     234   136 brown      brown      blue            NA   male  mascu…
 6 Owen La…    178   120 brown, gr… light      blue            52   male  mascu…
 7 Bossk       190   113 none       green      red             53   male  mascu…
 8 Chewbac…    228   112 brown      unknown    blue           200   male  mascu…
 9 Jek Ton…    180   110 brown      fair       blue            NA   <NA>  <NA>  
10 Dexter …    198   102 none       brown      yellow          NA   male  mascu…
# ℹ 77 more rows
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
#   vehicles <list>, starships <list>

dplyr

starwars %>%
    group_by(species) %>%
    summarise(
        n = n(),
        mass = mean(mass, na.rm = TRUE)
    ) %>%
    filter(
        n > 1,
        mass > 50
    )

dplyr

starwars %>%
    group_by(species) %>%
    summarise(
        n = n(),
        mass = mean(mass, na.rm = TRUE)
    ) %>%
    filter(
        n > 1,
        mass > 50
    )
# A tibble: 9 × 3
  species      n  mass
  <chr>    <int> <dbl>
1 Droid        6  69.8
2 Gungan       3  74  
3 Human       35  81.3
4 Kaminoan     2  88  
5 Mirialan     2  53.1
6 Twi'lek      2  55  
7 Wookiee      2 124  
8 Zabrak       2  80  
9 <NA>         4  81  

dplyr : jointures

Les jointures: left_join, right_join, full_join, inner_join Concaténation de tables: bind_rows, bind_columns

SQL

Vocabulaire des verbes tiré du SQL, voir par exemple : Ici

Données textuelles

Manipulation de chaines de caractères

Élément important des tâches de manipulation de données, de nettoyage, de transformation, souvent basé sur les expressions régulières.

En R base, possibilité de manipuler des chaînes de caractères, mais :

  • API des fonctions inconsistantes
  • naming difficile à comprendre
  • documentation parfois cryptique

Manipulation de chaines de caractères

Élément important des tâches de manipulation de données, de nettoyage, de transformation, souvent basé sur les expressions régulières.

En R base, possibilité de manipuler des chaînes de caractères, mais :

  • API des fonctions inconsistantes
  • naming difficile à comprendre
  • documentation parfois cryptique
  • une librairie user friendly : stringr

Expressions régulières

Simple match :

library(stringr)
x <- c("apple", "banana", "pear")
str_view(x, "an")
[2] │ b<an><an>a

Expressions régulières

“.” match tous les caractères

x <- c("apple", "banana", "pear")
str_view(x, ".a.")
[2] │ <ban>ana
[3] │ p<ear>

Expressions régulières

Escaping avec le symbole \ :

str_view(c("abc", "a.c", "bef"), "a\\.c")
[2] │ <a.c>

Expressions régulières

  • \d : match tous les symboles numériques
str_view_all("10 + 20 = 30", "\\d+")
[1] │ <10> + <20> = <30>

Expressions régulières

  • \s : caractères d’espacement
(text <- "Some  \t badly\n\t\tspaced \f text")
[1] "Some  \t badly\n\t\tspaced \f text"
str_replace_all(text, "\\s+", " ")
[1] "Some badly spaced text"

Expressions régulières

  • \w et \W : mots
str_extract_all("Don't eat that!", "\\w+")[[1]]
[1] "Don"  "t"    "eat"  "that"
str_split("Don't eat that!", "\\W")[[1]]
[1] "Don"  "t"    "eat"  "that" ""    

Expressions régulières

  • [abc] : match a, b, c
  • [a-z] : match tous les caractères minuscules
  • [^abc] : match tous les caractères exceptés a, b, c
  • [\^\-] : match les caractères ^ et -

Expressions régulières

  • [abc] : match a, b, c
  • [a-z] : match tous les caractères minuscules
  • [^abc] : match tous les caractères exceptés a, b, c
  • [\^\-] : match les caractères ^ et -

Voir R et expressions régulières

Fonctions stringr vs R base

stringr base R
str_detect(string, pattern) grepl(pattern, x)
str_dup(string, times) strrep(x, times)
str_extract(string, pattern) regmatches(x, m = regexpr(pattern, text))
str_extract_all(string, pattern) regmatches(x, m = gregexpr(pattern, text))
str_length(string) nchar(x)

Fonctions stringr vs R base

stringr base R
str_locate(string, pattern) regexpr(pattern, text)
str_locate_all(string, pattern) gregexpr(pattern, text)
str_match(string, pattern) regmatches(x, m = regexec(pattern, text))
str_order(string) order(…)
str_replace(string, pattern, replacement) sub(pattern, replacement, x)
str_replace_all(string, pattern, replacement) gsub(pattern, replacement, x)
stringr base R
str_sort(string) sort(x)
str_split(string, pattern) strsplit(x, split)
str_sub(string, start, end) substr(x, start, stop)
str_subset(string, pattern) grep(pattern, x, value = TRUE)
str_to_lower(string) tolower(x)
str_to_title(string) tools::toTitleCase(text)
str_to_upper(string) toupper(x)
str_trim(string) trimws(x)
str_which(string, pattern) grep(pattern, x)
str_wrap(string) strwrap(x)

Données calendaires

Unix time

L’heure Unix ou heure Posix est une mesure du temps fondée sur le nombre de secondes écoulées depuis le 1er janvier 1970 00:00:00 UTC, hors secondes intercalaires. Elle est utilisée principalement dans les systèmes qui respectent la norme POSIX, dont les systèmes de type Unix, d’où son nom. C’est la représentation POSIX du temps.

Timezone & UTC

Est-ce une date valide ?

"2022-01-01 03:40:54"
  • Importance des timezones
  • Universal Time Coordinated

UTC

Le temps universel coordonné ou UTC (en anglais : coordinated universal time) est une échelle de temps adoptée comme base du temps civil international par la majorité des pays du globe.

R base vs lubridate

Les dates sont des objets très fréquents et essentiels dans de multiple projets de datascience :

  • séries temporelles
  • données et messages horodatés

Il est possible de manipuler des objets de date en R base, mais lubridate propose une API plus consistante et accessible et peut faciliter vos traitements de données.

“Parsing” de dates

ymd(
    ...,
    quiet = FALSE,
    tz = NULL,
    locale = Sys.getlocale("LC_TIME"),
    truncated = 0
)

Exemple :

library(lubridate)
date <- ymd("2020-02-22")
str(date)
 Date[1:1], format: "2020-02-22"

Extraction d’éléments

date <- ymd("2020-02-22")
year(date)
month(date)
isoweek(date)
minute(date)

Extraction d’éléments

date <- ymd("2020-02-22")
year(date)
[1] 2020
month(date)
[1] 2
isoweek(date)
[1] 8
minute(date)
[1] 0

Extraction d’éléments

date <- ymd("2020-02-22")
wday(date)
Sys.setlocale(category = "LC_ALL", locale = "de_DE.UTF-8")
date <- ymd("2020-02-22")
wday(date, label = TRUE, abbr = FALSE)
Sys.setlocale(category = "LC_ALL", locale = "en_US.UTF-8")

Extraction d’éléments

date <- ymd("2020-02-22")
wday(date)
[1] 7
Sys.setlocale(category = "LC_ALL", locale = "de_DE.UTF-8")
[1] ""
date <- ymd("2020-02-22")
wday(date, label = TRUE, abbr = FALSE)
[1] Saturday
7 Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < ... < Saturday
format_ISO8601(as.POSIXct("2018-02-01 03:04:05", tz = "EST"), usetz = TRUE)
[1] "2018-02-01T03:04:05-0500"

Interval, duration, period

  • interval : période temporelle entre deux dates
  • duration : durée définie en temps calendaire “humain” : en jours, en semaines, en mois..
  • period : durée définie en nombre de secondes

Questions ?