I'm having a bit of a problem programming R for Sweave, and the #rstats twitter group often points here, so I thought I'd put this question to the SO crowd. I'm an analyst- not a programmer- so go easy on my first post.
Here's the problem: I am drafting a survey report in Sweave with R and would like to report the marginal returns in line using \Sexpr{}
. For example, rather than saying:
Only 14% of respondents said 'X'.
I want to write the report like this:
Only \Sexpr{p.mean(variable)}$\%$ of respondents said 'X'.
The problem is that Sweave converts the results of the expression in \Sexpr{}
to a character string, which means that the output from the expression in R and the output that appears in my document are different. For example, above I use the function 'p.mean':
p.mean<- function (x) {options(digits=1)
mmm<-weighted.mean(x, weight=weight, na.rm=T)
print(100*mmm)
}
In R, the output looks like this:
p.mean(variable)
>14
but when I use \Sexpr{p.mean(variable)}
, I get an unrounded character string (in this case: 13.5857142857143) in my document. I have tried to limit the output of my function to digits=1
in the global environment, in the function itself, and and in various commands. It only seems to contain what R prints, not the character transformation that is the result of the expression and which eventually prints in the LaTeX file.
as.character(p.mean(variable))
>[1] 14
>[1] "13.5857142857143"
Does anyone know what I can do to limit the digits printed in the LaTeX file, either by reprogramming the R function or with a setting in Sweave or \Sexpr{}
?
@KennyTM got it. @David, you should avoid options(digits = 1)
since it will affect all of your calculations (it will suppress decimals in each output afterwards). So use round()
function after applying the weighted.mean()
. Something like this:
\Sexpr{round(p.mean(x))}
And do not use print()
, but return()
. Here's why:
> set.seed(1234)
> x <- rnorm(100)
> foo <- function(x) {
res <- mean(x) + 5
print(res)
}
> foo(x)
[1] 5
> foo(x) + 10
[1] 5
[1] 15
Use return()
or just type the resulting variable in the last line:
> bar <- function(x) {
res <- mean(x) + 5
return(res)
}
> bar(x) + 10
[1] 15
So, rewrite your function, and be sure to use as.character()
... you have all the bits, now just put it all together.
P.S.
I'm not sure how you function works... I've never used weighed mean in my analysis. The bit that's puzzling me the most is weight=weight
. Wouldn't it be nicer to put one more argument in function? Frankly, I'm still amazed by the fact that your function is giving you right result... probably because you have weight
variable defined prior to function definition. [EDIT] You will not get the weighted mean with your function if you don't have weight
function predefined, but "regular" mean!
I hope this one helped you!
Kind regards,
Aleksandar
Try 'format':
options(digits=1)
and then:
\Sexpr{format(p.mean(variable))}
You can also use the 'nsmall' argument:
options(digits=3)
...
\Sexpr{format(sqrt(2)-0.41,nsmall=2)}
And you can also try 'sprintf' if you're familiar with C.
as.character(round(p.mean(variable)))
?
the sprintf() function is great for formatting numerical output.
The siunitx package can also be used to format numbers in sweave.
Code for Sweave
The following script shows how to use it to format numbers, the syntax is for Sweave. In the preamble you can set your default formatting like
\sisetup{
round-mode = figures,
round-precision = 3
}
and then override it in commands \Sexpr{num(pi,round_precision=2)}
\documentclass[a4paper]{article}
\usepackage{siunitx}
\usepackage{Sweave}
\title{siunitx}
\sisetup{
round-mode = figures,
round-precision = 3
}
\begin{document}
\maketitle
<<sanitize_number,echo=FALSE>>=
num <- function(x,round_precision=NULL)
{
if (is.null(round_precision)) {
return(sprintf("\\\\num{%s}", x))
} else {
return(sprintf("\\\\num[round-precision=%s]{%s}",round_precision, x))
}
}
@
Examples :\\
round\_precision= 2 gives : \Sexpr{num(pi,round_precision=2)} \\
round\_precision= 4 gives : \Sexpr{num(pi,round_precision=4)}\\
Default formatting gives : \Sexpr{num(pi)}
\end{document}
Code for knitr
In knitr by default, the numbers in \Sexpr are rounded when the option options(digits = 2)
is set. But if you want different rounding in different places the following code works, it needs to be adapted as there is no need to double escape antislashes in \Sexpr in knitr.
num <- function(x,round_precision=NULL)
{
if (is.null(round_precision)) {
return(sprintf("\\num{%s}", x))
} else {
return(sprintf("\\num[round-precision=%s]{%s}",round_precision, x))
}
}