4 votes

Comment remplacer `cur_data()` par `pick()` lors de l'ajout d'une ligne à chaque groupe dans un dataframe

Je vois que dans dplyr la fonction cur_data() a été abandonnée en faveur de pick(). Cependant, je suis confus sur la manière d'utiliser pick() pour ajouter des lignes à chaque groupe dans un dataframe groupé. Je nettoie des données farfelues et j'ai besoin d'insérer des lignes dans chaque groupe qui propagent la valeur de la variable de regroupement tout en insérant une valeur spécifique dans une colonne accompagnante.

Voici un exemple de code qui utilise cur_data() pour produire la sortie souhaitée :

df <- tibble::tribble(
  ~id,   ~val,
  "A",   95,
  "A",   20,
  "A",   45,
  "B",   10,
  "B",   50,
  "C",   80
)

df_new_rows <- df |>
  dplyr::group_by(id) |>
  dplyr::reframe(tibble::add_row(dplyr::cur_data(), val = 100)) |>
  dplyr::ungroup()

Voici la sortie souhaitée - les lignes avec 100 dans la colonne val ont été insérées :

# A tibble: 9 × 2
  id      val

1 A        95
2 A        20
3 A        45
4 A       100
5 B        10
6 B        50
7 B       100
8 C        80
9 C       100

Comment puis-je utiliser pick() ou une autre fonction pour faire cela? Pour des raisons de développement, j'aimerais utiliser des fonctions de base de R ou de tidyverse, mais s'il n'y a pas moyen de le faire, je suis ouvert à d'autres suggestions. Merci d'avance pour toute aide!

6voto

Newbee Points 65

Vous pouvez utiliser le group_modify() pour appliquer une fonction à chaque groupe dans un tibble groupé et retourner un tibble groupé.

df <- tibble::tibble(
 id = c("A", "A", "A", "B", "B", "C"),
 val = c(95, 20, 45, 10, 50, 80)
)

add_row_func <- function(df) {
 tibble::add_row(df, id = df$id[1], val = 100)
}

df_new_rows <- df |>
 dplyr::group_by(id) |>
 dplyr::group_modify(add_row_func) |>
 dplyr::ungroup()

print(df_new_rows)

3voto

G. Grothendieck Points 40825

1) Essayez nest_by qui crée un tibble à 3 lignes avec tout sauf id dans une colonne de liste data.

library(dplyr)

df |>
  nest_by(id) |>
  reframe(add_row(data, val = 100))

résultat:

# A tibble: 9 × 2
  id      val

1 A        95
2 A        20
3 A        45
4 A       100
5 B        10
6 B        50
7 B       100
8 C        80
9 C       100

2) ou ceci qui donne la même sortie

df |>
  reframe(add_row(pick(everything()), val = 100), .by = id)

3) Ceci est une solution en base R. Définissez une fonction AddRow pour ajouter une ligne à un composant du split, puis utilisez by pour effectuer le split et enfin do.call avec rbind pour le remettre ensemble.

AddRow <- function(x, ...) rbind(x, transform(x[1, ], ...))
do.call("rbind", by(df, df$id, AddRow, val = 10))

4) Ceci est une autre approche en base R. Elle s'applique si l'entrée df a deux colonnes comme c'est le cas ici. Utilisez tapply pour diviser val par id en ajoutant 10 à chaque composant résultant. Ensuite, utilisez stack pour convertir en forme longue. stack place les colonnes id en deuxième position et renomme cette colonne ind. Il place également la colonne val en premier et la renomme valeurs, utilisez donc rev pour les intervertir puis ajoutez les noms d'origine.

df2 <- df |>  with(tapply(val, id, append, 10)) |> stack() |> rev()
names(df2) <- names(df)
df2

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X