Dataframe - Extraction de valeurs

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

Kévin Dubois
Messages : 97
Enregistré le : 25 Mar 2019, 12:07

Dataframe - Extraction de valeurs

Messagepar Kévin Dubois » 13 Sep 2020, 09:22

Bonjour,

Je dispose d'un dataframe qui représente des caractéristiques de personnes, telles que la profession, le sexe, et l'utilisation du télétravail :

Code : Tout sélectionner

data = data.frame(profession = sample(c("artisan", "employe", "cadre supérieur"), 10000, replace = TRUE), sexe = sample(c("M", "F"), 10000, replace = TRUE), en_teletravail = sample(c("Oui", "Non"), 10000, replace = TRUE))


Je souhaiterais créer un nouveau dataframe, issus d'une extraction des valeurs de "data", de telle sorte :
- Qu'il y ait 20% d'hommes et 80% de femmes
- Et, qu'il y ait 60% d'artisans, 20% d'employes, et 20% de cadres supérieur
- Et, qu'il y ait 50% de "Oui" à l'utilisation du télétravail.

Est-il possible de faire ceci sur R ?
Merci

Facundo Muñoz
Messages : 156
Enregistré le : 04 Juil 2019, 09:58
Contact :

Re: Dataframe - Extraction de valeurs

Messagepar Facundo Muñoz » 13 Sep 2020, 10:47

Bonjour,

Bien sûr que si. Voici une façon de le faire :

Code : Tout sélectionner

data = data.frame(
  profession = sample(c("artisan", "employe", "cadre supérieur"), 10000, replace = TRUE),
  sexe = sample(c("M", "F"), 10000, replace = TRUE),
  en_teletravail = sample(c("Oui", "Non"), 10000, replace = TRUE)
)

## Traduction de vos réquis par chaque catégorie, marginalement
marginal_sample_sizes <-
  list(
    profession = c(artisan = .6, `cadre supérieur` = .2, employe = .2),
    sexe = c(F = .8, M = .2),
    en_teletravail = c(Non = .5, Oui = .5)
  )

## Vérification de sécurité : toutes les probs somment 1 pour chaque catégorie
stopifnot(all(vapply(marginal_sample_sizes, sum, 1) == 1))

## Calcule taille rélative de chaque combinaison conjointe de catégories
joint_sample_sizes <-
  cbind(
    expand.grid(lapply(marginal_sample_sizes, names)),
    rel_size = apply(expand.grid(marginal_sample_sizes), 1, prod)
  )

## Liste d'individus par group
idx_by_group <-
  split(
    seq.int(nrow(data)),
    data
  )

## Taille souhaitée d'échantillon
N <- 500

## Indice d'individus séléctionnés
selection_idx <-
  unlist(
    mapply(
      function(x, n) sample(x, n, replace = FALSE),
      idx_by_group,
      N*joint_sample_sizes$rel_size
    )
  )

## Vérification de résultat
table(data[selection_idx, "profession"]) / sum(table(data[selection_idx, "profession"]))
#>
#>         artisan cadre supérieur         employe
#>             0.6             0.2             0.2
table(data[selection_idx, "sexe"]) / sum(table(data[selection_idx, "sexe"]))
#>
#>   F   M
#> 0.8 0.2
table(data[selection_idx, "en_teletravail"]) / sum(table(data[selection_idx, "en_teletravail"]))
#>
#> Non Oui
#> 0.5 0.5
ƒacu.-

Kévin Dubois
Messages : 97
Enregistré le : 25 Mar 2019, 12:07

Re: Dataframe - Extraction de valeurs

Messagepar Kévin Dubois » 13 Sep 2020, 11:03

Un grand merci pour votre aide :) je vais essayer de l'appliquer à mon exemple.
Par hasard, savez-vous s'il est possible de faire la même chose avec des librairies ou des fonctions (pour simplifier un peu le code) ? Je pense à des fonctions permettant de faire un tirage aléatoire, comme "sample" par exemple, qui permettrait de rajouter des spécifications similaires à mon problème.

Merci.

Facundo Muñoz
Messages : 156
Enregistré le : 04 Juil 2019, 09:58
Contact :

