J'ai un data.frame appelé people qui décrit des employés uniques. Le fait est que le parcours des rôles de travail d'un employé est exprimé par une nouvelle ligne pour chaque nouveau rôle, où toutes les variables restent les mêmes à l'exception de Job_history.
employee_ID name Job_role Job_history Job_history2 1 1 Adam Manager Web designer N/A 2 2 Ben CSO Graduate Intern 3 3 Chris Manager N/A N/A 4 4 Dan CTO Manager N/A
Pour continuer à traiter mes données, je dois réduire ces doublons tout en préservant l'historique des tâches. Je voudrais mettre les valeurs de Job_history qui sont actuellement en lignes dans de nouvelles colonnes, et ne pas avoir le travail en cours répété dans la colonne Job_history. Pour visualiser, je veux que le data.frame ressemble à ceci:
employee_ID <- c('1','1','2','2','2','3','4','4')
name <- c('Adam','Adam','Ben','Ben','Ben','Chris','Dan','Dan')
Job_role <- c('Manager','Manager', 'CSO', 'CSO', 'CSO','Manager', 'CTO', 'CTO')
Job_history <- c('Manager', 'Web designer', 'CSO', 'Graduate', 'Intern', '0', 'CTO', 'Manager')
people.data <- data.frame(employee_ID, name, Job_role, Job_history)
employee_ID name Job_role Job_history
1 1 Adam Manager Manager
2 1 Adam Manager Web designer
3 2 Ben CSO CSO
4 2 Ben CSO Graduate
5 2 Ben CSO Intern
6 3 Chris Manager Manager
7 4 Dan CTO CTO
8 4 Dan CTO Manager
Comment dois-je procéder s'il vous plaît? J'ai essayé d'utiliser duplicate () ou unique () mais j'ai du mal à obtenir les valeurs dans les nouvelles colonnes, et dans le bon ordre (de bas en haut devient de gauche à droite pour chaque employé).
Toute aide est grandement appréciée!
3 Réponses :
Pour obtenir le nombre de colonnes, vous devez ajouter, c'est une bonne idée d'interroger automatiquement le nombre de lignes par nom pour connaître la profondeur de l'historique des tâches:
employee_ID <- c('1','1','2','2','2','3','4','4')
name <- c('Adam','Adam','Ben','Ben','Ben','Chris','Dan','Dan')
Job_role <- c('Manager','Manager', 'CSO', 'CSO', 'CSO','Manager', 'CTO', 'CTO')
Job_history <- c('Manager', 'Web designer', 'CSO', 'Graduate', 'Intern', '0', 'CTO', 'Manager')
people.data <- data.frame(employee_ID, name, Job_role, Job_history)
#install required packages
install.packages("tidyquery")
library(tidyquery)
install.packages("dplyr")
library(dplyr)
#get maximum entries per name to automatically get the columns need to be attached
maxrowcount <- query(people.data, "Select count(*) as 'Number', name GROUP BY name")
maxrowcount <- max(maxrowcount$Number, na.rm = TRUE)
maxrowcount
Vous devez d'abord créer un nouveau champ dans votre bloc de données qui contiendra le futur nom de la colonne (Job_history1, Job_history2, etc.). Nous attribuons un numéro séquentiel (1, 2, ...) à chaque enregistrement, groupé par employee_ID, de sorte que le séquentiel commence à 1 pour chaque employé.
# Scalable solution
people.data <- data.frame(employee_ID, name, Job_role, Job_history)
people.data <-
people.data %>%
group_by(employee_ID) %>%
mutate(seq = row_number()) %>%
ungroup()
seq_digits <- nchar(as.character(max(people.data$seq)))
people.data <-
people.data %>%
mutate(column_name = sprintf("Job_history%0*d", seq_digits, seq)) %>%
select(-c(seq))
people.data <-
people.data %>%
pivot_wider(names_from = column_name, values_from = Job_history)
Résultat:
XXX
Il ne nous reste plus qu'à appliquer une opération de pivot pour transposer les valeurs des champs souhaités sur de nouvelles colonnes.
# A tibble: 4 x 6 employee_ID name Job_role Job_history1 Job_history2 Job_history3 <fct> <fct> <fct> <fct> <fct> <fct> 1 1 Adam Manager Manager Web designer NA 2 2 Ben CSO CSO Graduate Intern 3 3 Chris Manager 0 NA NA 4 4 Dan CTO CTO Manager NA
Résultat:
library(tidyr) people.data <- people.data %>% pivot_wider(names_from = column_name, values_from = Job_history) print(people.data)
Une amélioration intéressante se produit si vous pensez qu'un employé peut avoir plus de 10 entrées d'historique ou plus. Parce que dans ce cas, les colonnes seront placées par ordre alphabétique: Job_history1, Job_history10, Job_history2, etc. ce qui n'est pas ce que nous voulons. Nous devons donc utiliser deux chiffres à la place pour formater les noms des colonnes: Job_history01, Job_history02, etc. Dans un cas extrême, nous pouvons même avoir plus de 99 entrées, donc 3 chiffres seraient nécessaires, et ainsi de suite. Nous voulons réduire au minimum le nombre de chiffres et rendre la solution évolutive. Ce que nous devons faire est de récupérer le numéro séquentiel le plus élevé attribué et de déterminer le nombre de chiffres dont il aura besoin.
# A tibble: 8 x 5 employee_ID name Job_role Job_history column_name <fct> <fct> <fct> <fct> <chr> 1 1 Adam Manager Manager Job_history1 2 1 Adam Manager Web designer Job_history2 3 2 Ben CSO CSO Job_history1 4 2 Ben CSO Graduate Job_history2 5 2 Ben CSO Intern Job_history3 6 3 Chris Manager 0 Job_history1 7 4 Dan CTO CTO Job_history1 8 4 Dan CTO Manager Job_history2
Une autre façon consiste à utiliser dplyr dans tidyverse:
# A tibble: 4 x 6 employee_ID name job_role job_history1 job_history2 job_history3 <fct> <fct> <fct> <fct> <fct> <fct> 1 1 Adam Manager Web designer NA NA 2 2 Ben CSO Graduate CSO Intern 3 3 Chris Manager 0 NA NA 4 4 Dan CTO Manager NA NA
conduisant à:
people.data %>%
pivot_longer(cols = starts_with("Job"), names_to = "Job", names_prefix = "job", values_to = "role") %>%
group_by(employee_ID, name) %>%
mutate(rn = cumsum(role != lag(role, default = first(role))), roles = if_else(rn == 0, "role", paste0("history", rn))) %>%
ungroup() %>%
select(-Job) %>%
distinct() %>%
pivot_wider(id_cols = c("employee_ID", "name"), names_from = roles, names_prefix = "job_", values_from = role)