Конвертировать сразу несколько столбцов кадра данных

Кажется, я потратил много времени на создание фрейма данных из файла, базы данных или чего-то еще, а затем преобразование каждого столбца в тип, в котором я его хотел (числовое значение, коэффициент, символ и т. Д.). Есть ли способ сделать это за один шаг, возможно, указав вектор типов?

foo<-data.frame(x=c(1:10), y=c("red", "red", "red", "blue", "blue", "blue", "yellow", "yellow", "yellow", "green"), z=Sys.Date()+c(1:10)) foo$x<-as.character(foo$x) foo$y<-as.character(foo$y) foo$z<-as.numeric(foo$z) 

вместо трех последних команд я хотел бы сделать что-то вроде

 foo<-convert.magic(foo, c(character, character, numeric)) 

Редактировать См. Этот связанный вопрос для некоторых упрощений и расширений в этой базовой идее.

Мой комментарий к ответу Брэндона с помощью switch :

 convert.magic <- function(obj,types){ for (i in 1:length(obj)){ FUN <- switch(types[i],character = as.character, numeric = as.numeric, factor = as.factor) obj[,i] <- FUN(obj[,i]) } obj } out <- convert.magic(foo,c('character','character','numeric')) > str(out) 'data.frame': 10 obs. of 3 variables: $ x: chr "1" "2" "3" "4" ... $ y: chr "red" "red" "red" "blue" ... $ z: num 15254 15255 15256 15257 15258 ... 

Для действительно больших кадров данных вы можете использовать lapply вместо цикла for :

 convert.magic1 <- function(obj,types){ out <- lapply(1:length(obj),FUN = function(i){FUN1 <- switch(types[i],character = as.character,numeric = as.numeric,factor = as.factor); FUN1(obj[,i])}) names(out) <- colnames(obj) as.data.frame(out,stringsAsFactors = FALSE) } 

При этом помните о некоторых тонкостях данных принуждения в R. Например, преобразование из коэффициента в числовое часто включает as.numeric(as.character(...)) . Кроме того, помните о data.frame() и as.data.frame() умолчанию для преобразования символа в коэффициент.

Если вы хотите автоматически определять тип данных столбцов, а не вручную указывать его (например, после обработки данных и т. Д.), Может помочь функция type.convert() .

Функция type.convert() принимает вектор символов и пытается определить оптимальный тип для всех элементов (что означает, что он должен применяться один раз за столбец).

 df[] <- lapply(df, function(x) type.convert(as.character(x))) 

Поскольку я люблю dplyr , я предпочитаю:

 library(dplyr) df <- df %>% mutate_all(funs(type.convert(as.character(.)))) 

Я нахожу, что сталкиваюсь с этим много. Речь идет о том, как вы импортируете данные. Все функции read … () имеют некоторую опцию, позволяющую не преобразовывать символьные строки в коэффициент. Это означает, что текстовые строки будут оставаться символом, а вещи, которые выглядят как числа, останутся как числа. Проблема возникает, когда у вас есть элементы, которые пусты, а не NA. Но опять же, na.strings = c (“”, …) также должно решить это. Я бы начал внимательно изучать процесс импорта и соответствующим образом корректировать его.

Но вы всегда можете создать функцию и пропустить эту строку.

 convert.magic <- function(x, y=NA) { for(i in 1:length(y)) { if (y[i] == "numeric") { x[i] <- as.numeric(x[[i]]) } if (y[i] == "character") x[i] <- as.character(x[[i]]) } return(x) } foo <- convert.magic(foo, c("character", "character", "numeric")) > str(foo) 'data.frame': 10 obs. of 3 variables: $ x: chr "1" "2" "3" "4" ... $ y: chr "red" "red" "red" "blue" ... $ z: num 15254 15255 15256 15257 15258 ... 

