Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid rbind()/cbind() conversion from numeric to factor

Tags:

r

I'm trying to build a dataset before plotting it. I decided to use function factory gammaplot.ff() and the first version of my code looks like this:

PowerUtility1d <- function(x, delta = 4) {   return(((x+1)^(1 - delta)) / (1 - delta)) } PowerUtility1d <- Vectorize(PowerUtility1d, "x")  # function factory allows multiparametrization of PowerUtility1d() gammaplot.ff <- function(type, gamma) {   ff <- switch(type,                 original = function(x) PowerUtility1d(x/10, gamma),                pnorm_wrong = function(x) PowerUtility1d(2*pnorm(x)-1, gamma),                pnorm_right = function(x) PowerUtility1d(2*pnorm(x/3)-1, gamma)               )   ff }  gammaplot.df <- data.frame(type=numeric(), gamma=numeric(),                             x=numeric(), y=numeric()) gammaplot.gamma <- c(1.1, 1.3, 1.5, 2:7) gammaplot.pts <- (-1e4:1e4)/1e3  # building the data set for (gm in gammaplot.gamma) {    for (tp in c("original", "pnorm_wrong", "pnorm_right")) {      fpts <- gammaplot.ff(tp, gm)(gammaplot.pts)          dataChunk <- cbind(tp, gm, gammaplot.pts, fpts)      colnames(dataChunk) <- names(gammaplot.df)      gammaplot.df <- rbind(gammaplot.df, dataChunk)    } }  # rbind()/cbind() cast all data to character, but x and y are numeric gammaplot.df$x <- as.numeric(as.character(gammaplot.df$x)) gammaplot.df$y <- as.numeric(as.character(gammaplot.df$y)) 

Turns out, the whole data frame contains character data, so I have to convert it back manually (took me a while to discover that in the first place!). SO search indicates that this happens because type variable is character. To avoid this (you can imagine performance issues on character data while building the data set!) I changed the code a bit:

gammaplot.ff <- function(type, gamma) {   ff <- switch(type,                 function(x) PowerUtility1d(x/10, gamma),                function(x) PowerUtility1d(2*pnorm(x)-1, gamma),                function(x) PowerUtility1d(2*pnorm(x/3)-1, gamma)               )   ff }  for (gm in gammaplot.gamma) {   for (tp in 1:3) {     fpts <- gammaplot.ff(tp, gm)(gammaplot.pts)         dataChunk <- cbind(tp, gm, gammaplot.pts, fpts)     colnames(dataChunk) <- names(gammaplot.df)     gammaplot.df <- rbind(gammaplot.df, dataChunk)   } } 

This works fine for me, but I lost a self-explanatory character parameter, which is a downside. Is there a way to keep the first version of function factory without an implicit conversion of all data to character?

If there's another way of achieving the same result, I'd be happy to try it out.

like image 498
tonytonov Avatar asked Oct 23 '13 07:10

tonytonov


People also ask

What can I use instead of Cbind in R?

data. frame() instead of cbind() .

What is the use of Rbind () and Cbind () in R?

cbind() and rbind() both create matrices by combining several vectors of the same length. cbind() combines vectors as columns, while rbind() combines them as rows.

What is the use of Cbind () function?

The cbind function is used to combine vectors, matrices and/or data frames by columns.


2 Answers

You can use rbind.data.frame and cbind.data.frame instead of rbind and cbind.

like image 101
shadow Avatar answered Oct 08 '22 18:10

shadow


I want to put @mtelesha 's comment to the front.

Use stringsAsFactors = FALSE in cbind or cbind.data.frame:

x <- data.frame(a = letters[1:5], b = 1:5) y <- cbind(x, c = LETTERS[1:5]) class(y$c) ## "factor" y <- cbind.data.frame(x, c = LETTERS[1:5]) class(y$c) ## "factor" y <- cbind(x, c = LETTERS[1:5], stringsAsFactors = FALSE) class(y$c) ## "character" y <- cbind.data.frame(x, c = LETTERS[1:5], stringsAsFactors = FALSE) class(y$c) ## "character" 

UPDATE (May 5, 2020):

As of R version 4.0.0, R uses a stringsAsFactors = FALSE default in calls to data.frame() and read.table().

https://developer.r-project.org/Blog/public/2020/02/16/stringsasfactors/

like image 22
HBat Avatar answered Oct 08 '22 18:10

HBat