logo

pick, pluck, pull expliqués à ma fille

 

 

pick, pluck, pull expliqués à ma fille

On dirait une comptine pour enfants… J’ai voulu expliquer trois fonctions aux noms cryptiques de {tidyverse} : pick, pluck et pull. J’espère que vous n’allez pas vous endormir avant la fin de l’histoire (spoiler : elle finit bien).

Pick

La fonction dplyr::pick est une alternative au across quand il n’a qu’un seul argument (pour plus d’infos sur across : voir ici). Par exemple dans les calculs “horizontaux” avec des fonctions comme rowSums.

library(dplyr)
mtcars %>% 
  mutate(total = rowSums(pick(where(is.numeric))),
         .before = everything())

 

                      total  mpg cyl  disp  hp drat    wt  qsec vs am gear carb
Mazda RX4           328.980 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag       329.795 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
Datsun 710          259.580 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive      426.135 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
Hornet Sportabout   590.310 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
Valiant             385.540 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
Duster 360          656.920 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
Merc 240D           270.980 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
Merc 230            299.570 22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
Merc 280            350.460 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
Merc 280C           349.660 17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
Merc 450SE          510.740 16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
Merc 450SL          511.500 17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
Merc 450SLC         509.850 15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
Cadillac Fleetwood  728.560 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
Lincoln Continental 726.644 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
Chrysler Imperial   725.695 14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
Fiat 128            213.850 32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
Honda Civic         195.165 30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
Toyota Corolla      206.955 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
Toyota Corona       273.775 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
Dodge Challenger    519.650 15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
AMC Javelin         506.085 15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
Camaro Z28          646.280 13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
Pontiac Firebird    631.175 19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
Fiat X1-9           208.215 27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
Porsche 914-2       272.570 26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
Lotus Europa        273.683 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
Ford Pantera L      670.690 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
Ferrari Dino        379.590 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
Maserati Bora       694.710 15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
Volvo 142E          288.890 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
# même résultat avec across au lieu de pick
mtcars %>% 
  mutate(total = rowSums(across(where(is.numeric))),
         .before = everything())

 

                      total  mpg cyl  disp  hp drat    wt  qsec vs am gear carb
Mazda RX4           328.980 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag       329.795 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
Datsun 710          259.580 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive      426.135 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
Hornet Sportabout   590.310 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
Valiant             385.540 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
Duster 360          656.920 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
Merc 240D           270.980 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
Merc 230            299.570 22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
Merc 280            350.460 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
Merc 280C           349.660 17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
Merc 450SE          510.740 16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
Merc 450SL          511.500 17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
Merc 450SLC         509.850 15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
Cadillac Fleetwood  728.560 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
Lincoln Continental 726.644 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
Chrysler Imperial   725.695 14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
Fiat 128            213.850 32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
Honda Civic         195.165 30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
Toyota Corolla      206.955 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
Toyota Corona       273.775 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
Dodge Challenger    519.650 15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
AMC Javelin         506.085 15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
Camaro Z28          646.280 13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
Pontiac Firebird    631.175 19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
Fiat X1-9           208.215 27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
Porsche 914-2       272.570 26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
Lotus Europa        273.683 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
Ford Pantera L      670.690 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
Ferrari Dino        379.590 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
Maserati Bora       694.710 15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
Volvo 142E          288.890 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2

Comme across on peut également s’en servir dans group_by ou arrange pour intégrer des paramètres qui listent des noms de colonnes sous forme de vecteurs texte.

colonnes <- c("am","vs")
mtcars %>% 
  group_by(pick(all_of({{colonnes}}))) %>% 
  count() %>% 
  ungroup()

 

# A tibble: 4 × 3
     am    vs     n
  <dbl> <dbl> <int>
1     0     0    12
2     0     1     7
3     1     0     6
4     1     1     7

Enfin pick peut servir à utiliser des fonctions comme starts_with, ends_with, contains ou where dans des contextes où elles ne sont pas les bienvenues comme dans count, group_by ou arrange. Là encore, across rend le même service.

try(
  mtcars %>% 
  arrange(starts_with("h"))
  ) # ne fonctionne pas

 

Error in arrange(., starts_with("h")) : 
  ℹ In argument: `..1 = starts_with("h")`.
Caused by error:
! `starts_with()` must be used within a *selecting* function.
ℹ See <https://tidyselect.r-lib.org/reference/faq-selection-context.html> for
  details.
