Quel est le moyen le plus rapide/le meilleur de modifier un grand nombre de colonnes en facteur numérique?
J'ai utilisé le code suivant mais il semble avoir re-commandé mes données.
> head(stats[,1:2])
rk team
1 1 Washington Capitals*
2 2 San Jose Sharks*
3 3 Chicago Blackhawks*
4 4 Phoenix Coyotes*
5 5 New Jersey Devils*
6 6 Vancouver Canucks*
for(i in c(1,3:ncol(stats))) {
stats[,i] <- as.numeric(stats[,i])
}
> head(stats[,1:2])
rk team
1 2 Washington Capitals*
2 13 San Jose Sharks*
3 24 Chicago Blackhawks*
4 26 Phoenix Coyotes*
5 27 New Jersey Devils*
6 28 Vancouver Canucks*
Quelle est la meilleure façon de faire, à moins de nommer chaque colonne de la manière suivante:
df$colname <- as.numeric(ds$colname)
Suite à la réponse de Ramnath, le comportement que vous rencontrez est dû au fait que as.numeric(x)
renvoie la représentation numérique interne du facteur x
au niveau R. Si vous voulez conserver les nombres correspondant aux niveaux du facteur (plutôt que leur représentation interne), vous devez d'abord convertir en caractère via as.character()
, comme dans l'exemple de Ramnath.
Votre boucle for
est aussi raisonnable qu'un appel apply
et pourrait être un peu plus lisible quant à l'intention du code. Il suffit de changer cette ligne:
stats[,i] <- as.numeric(stats[,i])
lire
stats[,i] <- as.numeric(as.character(stats[,i]))
Ceci est FAQ 7.10 dans la FAQ R.
HTH
Vous devez faire attention en changeant les facteurs en numérique. Voici une ligne de code qui changerait un ensemble de colonnes de factor en numérique. Je suppose ici que les colonnes à modifier en numérique sont 1, 3, 4 et 5 respectivement. Vous pouvez le changer en conséquence
cols = c(1, 3, 4, 5);
df[,cols] = apply(df[,cols], 2, function(x) as.numeric(as.character(x)));
Cela peut être fait sur une seule ligne, il n’est pas nécessaire d’utiliser une boucle, que ce soit une boucle for ou une apply. Utilisez unlist () à la place:
# testdata
Df <- data.frame(
x = as.factor(sample(1:5,30,r=TRUE)),
y = as.factor(sample(1:5,30,r=TRUE)),
z = as.factor(sample(1:5,30,r=TRUE)),
w = as.factor(sample(1:5,30,r=TRUE))
)
##
Df[,c("y","w")] <- as.numeric(as.character(unlist(Df[,c("y","w")])))
str(Df)
Edit: pour votre code, cela devient:
id <- c(1,3:ncol(stats)))
stats[,id] <- as.numeric(as.character(unlist(stats[,id])))
Évidemment, si vous avez un cadre de données d'une colonne et que vous ne souhaitez pas que la réduction automatique de la dimension de R le convertisse en vecteur, vous devrez ajouter l'argument drop=FALSE
.
Je sais que cette question est résolue depuis longtemps, mais j'ai récemment eu un problème similaire et je pense avoir trouvé une solution un peu plus élégante et fonctionnelle, bien qu'elle nécessite le package magrittr.
library(magrittr)
cols = c(1, 3, 4, 5)
df[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))
L'opérateur %<>%
canal et est réaffecté, ce qui est très utile pour simplifier le nettoyage et la transformation des données. Maintenant, la fonction list apply est beaucoup plus facile à lire, en spécifiant uniquement la fonction que vous souhaitez appliquer.
Je pense que ucfagls a trouvé pourquoi votre boucle ne fonctionne pas.
Si vous ne souhaitez toujours pas utiliser de boucle, voici la solution avec lapply
:
factorToNumeric <- function(f) as.numeric(levels(f))[as.integer(f)]
cols <- c(1, 3:ncol(stats))
stats[cols] <- lapply(stats[cols], factorToNumeric)
Modifier. J'ai trouvé une solution plus simple. Il semble que as.matrix
se convertisse en personnage. Alors
stats[cols] <- as.numeric(as.matrix(stats[cols]))
devrait faire ce que vous voulez.
lapply est assez bien conçu pour cela
unfactorize<-c("colA","colB")
df[,unfactorize]<-lapply(unfactorize, function(x) as.numeric(as.character(df[,x])))
J'ai trouvé cette fonction sur un couple de threads en double et l'ai trouvé un moyen élégant et général de résoudre ce problème. Ce fil apparaît en premier sur la plupart des recherches sur ce sujet, je le partage donc ici pour faire gagner du temps aux gens. Je ne prends aucun crédit pour cela, alors consultez les messages originaux ici et ici pour plus de détails.
df <- data.frame(x = 1:10,
y = rep(1:2, 5),
k = rnorm(10, 5,2),
z = rep(c(2010, 2012, 2011, 2010, 1999), 2),
j = c(rep(c("a", "b", "c"), 3), "d"))
convert.magic <- function(obj, type){
FUN1 <- switch(type,
character = as.character,
numeric = as.numeric,
factor = as.factor)
out <- lapply(obj, FUN1)
as.data.frame(out)
}
str(df)
str(convert.magic(df, "character"))
str(convert.magic(df, "factor"))
df[, c("x", "y")] <- convert.magic(df[, c("x", "y")], "factor")
J'aime ce code parce qu'il est très pratique:
data[] <- lapply(data, function(x) type.convert(as.character(x), as.is = TRUE)) #change all vars to their best fitting data type
Ce n'est pas exactement ce qui était demandé (convertir en numérique), mais dans de nombreux cas, même plus approprié.
vous pouvez utiliser la fonction unfactor()
à partir du package "varhandle" CRAN:
library("varhandle")
my_iris <- data.frame(Sepal.Length = factor(iris$Sepal.Length),
sample_id = factor(1:nrow(iris)))
my_iris <- unfactor(my_iris)
J'aimerais souligner que si vous avez des AN dans une colonne, utiliser simplement des indices ne fonctionnera pas. S'il y a des NA dans le facteur, vous devez utiliser le script apply fourni par Ramnath.
Par exemple.
Df <- data.frame(
x = c(NA,as.factor(sample(1:5,30,r=T))),
y = c(NA,as.factor(sample(1:5,30,r=T))),
z = c(NA,as.factor(sample(1:5,30,r=T))),
w = c(NA,as.factor(sample(1:5,30,r=T)))
)
Df[,c(1:4)] <- as.numeric(as.character(Df[,c(1:4)]))
Renvoie ce qui suit:
Warning message:
NAs introduced by coercion
> head(Df)
x y z w
1 NA NA NA NA
2 NA NA NA NA
3 NA NA NA NA
4 NA NA NA NA
5 NA NA NA NA
6 NA NA NA NA
Mais:
Df[,c(1:4)]= apply(Df[,c(1:4)], 2, function(x) as.numeric(as.character(x)))
Résultats:
> head(Df)
x y z w
1 NA NA NA NA
2 2 3 4 1
3 1 5 3 4
4 2 3 4 1
5 5 3 5 5
6 4 2 4 4
Voici quelques options dplyr
:
# by column type:
df %>%
mutate_if(is.factor, ~as.numeric(as.character(.)))
# by specific columns:
df %>%
mutate_at(vars(x, y, z), ~as.numeric(as.character(.)))
# all columns:
df %>%
mutate_all(~as.numeric(as.character(.)))
J'ai eu des problèmes pour convertir toutes les colonnes en numérique avec un appel apply()
:
apply(data, 2, as.numeric)
Le problème s’explique par le fait que certaines chaînes contiennent une virgule - par exemple. "1 024,63" au lieu de "1024,63" - et R n'aime pas cette façon de formater les nombres. Alors je les ai enlevés puis j'ai lancé as.numeric()
:
data = as.data.frame(apply(data, 2, function(x) {
y = str_replace_all(x, ",", "") #remove commas
return(as.numeric(y)) #then convert
}))
Notez que cela nécessite que le package stringr soit chargé.
D'après la réponse de @ SDahm, il s'agissait d'une solution "optimale" pour ma tibble
:
data %<>% lapply(type.convert) %>% as.data.table()
Cela nécessite dplyr
et magrittr
.
df$colname <- as.numeric(df$colname)
J'ai essayé cette méthode pour changer un type de colonne et je pense que c'est mieux que beaucoup d'autres versions, si vous n'allez pas changer tous les types de colonne
df$colname <- as.character(df$colname)
pour l'inverse.
J'ai essayé plusieurs d'entre elles sur un problème similaire et j'ai continué à avoir des NA. La base R a des comportements de coercition vraiment irritants, qui sont généralement résolus dans les paquets Tidyverse. J'avais l'habitude de les éviter parce que je ne voulais pas créer de dépendances, mais elles facilitent la vie tellement plus facilement que maintenant je ne me donne même plus la peine d'essayer de comprendre la solution Base R la plupart du temps.
Voici la solution Tidyverse, extrêmement simple et élégante:
library(purrr)
mydf <- data.frame(
x1 = factor(c(3, 5, 4, 2, 1)),
x2 = factor(c("A", "C", "B", "D", "E")),
x3 = c(10, 8, 6, 4, 2))
map_df(mydf, as.numeric)