Измените класс с факторного на числовой для многих столбцов во фрейме данных
Каков самый быстрый/лучший способ изменить большое количество столбцов на числовые из коэффициента?
Я использовал следующий код, но он, похоже, повторно заказал мои данные.
> 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*
Каков наилучший способ, не называя каждого столбца, как в:
df$colname <- as.numeric(ds$colname)
Ответы
Ответ 1
В ответ на ответ Рамната поведение, которое вы испытываете, состоит в том, что из-за as.numeric(x)
возврата внутреннего числового представления коэффициента x
на уровне R. Если вы хотите сохранить числа, которые являются уровнями фактора (а не их внутренним представлением), вам нужно сначала преобразовать символ через as.character()
в соответствии с примером Рамната.
Ваш цикл for
столь же разумен, как и вызов apply
, и может быть немного более читабельным относительно того, каково намерение кода. Просто измените эту строку:
stats[,i] <- as.numeric(stats[,i])
читать
stats[,i] <- as.numeric(as.character(stats[,i]))
Это FAQ 7.10 в FAQ FAQ.
НТН
Ответ 2
Вы должны быть осторожны при изменении факторов на числовые. Вот строка кода, которая изменила бы набор столбцов от коэффициента к числовому. Я предполагаю, что столбцы, которые нужно изменить на числовые, равны 1, 3, 4 и 5 соответственно. Вы можете изменить его соответствующим образом.
cols = c(1, 3, 4, 5);
df[,cols] = apply(df[,cols], 2, function(x) as.numeric(as.character(x)));
Ответ 3
Это может быть сделано в одной строке, нет необходимости в цикле, будь то цикл for или применение. Вместо этого используйте 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)
Изменение: для вашего кода это становится:
id <- c(1,3:ncol(stats)))
stats[,id] <- as.numeric(as.character(unlist(stats[,id])))
Очевидно, что если у вас есть фрейм данных из одного столбца, и вы не хотите, чтобы автоматическое уменьшение размера R преобразовывало его в вектор, вам придется добавить аргумент drop=FALSE
.
Ответ 4
Я знаю, что этот вопрос давно решен, но недавно у меня была похожая проблема, и я думаю, что нашел немного более элегантное и функциональное решение, хотя для этого требуется пакет magrittr.
library(magrittr)
cols = c(1, 3, 4, 5)
df[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))
Оператор %<>%
направляет и переназначает, что очень полезно для упрощения очистки и преобразования данных. Теперь функцию применения списка гораздо проще читать, указав только функцию, которую вы хотите применить.
Ответ 5
Я думаю, что ucfagls нашел, почему ваш цикл не работает.
Если вы все еще не хотите использовать цикл, то это решение с lapply
:
factorToNumeric <- function(f) as.numeric(levels(f))[as.integer(f)]
cols <- c(1, 3:ncol(stats))
stats[cols] <- lapply(stats[cols], factorToNumeric)
Изменить. Я нашел более простое решение. Кажется, что as.matrix
преобразуется в символ. Так
stats[cols] <- as.numeric(as.matrix(stats[cols]))
должен делать то, что вы хотите.
Ответ 6
lapply в значительной степени предназначен для этого
unfactorize<-c("colA","colB")
df[,unfactorize]<-lapply(unfactorize, function(x) as.numeric(as.character(df[,x])))
Ответ 7
Я нашел эту функцию на пару других повторяющихся потоков и нашел ее элегантный и общий способ решить эту проблему. Этот поток появляется в первую очередь в большинстве запросов по этой теме, поэтому я поделился им здесь, чтобы спасти людей некоторое время. Я не беру на себя ответственность за это, так что см. Здесь оригинальные сообщения здесь и здесь.
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")
Ответ 8
Я хотел бы указать, что если у вас есть NA в любом столбце, просто использование индексов не будет работать. Если в коэффициенте есть NA, вы должны использовать приложение script, предоставленное Ramnath.
например.
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)]))
Возвращает следующее:
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
Но:
Df[,c(1:4)]= apply(Df[,c(1:4)], 2, function(x) as.numeric(as.character(x)))
Возврат:
> 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
Ответ 9
Вы можете использовать unfactor()
из пакета CRAN "varhandle":
library("varhandle")
my_iris <- data.frame(Sepal.Length = factor(iris$Sepal.Length),
sample_id = factor(1:nrow(iris)))
my_iris <- unfactor(my_iris)
Ответ 10
Мне нравится этот код, потому что он довольно удобен:
data[] <- lapply(data, function(x) type.convert(as.character(x), as.is = TRUE)) #change all vars to their best fitting data type
Это не совсем то, что было запрошено (преобразовать в числовое), но во многих случаях даже более уместно.
Ответ 11
Вот несколько вариантов 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(.)))
Ответ 12
У меня были проблемы с преобразованием всех столбцов в числовые с вызовом apply()
:
apply(data, 2, as.numeric)
Проблема заключается в том, что некоторые из строк имеют в них запятую - например, "1,024,63" вместо "1024,63" - и R не нравится этот способ форматирования чисел. Поэтому я удалил их, а затем побежал as.numeric()
:
data = as.data.frame(apply(data, 2, function(x) {
y = str_replace_all(x, ",", "") #remove commas
return(as.numeric(y)) #then convert
}))
Обратите внимание, что для этого требуется, чтобы загружался пакет stringr.
Ответ 13
Что сработало для меня. Функция apply()
пытается принудить df к матрице и возвращает NA.
numeric.df <- as.data.frame(sapply(df, 2, as.numeric))
Ответ 14
Основываясь на ответе @SDahm, это было "оптимальное" решение для моего tibble
:
data %<>% lapply(type.convert) %>% as.data.table()
Это требует dplyr
и magrittr
.
Ответ 15
Я перепробовал несколько подобных проблем и продолжал получать АН. Base R имеет некоторые действительно раздражающие способы принуждения, которые обычно исправляются в пакетах Tidyverse. Раньше я избегал их, потому что не хотел создавать зависимости, но они делают жизнь намного проще, и теперь я даже не пытаюсь найти решение Base R большую часть времени.
Вот решение Tidyverse, которое предельно просто и элегантно:
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)
Ответ 16
df$colname <- as.numeric(df$colname)
Я попробовал этот способ для изменения одного типа столбца, и я думаю, что это лучше, чем многие другие версии, если вы не собираетесь менять все типы столбцов
df$colname <- as.character(df$colname)
для наоборот.