copier des lignes si un id est identique

Postez ici vos questions, réponses, commentaires ou suggestions - Les sujets seront ultérieurement répartis dans les archives par les modérateurs

Modérateur : Groupe des modérateurs

raph menajovsky
Messages : 59
Enregistré le : 04 Déc 2019, 14:44

copier des lignes si un id est identique

Messagepar raph menajovsky » 10 Fév 2020, 10:03

Bonjour,

Mon dataframe a des identifiants pour chaque personne, chaque personne étant renseignée par ses différentes commandes. J'ai différentes lignes par commande avec le détail des commandes, mais l'identifiant de chaque personne n'est mis que sur 1 ligne : j'aimerais, pour chaque numéro de commande (Order.ID), copier le User.id indiqué sur la 1e mention de l'Order.ID (quand il y a un User.id) sur toutes les lignes avec le même Order.ID. Comment faire ?

Voici un extrait de mon df :
structure(list(Order.ID = c(134917292L, 134917428L, 134917428L,
134917428L, 134917428L, 134917428L, 134917428L, 134916893L, 134916893L,
134917011L, 134917365L, 134917365L, 134916625L, 134916625L, 134917256L,
134917256L, 134916893L, 134917256L), User.id = c(3957163L, 10874430L,
NA, NA, NA, NA, NA, 6032976L, NA, NA, 6899232L, NA, NA, NA, 6899232L,
6899232L, 6899232L, 6899232L)), row.names = 607:624, class = "data.frame")

J'aimerais dans cet exemple :
- garder le User.id pour l'Order.ID = 134917292
- copier les User.id sur toutes les lignes où l'Order.ID est identique (ex : copier le User.id=10874430 sur toutes les lignes où l'Order.ID=134917428, copier le User.id=6032976 sur toutes les lignes où l'Order.ID=134916893, etc)
- il est possible qu'un même User.id ait passé plusieurs commandes avec plusieurs Order.ID (comme le 6899232 dans mon exemple) : dans ce cas, j'aimerais que le User.id copié soit à chaque fois celui qui est indiqué lors de la 1e mention de l'Order.ID (on peut classer les data par Order.ID si besoin)
- mettre un User.id vide (plutôt que NA, si possible), où les Order.ID n'ont pas de User.id renseignés (ex : 134917011, 134916625)
- précision : le fichier entier fait 150 000 lignes

Est-ce que quelqu'un saurait comment faire ca ?

je vous remercie
raphm

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: copier des lignes si un id est identique

Messagepar Pierre-Yves Berrard » 10 Fév 2020, 13:13

Bonjour,

J'utiliserais la fonction fill du package tidyr.

Cette fonction remplit toutes les cases vides à partir de la première case non vide située plus haut.
Il faut donc au préalable trier les données par Order.id, puis par valeur non vide dans User.id.

Il faut certainement faire un traitement à part pour les Order.id sans User.id. Première idée : les enlever, traiter les autres, puis les remettre ?
PY

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: copier des lignes si un id est identique

Messagepar Pierre-Yves Berrard » 10 Fév 2020, 13:47

On peut certainement gérer les cas particuliers directement :

Code : Tout sélectionner

library(dplyr)
library(tidyr)

donnees %>%
  group_by(Order.ID) %>%
  mutate(
    User.id = if (all(is.na(User.id))) -1 else User.id  # -1 car User.id est numérique...
  ) %>%   
  arrange(Order.ID, is.na(User.id)) %>%
  fill(User.id)
PY

raph menajovsky
Messages : 59
Enregistré le : 04 Déc 2019, 14:44

Re: copier des lignes si un id est identique

Messagepar raph menajovsky » 11 Fév 2020, 08:43

Bonjour Pierre-Yves,

Merci beaucoup pour ces 2 éléments de réponse.
Cela semble faire en effet tout ce dont j'ai besoin !

Juste une petite limite : on dirait que la fonction fill donne le résultat dans la console mais ne remplit pas mon dataframe : est-ce bien le cas ? Comment faire pour que les données s'écrivent dans le df ?

je vous remercie,
raphm

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: copier des lignes si un id est identique

Messagepar Pierre-Yves Berrard » 11 Fév 2020, 08:46

Affecter à un nouvel objet :

Code : Tout sélectionner

donnees2 <- donnees %>% ...

Ou utiliser le même nom à gauche pour écraser.
PY

raph menajovsky
Messages : 59
Enregistré le : 04 Déc 2019, 14:44

Re: copier des lignes si un id est identique

Messagepar raph menajovsky » 11 Fév 2020, 09:15

c'était simple, je m'en veux de vous avoir dérangé pour si peu.
Merci beaucoup Pierre-Yves pour votre aide et votre réactivité !
très bonne journée,
raphm

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Re: copier des lignes si un id est identique

Messagepar Logez Maxime » 11 Fév 2020, 13:33

Bonjour,

Pour éviter ce genre de choses tu peux utiliser l'opérateur "%<>%".
J'en suis pas fan parce que je trouve que ça manque de lisibilité dans un code, je préfère la combinaison des opérateurs "<-" et "%>%".

Code : Tout sélectionner

donnees %<>%
  group_by(Order.ID) %>%
  mutate(
    User.id = if (all(is.na(User.id))) -1 else User.id  # -1 car User.id est numérique...
  ) %>%   
  arrange(Order.ID, is.na(User.id)) %>%
  fill(User.id)
Cordialement,
Maxime

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: copier des lignes si un id est identique

Messagepar Pierre-Yves Berrard » 11 Fév 2020, 13:42

Logez Maxime a écrit :Pour éviter ce genre de choses tu peux utiliser l'opérateur "%<>%".
J'en suis pas fan parce que je trouve que ça manque de lisibilité dans un code, je préfère la combinaison des opérateurs "<-" et "%>%".

Il te faudra de plus charger magrittr.
PY

Franck Theeten
Messages : 17
Enregistré le : 07 Fév 2020, 17:09

Re: copier des lignes si un id est identique

Messagepar Franck Theeten » 12 Fév 2020, 20:12

Bonjour,

Voici une version sans importation de package et avec un appel à "apply" de la jointure sur les Order.id (entre User.id non-définis et User.id connus) qui pourrait fonctionner:

Code : Tout sélectionner

idx<-which(!is.na(df$User.id))
df2<-df[idx, ]

apply(df2, 1,
function(x)
{

    tmp<-which(df[1]==as.numeric(x[1]))   
    df[rownames(df)[tmp],2]<<-x[2]   
}
)



Et sans tableau intermédiaire :

Code : Tout sélectionner

apply(df[which(!is.na(df$User.id)), ], 1,
function(x)
{

    tmp<-which(df[1]==as.numeric(x[1]))   
    df[rownames(df)[tmp],2]<<-x[2]   
}
)


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité