IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

R Discussion :

premier et dernier élément


Sujet :

R

  1. #1
    Membre actif
    Inscrit en
    Novembre 2003
    Messages
    543
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 543
    Points : 239
    Points
    239
    Par défaut premier et dernier élément
    Bonjour,

    Je dispose d'un data.frame trié selon des numéros de personnes.
    Chaque personne peut être présente sur plusieurs lignes successives.

    Y a-t-il une commande simple, et sans faire de boucle, pour sélectionner la 1ère occurence d'une personne ou la dernière.
    Je me souviens que sous SAS, il existait une commande first.Variable ou last.Variable qui permettait de faire ce genre de sélection.
    Y a-til quelque chose de comparable sous R ?

    Merci

  2. #2
    Membre du Club
    Homme Profil pro
    Formateur et consultant R
    Inscrit en
    Juin 2020
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formateur et consultant R
    Secteur : Conseil

    Informations forums :
    Inscription : Juin 2020
    Messages : 36
    Points : 69
    Points
    69
    Par défaut
    Bonjour,

    Vous pouvez utiliser first() et last() dans {dplyr} par exemple, mais il faudrait surement associer cela avec un filter().
    Pouvez-vous partager un exemple reproductible pour votre jeu de données avec les données en entrée et le résultat escompté en sortie pour mieux vous guider ?

    Pour faire un bon exemple reproductible, vous pouvez regarder ici: https://thinkr.fr/reprex-ou-comment-...-efficacement/

  3. #3
    Expert confirmé
    Avatar de olivier.decourt
    Homme Profil pro
    Formateur R/SAS/statistiques
    Inscrit en
    Avril 2008
    Messages
    2 064
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Activité : Formateur R/SAS/statistiques
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 064
    Points : 4 478
    Points
    4 478
    Par défaut
    Bonjour Enicnath.
    Effectivement {dplyr} propose des choses assez simples pour faire l'équivalent des SET BY / FIRST ou LAST de SAS. Il faut combiner un group_by (pour travailler par blocs) et un slice (pour prendre la n-ième ligne). Pour FIRST c'est simple, c'est la ligne 1 ; pour LAST, il faut compter les lignes du bloc avec la fonction n().
    Enfin, ne pas oublier de dégrouper les données pour avoir un comportement global du data.frame ensuite, et pas un comportement par blocs.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    library(dplyr)
     
    iris %>% 
      group_by(Species) %>% 
      slice(1) %>% # 1e ligne de chaque groupe
      ungroup()
     
    iris %>% 
      group_by(Species) %>% 
      slice(n()) %>% # dernière ligne de chaque groupe
      ungroup()
    Bon courage.
    Olivier

  4. #4
    Membre actif
    Inscrit en
    Novembre 2003
    Messages
    543
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 543
    Points : 239
    Points
    239
    Par défaut
    Bonjour à tous les deux
    Ca sera pour moi une occasion d'utiliser dplyr, que je n'ai pas eu besoin d'utiliser jusqu'à maintenant.
    Merci pour votre aide.

  5. #5
    Membre expérimenté
    Inscrit en
    Novembre 2009
    Messages
    703
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 703
    Points : 1 311
    Points
    1 311
    Par défaut first, last
    Bonjour,

    Une autre solution :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    myBys <- data.frame(iris$Species)
     
    myfirstList <- by(iris, myBys, head, n=1)
    do.call(rbind, myfirstList)
    #>            Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> setosa              5.1         3.5          1.4         0.2     setosa
    #> versicolor          7.0         3.2          4.7         1.4 versicolor
    #> virginica           6.3         3.3          6.0         2.5  virginica
     
    mylastList <- by(iris, myBys, tail, n=1)
    do.call(rbind, mylastList)
    #>            Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> setosa              5.0         3.3          1.4         0.2     setosa
    #> versicolor          5.7         2.8          4.1         1.3 versicolor
    #> virginica           5.9         3.0          5.1         1.8  virginica
     
    # [Created on 2021-01-11 by the reprex package (v0.3.0)
    (Solution proposée dans le livre R for SAS and SPSS users de Robert A. Muenchen)

    Cordialement,

  6. #6
    Membre actif
    Inscrit en
    Novembre 2003
    Messages
    543
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 543
    Points : 239
    Points
    239
    Par défaut
    Ouah, super !
    Merci mgdondon
    C'est une solution qui me semble vraiment élégante (quoique difficile à bien comprendre pour moi qui ne maîtrise pas les do.call)

  7. #7
    Membre expérimenté
    Inscrit en
    Novembre 2009
    Messages
    703
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 703
    Points : 1 311
    Points
    1 311
    Par défaut first, last
    Bonjour,

    La fonction do.call(rbind,) sert ici à transformer le résultat de la fonction by() en dataframe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    myBys <- data.frame(iris$Species)
    myfirstList <- by(iris, myBys, head, n=1)
    myfirstList
    #> iris.Species: setosa
    #>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
    #> 1          5.1         3.5          1.4         0.2  setosa
    #> ------------------------------------------------------------ 
    #> iris.Species: versicolor
    #>    Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> 51            7         3.2          4.7         1.4 versicolor
    #> ------------------------------------------------------------ 
    #> iris.Species: virginica
    #>     Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
    #> 101          6.3         3.3            6         2.5 virginica
     
    do.call(rbind, myfirstList)
    #>            Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> setosa              5.1         3.5          1.4         0.2     setosa
    #> versicolor          7.0         3.2          4.7         1.4 versicolor
    #> virginica           6.3         3.3          6.0         2.5  virginica
    Ceci me fait penser qu'il est possible d'obtenir le même résultat avec la fonction aggregate() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    aggregate(. ~ Species, data=iris, head, n=1)
    #>      Species Sepal.Length Sepal.Width Petal.Length Petal.Width
    #> 1     setosa          5.1         3.5          1.4         0.2
    #> 2 versicolor          7.0         3.2          4.7         1.4
    #> 3  virginica          6.3         3.3          6.0         2.5
     
    aggregate(. ~ Species, data=iris, tail, n=1)
    #>      Species Sepal.Length Sepal.Width Petal.Length Petal.Width
    #> 1     setosa          5.0         3.3          1.4         0.2
    #> 2 versicolor          5.7         2.8          4.1         1.3
    #> 3  virginica          5.9         3.0          5.1         1.8
    Mais la solution avec la fonction by() est plus générale et permet de sélectionner plusieurs lignes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    myBys <- data.frame(iris$Species)
    myfirstList <- by(iris, myBys, head, n=2)
    do.call(rbind, myfirstList)
    #>               Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> setosa.1               5.1         3.5          1.4         0.2     setosa
    #> setosa.2               4.9         3.0          1.4         0.2     setosa
    #> versicolor.51          7.0         3.2          4.7         1.4 versicolor
    #> versicolor.52          6.4         3.2          4.5         1.5 versicolor
    #> virginica.101          6.3         3.3          6.0         2.5  virginica
    #> virginica.102          5.8         2.7          5.1         1.9  virginica
     
    aggregate(. ~ Species, data=iris, head, n=2)
    #>      Species Sepal.Length.1 Sepal.Length.2 Sepal.Width.1 Sepal.Width.2
    #> 1     setosa            5.1            4.9           3.5           3.0
    #> 2 versicolor            7.0            6.4           3.2           3.2
    #> 3  virginica            6.3            5.8           3.3           2.7
    #>   Petal.Length.1 Petal.Length.2 Petal.Width.1 Petal.Width.2
    #> 1            1.4            1.4           0.2           0.2
    #> 2            4.7            4.5           1.4           1.5
    #> 3            6.0            5.1           2.5           1.9
     
    # Created on 2021-01-13 by the reprex package (v0.3.0)
    Cordialement,

  8. #8
    Membre actif
    Inscrit en
    Novembre 2003
    Messages
    543
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 543
    Points : 239
    Points
    239
    Par défaut
    Merci mgdondon

    Du coup, j'ai essayé aussi avec tapply ... et ça fonctionne aussi.
    Bonne fin de semaine

  9. #9
    Membre expérimenté
    Inscrit en
    Novembre 2009
    Messages
    703
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 703
    Points : 1 311
    Points
    1 311
    Par défaut first, last
    Bonjour,

    Pour la version avec le package dplyr, il est possible de remplacer la fonction ungroup() (--> tibble) par la fonction as.data.frame() (--> dataframe).

    En version sans pipe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    library(dplyr)
    iris <- group_by(iris, Species)
    ungroup(slice(iris, 1))
    #> # A tibble: 3 x 5
    #>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species   
    #>          <dbl>       <dbl>        <dbl>       <dbl> <fct>     
    #> 1          5.1         3.5          1.4         0.2 setosa    
    #> 2          7           3.2          4.7         1.4 versicolor
    #> 3          6.3         3.3          6           2.5 virginica
    as.data.frame(slice(iris, 1))
    #>   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    #> 1          5.1         3.5          1.4         0.2     setosa
    #> 2          7.0         3.2          4.7         1.4 versicolor
    #> 3          6.3         3.3          6.0         2.5  virginica
    Cordialement,

  10. #10
    Membre actif
    Inscrit en
    Novembre 2003
    Messages
    543
    Détails du profil
    Informations forums :
    Inscription : Novembre 2003
    Messages : 543
    Points : 239
    Points
    239
    Par défaut
    Bonjour,

    Je reviens sur le sujet avec un exemple avec la fonction tapplyPremier exemple sur la première variable, triée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    DF <- data.frame(Obs=c('A','B','C','D','E','F','G','H','I','J','K'),X=c(1,1,1,1,2,2,2,3,4,4,4),Y=c(1,1,1,2,3,1,3,1,2,1,3))
    tapply(DF$Obs, list(DF$X), tail, n=1)           # éléments n° 4 7 8 11 
    DF$Obs[tapply(DF$Obs, list(DF$X), tail, n=1)]   # D G H K
    Deuxième exemple sur la seconde variable, non triée
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    tapply(DF$Obs, list(DF$Y), tail, n=1)          # éléments n°10 9 11 
    DF$Obs[tapply(DF$Obs, list(DF$Y), tail, n=1)]  # J I K

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 24/09/2018, 10h56
  2. Réponses: 2
    Dernier message: 10/02/2015, 10h34
  3. Bordure premier et dernier élément sur une listview
    Par Willy55 dans le forum Composants graphiques
    Réponses: 0
    Dernier message: 29/03/2014, 20h30
  4. Réponses: 0
    Dernier message: 18/08/2011, 11h21
  5. Réponses: 4
    Dernier message: 14/11/2008, 10h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo