Jaki jest najszybszy / najlepszy sposób zmiany dużej liczby kolumn na liczbowe ze współczynnika?
Użyłem następującego kodu, ale wygląda na to, że uporządkowałem moje dane.
> 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*
Jaki jest najlepszy sposób, poza nazwaniem każdej kolumny, jak w:
df$colname <- as.numeric(ds$colname)
Odpowiedzi:
W nawiązaniu do odpowiedzi Ramnatha, zachowanie, którego doświadczasz, jest spowodowane
as.numeric(x)
zwróceniem wewnętrznej, liczbowej reprezentacji czynnikax
na poziomie R. Jeśli chcesz zachować liczby, które są poziomami współczynnika (a nie ich wewnętrzną reprezentacją), musisz najpierw przekonwertować na znak przez,as.character()
jak na przykładzie Ramnatha.Twoja
for
pętla jest tak samo rozsądna jakapply
wywołanie i może być nieco bardziej czytelna, jeśli chodzi o intencję kodu. Po prostu zmień tę linię:stats[,i] <- as.numeric(stats[,i])
czytać
stats[,i] <- as.numeric(as.character(stats[,i]))
To jest FAQ 7.10 w R FAQ.
HTH
źródło
factor
i nie zadziałało.sapply
lubmutate_if
wydają się bardziej powszechnie stosowanymi rozwiązaniami.apply
do uruchamiania pętli, a OPfor
jawnie używa pętli. W rzeczywistości wszystkie wysoko ocenione odpowiedzi używająas.numeric(as.character())
idiomu.numeric
, ale nie działa odwrotnie (aby zmienić klasę wielu kolumn nafactor
). Jeśli używasz indeksów, których potrzebujesz,unlist()
i po zastosowaniu do kolumn ze znakami, wyświetla on każdy pojedynczy znak, co sprawia, że nie działa już podczas wstawiania wyniku z powrotem dostats[,i]
. Sprawdź odpowiedź tutaj: stackoverflow.com/questions/45713473/…as.factor()
zamiastas.numeric(as.character())
tutaj i będzie działać dobrze. Oczywiście, jeśli masz mieszankę kolumn, musisz wybieraći
selektywnie, ale to również trywialne.Trzeba uważać przy zmianie czynników na numeryczne. Oto wiersz kodu, który zmieni zestaw kolumn ze współczynnika na liczbowy. Zakładam tutaj, że kolumny, które mają zostać zmienione na numeryczne, to odpowiednio 1, 3, 4 i 5. Możesz to odpowiednio zmienić
cols = c(1, 3, 4, 5); df[,cols] = apply(df[,cols], 2, function(x) as.numeric(as.character(x)));
źródło
x<-as.factor(1:3); df<-data.frame(a=x,y=runif(3),b=x,c=x,d=x)
. Myślę, że nieapply
jest to właściwe dla tego rodzaju problemów.apply
. Sprawdź moją zmianę.unlist
. Aas.character
konwersja w twoim rozwiązaniu nie jest potrzebna, ponieważapply
konwersjadf[,cols]
nacharacter
takapply(df[,cols], 2, function(x) as.numeric(x))
też zadziała.=
? Dlaczego nie<-
?Można to zrobić w jednej linii, nie ma potrzeby tworzenia pętli, czy to pętli for, czy aplikacji. Zamiast tego użyj unlist ():
# 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)
Edytuj: dla twojego kodu wygląda to następująco:
id <- c(1,3:ncol(stats))) stats[,id] <- as.numeric(as.character(unlist(stats[,id])))
Oczywiście, jeśli masz ramkę danych z jedną kolumną i nie chcesz, aby automatyczna redukcja wymiaru R przekształciła ją w wektor, musisz dodać
drop=FALSE
argument.źródło
recursive
iuse.names
parametryunlist
obu naFALSE
.Df <- tibble::as_tibble(Df)
mutate_if
. Albo jakiekolwiek nowe podejście zostanie udostępnione w kolejnej iteracjidplyr
…Wiem, że to pytanie zostało rozwiązane od dawna, ale ostatnio miałem podobny problem i myślę, że znalazłem nieco bardziej eleganckie i funkcjonalne rozwiązanie, chociaż wymaga pakietu magrittr.
library(magrittr) cols = c(1, 3, 4, 5) df[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))
Do
%<>%
rury operatora i przypisuje, co jest bardzo przydatne do czyszczenia danych przechowywanie i transformacja prosty. Teraz lista funkcji zastosowania jest znacznie łatwiejsza do odczytania, określając jedynie funkcję, którą chcesz zastosować.źródło
df[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))
df[,cols] %<>% as.numeric(as.character(.))
działa tak samoError in [.data.table(Results, , cols) : j (the 2nd argument inside [...]) is a single symbol but column name 'cols' is not found. Perhaps you intended DT[,..cols] or DT[,cols,with=FALSE]. This difference to data.frame is deliberate and explained in FAQ 1.1.
cols <- c("a","b"); df[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))
Oto kilka
dplyr
opcji:# 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(.)))
źródło
Myślę, że ucfagls odkrył, dlaczego twoja pętla nie działa.
Jeśli nadal nie chcesz używać pętli, oto rozwiązanie z
lapply
:factorToNumeric <- function(f) as.numeric(levels(f))[as.integer(f)] cols <- c(1, 3:ncol(stats)) stats[cols] <- lapply(stats[cols], factorToNumeric)
Edytować. Znalazłem prostsze rozwiązanie. Wygląda na to, że
as.matrix
przekształca się w charakter. Więcstats[cols] <- as.numeric(as.matrix(stats[cols]))
powinieneś robić, co chcesz.
źródło
lapply jest właściwie do tego przeznaczony
unfactorize<-c("colA","colB") df[,unfactorize]<-lapply(unfactorize, function(x) as.numeric(as.character(df[,x])))
źródło
Znalazłem tę funkcję w kilku innych zduplikowanych wątkach i uznałem, że jest to elegancki i ogólny sposób rozwiązania tego problemu. Ten wątek pojawia się jako pierwszy w większości wyszukiwań na ten temat, więc udostępniam go tutaj, aby zaoszczędzić ludziom trochę czasu. Nie biorę za to uznania, więc zobacz oryginalne posty tutaj i tutaj, aby uzyskać szczegółowe informacje.
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")
źródło
Chciałbym zwrócić uwagę, że jeśli masz NA w dowolnej kolumnie, po prostu użycie indeksów dolnych nie zadziała. Jeśli czynnik zawiera NA, musisz użyć skryptu aplikacji dostarczonego przez Ramnath.
Na przykład
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)]))
Zwraca następujące dane:
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
Ale:
Df[,c(1:4)]= apply(Df[,c(1:4)], 2, function(x) as.numeric(as.character(x)))
Zwroty:
> 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
źródło
możesz użyć
unfactor()
funkcji z pakietu "varhandle" z CRAN:library("varhandle") my_iris <- data.frame(Sepal.Length = factor(iris$Sepal.Length), sample_id = factor(1:nrow(iris))) my_iris <- unfactor(my_iris)
źródło
Podoba mi się ten kod, ponieważ jest bardzo przydatny:
data[] <- lapply(data, function(x) type.convert(as.character(x), as.is = TRUE)) #change all vars to their best fitting data type
Nie jest to dokładnie to, o co proszono (konwersja na numeryczne), ale w wielu przypadkach nawet bardziej odpowiednie.
źródło
df$colname <- as.numeric(df$colname)
Próbowałem w ten sposób zmienić jeden typ kolumny i myślę, że jest lepszy niż wiele innych wersji, jeśli nie zamierzasz zmieniać wszystkich typów kolumn
df$colname <- as.character(df$colname)
na odwrót.
źródło
Miałem problemy z konwersją wszystkich kolumn na numeryczne z
apply()
wywołaniem:apply(data, 2, as.numeric)
Okazuje się, że problem polega na tym, że niektóre ciągi miały przecinek - np. „1024,63” zamiast „1024,63” - a R nie lubi tego sposobu formatowania liczb. Więc je usunąłem, a potem uruchomiłem
as.numeric()
:data = as.data.frame(apply(data, 2, function(x) { y = str_replace_all(x, ",", "") #remove commas return(as.numeric(y)) #then convert }))
Zauważ, że wymaga to załadowania pakietu stringr.
źródło
To działa dla mnie. Do
apply()
prób funkcyjnych do zmuszania df aby matryca i zwraca NA użytkownika.numeric.df <- as.data.frame(sapply(df, 2, as.numeric))
źródło
Opierając się na odpowiedzi @ SDahm, było to „optymalne” rozwiązanie dla moich
tibble
:To wymaga
dplyr
imagrittr
.źródło
Wypróbowałem kilka z nich w przypadku podobnego problemu i nadal otrzymywałem NA. Base R ma kilka naprawdę irytujących zachowań przymusu, które są generalnie naprawione w pakietach Tidyverse. Kiedyś ich unikałem, ponieważ nie chciałem tworzyć zależności, ale ułatwiają życie, więc teraz nawet nie kłopoczę się próbą znalezienia rozwiązania Base R.
Oto rozwiązanie Tidyverse, które jest niezwykle proste i eleganckie:
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)
źródło
as.numeric(as.character())
konwersję, aby uniknąć zbyt powszechnej konwersji poziomów całkowitych zamiast wartości na liczby. Z radością zagłosowałbym za tą odpowiedzią, jeśli pokażesz tę opcję.