Я знаю, что довольно поздно ответить, но использование цикла вместе с функцией атрибутов – простое решение вашей проблемы.

 names <-c(x, y, z) chclass <-c("character","character","numeric") for (i in (1:length(names))){ attributes(foo[,(names[i])])$class <-chclass[i] } 

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

 ##data.frame conversion function convert.magic2 <- function(df,classes){ out <- lapply(1:length(classes), FUN = function(classIndex){as(df[,classIndex],classes[classIndex])}) names(out) <- colnames(df) return(data.frame(out)) } ##small example case tmp.df <- data.frame('dt'=c("2013-09-02 09:35:06", "2013-09-02 09:38:24", "2013-09-02 09:38:42", "2013-09-02 09:38:42"), 'v'=c('1','2','3','4'), stringsAsFactors=FALSE) classes=c('POSIXct','numeric') str(tmp.df) #confirm that it has character datatype columns ## 'data.frame': 4 obs. of 2 variables: ## $ dt: chr "2013-09-02 09:35:06" "2013-09-02 09:38:24" "2013-09-02 09:38:42" "2013-09-02 09:38:42" ## $ v : chr "1" "2" "3" "4" ##is the dt column coerceable to POSIXct? canCoerce(tmp.df$dt,"POSIXct") ## [1] FALSE ##and the conver.magic2 function fails also: tmp.df.n <- convert.magic2(tmp.df,classes) ## Error in as(df[, classIndex], classes[classIndex]) : ## no method or default for coercing “character” to “POSIXct” ##ittle reading reveals the setAS function setAs('character', 'POSIXct', function(from){return(as.POSIXct(from))}) ##better answer for canCoerce canCoerce(tmp.df$dt,"POSIXct") ## [1] TRUE ##better answer from conver.magic2 tmp.df.n <- convert.magic2(tmp.df,classes) ##column datatypes converted as I would like them! str(tmp.df.n) ## 'data.frame': 4 obs. of 2 variables: ## $ dt: POSIXct, format: "2013-09-02 09:35:06" "2013-09-02 09:38:24" "2013-09-02 09:38:42" "2013-09-02 09:38:42" ## $ v : num 1 2 3 4 

Несколько простое решение data.table, хотя это займет несколько шагов, если вы переходите к множеству разных типов столбцов.

 dt <- data.table( x=c(1:10), y=c(10:20), z=c(10:20), name=letters[1:10]) dt <- dt[, lapply(.SD, as.numeric), by= name] 

Это изменит все столбцы, за исключением тех, которые указаны в lapply (или все, что вы установили lapply )

Добавление к ответу @ joran, в котором convert.magic не сохранит числовые значения в преобразовании числа в числовое:

 convert.magic <- function(obj,types){ out <- lapply(1:length(obj),FUN = function(i){FUN1 <- switch(types[i], character = as.character,numeric = as.numeric,factor = as.factor); FUN1(obj[,i])}) names(out) <- colnames(obj) as.data.frame(out,stringsAsFactors = FALSE) } foo<-data.frame(x=c(1:10), y=c("red", "red", "red", "blue", "blue", "blue", "yellow", "yellow", "yellow", "green"), z=Sys.Date()+c(1:10)) foo$x<-as.character(foo$x) foo$y<-as.character(foo$y) foo$z<-as.numeric(foo$z) str(foo) # 'data.frame': 10 obs. of 3 variables: # $ x: chr "1" "2" "3" "4" ... # $ y: chr "red" "red" "red" "blue" ... # $ z: num 16777 16778 16779 16780 16781 ... foo.factors <- convert.magic(foo, rep("factor", 3)) str(foo.factors) # all factors foo.numeric.not.preserved <- convert.magic(foo.factors, c("numeric", "character", "numeric")) str(foo.numeric.not.preserved) # 'data.frame': 10 obs. of 3 variables: # $ x: num 1 3 4 5 6 7 8 9 10 2 # $ y: chr "red" "red" "red" "blue" ... # $ z: num 1 2 3 4 5 6 7 8 9 10 # z comes out as 1 2 3... 

Следующее должно сохранить числовые значения:

 ## as.numeric function that preserves numeric values when converting factor to numeric as.numeric.mod <- function(x) { if(is.factor(x)) as.numeric(levels(x))[x] else as.numeric(x) } ## The same than in @joran's answer, except for as.numeric.mod convert.magic <- function(obj,types){ out <- lapply(1:length(obj),FUN = function(i){FUN1 <- switch(types[i], character = as.character,numeric = as.numeric.mod, factor = as.factor); FUN1(obj[,i])}) names(out) <- colnames(obj) as.data.frame(out,stringsAsFactors = FALSE) } foo.numeric <- convert.magic(foo.factors, c("numeric", "character", "numeric")) str(foo.numeric) # 'data.frame': 10 obs. of 3 variables: # $ x: num 1 2 3 4 5 6 7 8 9 10 # $ y: chr "red" "red" "red" "blue" ... # $ z: num 16777 16778 16779 16780 16781 ... # z comes out with the correct numeric values 

Трансформация – это то, что вы, кажется, описываете:

 foo <- transform(foo, x=as.character(x), y=as.character(y), z=as.numeric(z)) 
  • Почему я не могу использовать интерфейс с явным оператором?
  • Преобразование NSString в массив символов
  • Как выводить символ как целое через cout?
  • Целочисленные преобразования (сужение, расширение), неопределенное поведение
  • Давайте будем гением компьютера.