Re: Dataframe - Extraction de valeurs

Messagepar Facundo Muñoz » 13 Sep 2020, 14:51

Bonjour Kevin,

Bien sûr, vous pouvez mettre tout cela dans une fonction qui prenne les données et les contraintes comme arguments pour donner comme résultat le sub-dataframe avec les individus sélectionnées, ou peut-être les indices. Ça dépend de vos besoins.

On peut aussi utiliser d'autres packages (notamment du tidyverse) pour le re-ecrire peut-être d'une façon un peu plus parlante. Mais ça ne va pas changer grand chose : en ce moment sont littéralement 3 lignes de code qui font le travail (je las ai mis sur plusieurs lignes pour lisibilité).

Sinon, le code proposé fait déjà un tirage aléatoire. Vous pouvez voir que pour construire l'objet selection_idx on fait appel à la fonction sample. Peut-être vous vouliez utiliser des probabilités d'inclusion plutôt qu'un nombre fixe d'individus dans chaque catégorie ?

Cordialement,
ƒacu.-

Kévin Dubois
Messages : 97
Enregistré le : 25 Mar 2019, 12:07

Re: Dataframe - Extraction de valeurs

Messagepar Kévin Dubois » 13 Sep 2020, 18:12

Génial, effectivement, j'ai réussi à convertir ce code dans une fonction :

Code : Tout sélectionner

extraction_dataframe = function(liste_conditions, data_origine, nb_lignes_souhaite){
    ## Vérification de sécurité : toutes les probs somment 1 pour chaque catégorie
    stopifnot(all(vapply(liste_conditions, sum, 1) == 1))
   
    ## Calcule taille rélative de chaque combinaison conjointe de catégories
    joint_sample_sizes <-
        cbind(
            expand.grid(lapply(liste_conditions, names)),
            rel_size = apply(expand.grid(liste_conditions), 1, prod)
        )
   
    ## Liste d'individus par group
    idx_by_group <-
        split(
            seq.int(nrow(data_origine)),
            data_origine
        )
   
    ## Taille souhaitée d'échantillon
    N <- nb_lignes_souhaite
   
    ## Indice d'individus séléctionnés
    selection_idx <-
        unlist(
            mapply(
                function(x, n) sample(x, n, replace = FALSE),
                idx_by_group,
                N*joint_sample_sizes$rel_size
            )
        )
    ##FINAL
    index_final = (data.frame(selection_idx))
    data_extrait <<- subset(data_origine, rownames(data_origine) %in% index_final$selection_idx)
   
}


Malheureusement, pour utiliser cette fonction sur un de mes exemple sur lequel je travaille (récolte de données d'enquête avec un petit effectif), le fait de devoir donner une taille de lignes me pose problème. Effectivement, je ne connais pas le nombre maximum de lignes possible suivant les facteurs que j'entre. Par exemple, cette fonction tourne en boucle sur mon exemple car (j'imagine ?) je lui demande de me sortir un nombre de ligne supérieur de ce que mon dataframe ne peut me sortir, suivant les facteurs que j'entre.

Est-il possible d'adapter cette fonction, pour que le nombre de lignes retourné soit le nombre maximum de lignes possible suivant les facteurs que j'entre ? Je continus mes recherches de mon côté.

Merci pour ces conseils qui m'ont déjà fait beaucoup progresser.

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

Re: Dataframe - Extraction de valeurs

Messagepar Pierre-Yves Berrard » 14 Sep 2020, 08:21

Il y a peut-être un problème si les données de bases contiennent d'autres colonnes que les variables des stratification.

Remplacer :

Code : Tout sélectionner

        split(
            seq.int(nrow(data_origine)),
            data_origine
        )
par

Code : Tout sélectionner

        split(
            seq.int(nrow(data_origine)),
            data_origine[names(marginal_sample_sizes)]
        )

?
PY

Sylvain Laurin
Messages : 2
Enregistré le : 08 Avr 2020, 14:12

Re: Dataframe - Extraction de valeurs

Messagepar Sylvain Laurin » 15 Sep 2020, 10:23

J'avais un problème similaire et ça m'a aidé, merci ! :)


Retourner vers « Questions en cours »

Qui est en ligne

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