tags:

views:

465

answers:

6

I'm trying to round an output from a simple by() function in R. This is what I have...

> by(glaciers[,1:3],glaciers$activity.level,mean)

glaciers$activity.level: Active
       aspect  sun.duration      latitude 
-9.444444e+00  1.771778e+03  3.247643e+09 
-------------------------------------------
glaciers$activity.level: Inactive
      aspect sun.duration     latitude 
1.041667e+01 2.067583e+03 4.048301e+09 
-------------------------------------------
glaciers$activity.level: Relict
      aspect sun.duration     latitude 
1.766667e+01 2.168000e+03 2.759283e+09

How can I get my output to round to say 5 decimal places, and still keep the factors? I tried round(by(glaciers[,1:3],glaciers$activity.level,mean),5) but get an error Non-numeric argument to mathematical function.

+3  A: 
by(glaciers[,1:3], glaciers$activity.level, function(x){round(mean(x),5)})

UPDATE: Here is a working example

glaciers <- as.data.frame(matrix(rnorm(1000),ncol=4)) 
glaciers[,4] <- sample(0:3,250,replace=TRUE) 
colnames(glaciers) <- c("A","B","C","activity.level") 
by(glaciers[,1:3], glaciers$activity.level, function(x){round(mean(x),5)})
Rob Hyndman
Rob,I also tried this method but am still getting non-rounded numbers with exponents as above. Not sure why the round() function is going through.
Jb
I played around with this more and found that if I round by .5 say then it will actually round but to only 1 decimal place. I want to round to say 3-5 decimal places but using the whole number doesn't seem to do this.
Jb
I don't know what you're doing. I've updated my answer to include a working example.
Rob Hyndman
Rob,If you look at my outcome above I have scientific notation as an outcome. The round command doesn't seem to work well with S.N. because the numbers are sooo dang long. I looked in the help(round) and found the signif. This will round by whatever precision you like, but still in the scientific notation. I ended up using your function placement in the by command but used .5 instead of 5 and it got me real number to 1 decimal place. by(glaciers[,1:3], glaciers$activity.level, function(x){round(mean(x),.5)})
Jb
+4  A: 

If you already have the output saved to a variable, say x:

x <- by(glaciers[,1:3],glaciers$activity.level,mean)

Then apply round() to each element (the output of by() in this case is a list).

x[] <- lapply(x,round,5)
x

reassigning to x[] rather than x allows x to retain attributes attached to it from by().

Edit: round() actually changes the value of the variables but is decoupled from its printing. If you want to suppress the scientific notation output format, use format="f" argument to formatC()

> round(1.2345e10,5)
[1] 1.2345e+10
> formatC(1.2345e10,digits=5,format="f")
[1] "12345000000.00000"

So the correction to the expression originally posted would be

x[] <- lapply(x,formatC,digits=5,format="f")
Stephen
Stephen,I tried this method but I'm still getting non-rounded numbers with exponent outputs as above. Any ideas?
Jb
+1  A: 

Do you want to round or to just truncate the number of digits shown? If the latter, use options(digits=3) or whatever.

> by(mpg[,8:9], mpg$cyl, mean)
mpg$cyl: 4
   cty    hwy 
21.012 28.802 
------------------------------------------------------------ 
mpg$cyl: 5
  cty   hwy 
20.50 28.75 
------------------------------------------------------------ 
mpg$cyl: 6
   cty    hwy 
16.215 22.823 
------------------------------------------------------------ 
mpg$cyl: 8
   cty    hwy 
12.571 17.629 
> options(digits=3)
> by(mpg[,8:9], mpg$cyl, mean)
mpg$cyl: 4
 cty  hwy 
21.0 28.8 
------------------------------------------------------------ 
mpg$cyl: 5
 cty  hwy 
20.5 28.8 
------------------------------------------------------------ 
mpg$cyl: 6
 cty  hwy 
16.2 22.8 
------------------------------------------------------------ 
mpg$cyl: 8
 cty  hwy 
12.6 17.6
Harlan
+1  A: 

Only have a couple of minutes, but you might try looking at the format(), formatC(), and prettyNum() functions. Their help files look like gibberish to me right now, but I haven't slept much. However, I did use one of these functions - most likely formatC() - for a Sweave report some months ago in which I needed very specifically formatted numbers.

Matt Parker
To clarify: you'd need to put it into the by() function as Rob and Stephen have done with round().
Matt Parker
+4  A: 

round() doesn't make sense in this instance, since you're working with very large numebrs. You want to use the format() command, and choose how many digits to display. For instance, to show 3 significant digits:

by(glaciers[,1:3], glaciers$activity.level, function(x) {
      as.numeric(format(mean(x), digits=3))
})
Shane
+1  A: 

You asked "How can I get my output to round to say 5 decimal places?" but I think what you meant was "How can I get my output to show say 6 significant figures?" The following code combines two of the previous answers -- the idea of reassigning to res[], and the use of signif rather than round.

glaciers <- data.frame(aspect=runif(20)*100,
                       sun.duration=runif(20)*10000,
                       latitude=runif(20)*10^9,
                       activity.level=sample(c('Active','Inactive','Relict'),20,replace=TRUE))
res <- by(glaciers[,1:3],glaciers$activity.level,mean)
res[] <- lapply(res,signif,3)
res

This code produces the following output:

glaciers$activity.level: Active
      aspect sun.duration     latitude 
    3.66e+01     4.72e+03     4.56e+08 
------------------------------------------------- 
glaciers$activity.level: Inactive
      aspect sun.duration     latitude 
    5.81e+01     5.28e+03     4.83e+08 
------------------------------------------------- 
glaciers$activity.level: Relict
      aspect sun.duration     latitude 
    6.08e+01     4.75e+03     3.98e+08
DamonJW