mtcars %>% 
  arrange(pick(starts_with("h")))  # trie selon "hp"

 

                     mpg cyl  disp  hp drat    wt  qsec vs am gear carb
Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
mtcars %>% 
  arrange(across(starts_with("h"))) # fonctionne aussi

 

                     mpg cyl  disp  hp drat    wt  qsec vs am gear carb
Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2
Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8

Pluck

La fonction pluck se trouve dans le package {purrr} intégré à {tidyverse}. Son rôle est de renvoyer un élément de liste, repéré par un numéro ou un nom, comme peuvent le faire les syntaxes de R base [[ ou $.

library(purrr)
mtcars %>% 
  pluck("cyl")  # récupère la colonne "cyl" en tant que vecteur, comme avec mtcars$cyl

 

 [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4

Cette fonction s’avère plus spécialement utile sur une sortie de fonction statistique car ce sont souvent des listes avec une structure complexe.

t.test(mtcars$hp, mu=100) %>% 
  pluck("p.value")  # équivaut à t.test(...)$p.value

 

[1] 0.0005502226

Dans les structures imbriquées, on énumère les différents noms ou indices des éléments à récupérer à la suite les uns des autres, séparés par des virgules.

lapply(mtcars, t.test, mu=100) %>% 
  pluck("hp","p.value")  # équivaut à lapply(mtcars, t.test)$hp$p.value

 

[1] 0.0005502226

Pull

La fonction dplyr::pull permet de récupérer une colonne sous forme de vecteur. En effet, une syntaxe comme select renvoie toujours un data.frame, même s’il ne contient qu’une seule colonne. Alors que pour créer un paramètre ou piloter une boucle, c’est souvent un vecteur qui est demandé.

Comme on vient de le voir, purrr::pluck rend également ce service, avec un usage plus général, puisqu’il s’applique à une liste en général. pull s’applique uniquement à des data.frames.

mtcars %>% 
  distinct(cyl) %>% 
  pull()

 

[1] 6 4 8
# en R base
unique(mtcars$cyl)

 

[1] 6 4 8
# sans pull() le résultat est un data.frame à 1 colonne
mtcars %>% 
  distinct(cyl)

 

                  cyl
Mazda RX4           6
Datsun 710          4
Hornet Sportabout   8

En revanche, pull pourra s’appliquer à un lazy data.frame comme ce que renvoie la fonction tbl qui manipule des liens vers des tables dans des bases de données.

library(duckdb)

bd <- dbConnect(duckdb())
duckdb_register(bd, "table_mtcars", mtcars)
lien_vers_mtcars <- tbl(bd, "table_mtcars")

lien_vers_mtcars %>% 
  distinct(cyl) %>% 
  pull()

 

[1] 8 4 6
lien_vers_mtcars %>% 
  distinct(cyl) %>% 
  pluck(1) # le résultat est différent car la liste contient une requête, pas les données issues de l'exécution de la requête (c'est une lazy query)

 

src:  DuckDB 1.4.4 [PC@Windows 10 x64:R 4.5.2/:memory:]
tbls: table_mtcars

Configuration de R pour le code de cet article

sessionInfo()

 

R version 4.5.2 (2025-10-31 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 10 x64 (build 19045)

Matrix products: default
  LAPACK version 3.12.1

locale:
[1] LC_COLLATE=French_France.utf8  LC_CTYPE=French_France.utf8   
[3] LC_MONETARY=French_France.utf8 LC_NUMERIC=C                  
[5] LC_TIME=French_France.utf8    

time zone: Europe/Paris
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] duckdb_1.4.4 DBI_1.3.0    purrr_1.2.2  dplyr_1.2.1 

loaded via a namespace (and not attached):
 [1] vctrs_0.7.3       cli_3.6.5         knitr_1.51        rlang_1.2.0      
 [5] xfun_0.59         otel_0.2.0        generics_0.1.4    jsonlite_2.0.0   
 [9] glue_1.8.1        dbplyr_2.5.2      htmltools_0.5.8.1 rmarkdown_2.29   
[13] evaluate_1.0.5    tibble_3.3.0      fastmap_1.2.0     yaml_2.3.12      
[17] lifecycle_1.0.5   compiler_4.5.2    blob_1.2.4        htmlwidgets_1.6.4
[21] pkgconfig_2.0.3   rstudioapi_0.19.0 digest_0.6.37     R6_2.6.1         
[25] tidyselect_1.2.1  pillar_1.11.0     magrittr_2.0.3    tools_4.5.2      
[29] withr_3.0.3      


0 found this helpful