Измените класс с факторного на числовой для многих столбцов во фрейме данных - PullRequest
74 голосов
/ 26 сентября 2010

Какой самый быстрый / лучший способ заменить большое количество столбцов на числовые с коэффициента?

Я использовал следующий код, но, похоже, он переупорядочил мои данные.

> 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)

Ответы [ 16 ]

68 голосов
/ 26 сентября 2010

Вы должны быть осторожны при изменении коэффициентов на числовые. Вот строка кода, которая изменит набор столбцов с факторного на числовой. Здесь я предполагаю, что столбцы, которые нужно изменить на числовые, равны 1, 3, 4 и 5 соответственно. Вы можете изменить его соответственно

cols = c(1, 3, 4, 5);    
df[,cols] = apply(df[,cols], 2, function(x) as.numeric(as.character(x)));
53 голосов
/ 26 сентября 2010

В дополнение к ответу Рамната, ваше поведение таково, что 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 в R FAQ.

НТН

34 голосов
/ 27 сентября 2010

Это может быть сделано в одной строке, нет необходимости в цикле, будь то цикл или применение.Вместо этого используйте 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)

Edit: для вашего кода это становится:

id <- c(1,3:ncol(stats))) 
stats[,id] <- as.numeric(as.character(unlist(stats[,id])))

Очевидно, если у вас есть фрейм данных из одного столбца, и вы не хотитеавтоматическое уменьшение размера R для преобразования его в вектор, вам нужно будет добавить аргумент drop=FALSE.

28 голосов
/ 03 апреля 2016

Я знаю, что этот вопрос давно решен, но недавно у меня была похожая проблема, и я думаю, что нашел немного более элегантное и функциональное решение, хотя для этого требуется пакет magrittr.

library(magrittr)
cols = c(1, 3, 4, 5)
df[,cols] %<>% lapply(function(x) as.numeric(as.character(x)))

The %<>% операторские каналы и переназначаются, что очень полезно для упрощения очистки и преобразования данных.Теперь функцию применения списка гораздо проще читать, указав только функцию, которую вы хотите применить.

6 голосов
/ 26 сентября 2010

Я думаю, что ucfagls обнаружил, почему ваш цикл не работает.

Если вы все еще не хотите использовать цикл, вот решение с lapply:

factorToNumeric <- function(f) as.numeric(levels(f))[as.integer(f)] 
cols <- c(1, 3:ncol(stats))
stats[cols] <- lapply(stats[cols], factorToNumeric)

Edit. Я нашел более простое решение. Кажется, что as.matrix преобразовать в символ. Так

stats[cols] <- as.numeric(as.matrix(stats[cols]))

должен делать то, что вы хотите.

5 голосов
/ 07 января 2014

lapply в значительной степени разработан для этого

unfactorize<-c("colA","colB")
df[,unfactorize]<-lapply(unfactorize, function(x) as.numeric(as.character(df[,x])))
2 голосов
/ 08 декабря 2016

Я нашел эту функцию в паре других дублирующих тем и нашел ее элегантным и общим способом решения этой проблемы. Эта тема показывается первой в большинстве запросов по этой теме, поэтому я делюсь ею здесь, чтобы сэкономить время. Я не воздаю должное этому, просто посмотрите исходные сообщения здесь и здесь для подробностей.

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")
1 голос
/ 21 марта 2019

Вот несколько вариантов 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(.))) 
1 голос
/ 14 декабря 2018

Мне нравится этот код, потому что он довольно удобен:

  data[] <- lapply(data, function(x) type.convert(as.character(x), as.is = TRUE)) #change all vars to their best fitting data type

Это не совсем то, что было запрошено (преобразовать в числовое), но во многих случаях даже более уместно.

1 голос
/ 02 августа 2018

Вы можете использовать функцию unfactor() из формы пакета "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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...