Je suis un utilisateur débutant de R et j'ai écrit un code qui, je pense, pourrait être raccourci avec une boucle for. Le problème est que je n'arrive pas à comprendre comment écrire la boucle.
J'ai un dataframe avec la colonne "TestGrade" avec des valeurs comme "Grade 1" ou "Kindergarten". J'essaye de changer cette colonne pour n'être qu'une valeur numérique. Par exemple, «Kindergarten» serait changé en 0 et «Grade 1» serait changé en 1. Je fournirai le code ci-dessous d'un exemple de dataframe et comment j'ai résolu le problème sans boucle.
Toute orientation sera grandement appréciée!
##Sample Data
FirstInitial <- c("A", "D", "M", "C", "J", "S", "K", "L", "M", "K", "G", "B", "F")
LastInitial <- c("S", "M", "T", "M", "A", "B", "H", "M", "S", "W", "L", "Z", "P")
TestGrade <- c('Kindergarten', 'Grade 1','Grade 2', 'Grade 3','Grade 4', 'Grade 5', 'Grade 6','Grade 7','Grade 8', 'Grade 9', 'Grade 10', 'Grade 11','Grade 12')
df <- data.frame(FirstInitial, LastInitial, TestGrade)
##The codes current function
if(any(df$TestGrade == 'Kindergarten')){
df$TestGrade <- gsub('Kindergarten', '0', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 1')){
df$TestGrade <- gsub('Grade 1', '1', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 2')){
df$TestGrade <- gsub('Grade 2', '2', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 3')){
df$TestGrade <- gsub('Grade 3', '3', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 4')){
df$TestGrade <- gsub('Grade 4', '4', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 5')){
df$TestGrade <- gsub('Grade 5', '5', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 6')){
df$TestGrade <- gsub('Grade 6', '6', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 7')){
df$TestGrade <- gsub('Grade 7', '7', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 8')){
df$TestGrade <- gsub('Grade 8', '8', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 9')){
df$TestGrade <- gsub('Grade 9', '9', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 10')){
df$TestGrade <- gsub('Grade 10', '10', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 11')){
df$TestGrade <- gsub('Grade 11', '11', df$TestGrade)
}
if(any(df$TestGrade == 'Grade 12')){
df$TestGrade <- gsub('Grade 12', '12', df$TestGrade)
}
6 Réponses :
Ceci résout votre problème ici:
df$TestGrade <- sapply(df$TestGrade,function(el)
{
if(el == "Kindergarten") return(0)
else return(as.numeric(sub("Grade ","",el)))
}
Nous pouvons utiliser ifelse , attribuer 0 pour "Kindergarten" et supprimer "Grade" des autres
as.numeric(ifelse(df$TestGrade == "Kindergarten", 0,
sub("Grade ", "", df$TestGrade)))
#[1] 0 1 2 3 4 5 6 7 8 9 10 11 12
Cela peut être fait sans avoir besoin d'une boucle for en utilisant un code à deux lignes. Je vous suggère également d'ajouter stringsAsFactors = F dans votre commande data.frame avant d'exécuter ces lignes
df$TestGrade[df$TestGrade == "Kindergarten"] = 0
df$TestGrade <- gsub("Grade ", "", df$TestGrade)
> df
FirstInitial LastInitial TestGrade
1 A S 0
2 D M 1
3 M T 2
4 C M 3
5 J A 4
6 S B 5
7 K H 6
8 L M 7
9 M S 8
10 K W 9
11 G L 10
12 B Z 11
13 F P 12
Vous pouvez écrire une clé et définir les notes comme un facteur. Cela fonctionnera même si le format des notes change.
key <- c('Kindergarten',
'Grade 1',
'Grade 2',
'Grade 3',
'Grade 4',
'Grade 5',
'Grade 6',
'Grade 7',
'Grade 8',
'Grade 9',
'Grade 10',
'Grade 11',
'Grade 12')
dat <- c('Grade 3', 'Grade 5', 'Grade 2')
dat <- factor(dat, levels = key)
dat <- as.numeric(dat) - 1
dat
Nous soustrayons 1 à la fin car les facteurs commencent à 1 et vous vouliez que la maternelle soit définie sur 0.
Nous pouvons utiliser case_when
library(dplyr)
library(readr)
df %>%
mutate(TestGrade = case_when(as.character(TestGrade) == "Kindergarten"~ 0,
TRUE ~ parse_number(TestGrade)))
# FirstInitial LastInitial TestGrade
#1 A S 0
#2 D M 1
#3 M T 2
#4 C M 3
#5 J A 4
#6 S B 5
#7 K H 6
#8 L M 7
#9 M S 8
#10 K W 9
#11 G L 10
#12 B Z 11
#13 F P 12
Premier raccourcissement: vous n'avez pas besoin de if (any (...)) . gsub est intelligent, c'est comme une recherche / remplacement. La commande gsub ('Grade 9', '9', df $ TestGrade) remplacera 'Grade 9' par '9' , et ne touchera à rien d'autre. Donc, en supprimant toutes vos instructions if , nous obtenons:
# optimized
df$TestGrade = as.character(df$TestGrade) # needed only if it is a factor
df$TestGrade[df$TestGrade == "Kindergarten"] = 0
df$TestGrade = as.integer(sub("Grade ", "", df$TestGrade, fixed = TRUE))
Prochaine amélioration, nous pourrions faire une boucle. C'est exactement équivalent au code ci-dessus, juste moins de frappe.
df$TestGrade = as.character(df$TestGrade) # needed only if it is a factor
df$TestGrade[df$TestGrade == "Kindergarten"] = 0
df$TestGrade = sub("Grade ", "", df$TestGrade)
df$TestGrade = as.numeric(df$TestGrade) # if needed
Encore mieux, nous pourrions être plus intelligents, faire de la maternelle un cas particulier et simplement supprimer "Grade" de tout le reste, comme dans les réponses de Juian et Ronak. Une autre variante de cela est la suivante:
pattern = c("Kindergarten", paste("Grade", 1:12))
replacement = as.character(0:12)
for (i in seq_along(pattern)) {
df$TestGrade <- gsub(pattern[i], replacement[i], df$TestGrade)
}
Si nous voulons vraiment être sophistiqués, nous pourrions définir fixed = TRUE dans sub () . Cela indique à sub que nous ne voulons que des correspondances exactes, nous n'essayons pas d'utiliser des expressions régulières. Cela rendra le code plus rapide, mais à moins que vous n'ayez beaucoup de données, vous ne remarquerez aucune différence. Si vous avez plus de 100 000 lignes, cette méthode sera assez rapide:
df$TestGrade <- gsub('Kindergarten', '0', df$TestGrade)
df$TestGrade <- gsub('Grade 1', '1', df$TestGrade)
df$TestGrade <- gsub('Grade 2', '2', df$TestGrade)
df$TestGrade <- gsub('Grade 3', '3', df$TestGrade)
df$TestGrade <- gsub('Grade 4', '4', df$TestGrade)
df$TestGrade <- gsub('Grade 5', '5', df$TestGrade)
df$TestGrade <- gsub('Grade 6', '6', df$TestGrade)
df$TestGrade <- gsub('Grade 7', '7', df$TestGrade)
df$TestGrade <- gsub('Grade 8', '8', df$TestGrade)
df$TestGrade <- gsub('Grade 9', '9', df$TestGrade)
df$TestGrade <- gsub('Grade 10', '10', df$TestGrade)
df$TestGrade <- gsub('Grade 11', '11', df$TestGrade)
df$TestGrade <- gsub('Grade 12', '12', df$TestGrade)
Le conseil tangentiel que je propose à plusieurs reprises est d'utiliser des boucles explicites comme DERNIER choix dans R. Les fonctions apply et les packages associés sont conçus pour l'efficacité du codage.