Reputation: 1433
I have the following R functions which I want to use to obtain the sum, sum of squares and sum of cubes of any numeric vector:
Functions Corrected
ss <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x, .combine = "+") %dopar% {i}
}
sss <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x, .combine = "+") %dopar% {i^2}
}
ssq <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x, .combine = "+") %dopar% {i^3}
}
which I want to produce the sum of the vector, the sum of the square of the vector and the sum of the cube of the same vector. I want it to print the three results once I run just one function with the will be contained in the R package documentation.
I know how to write an R package with just one function for just one task by documenting the R folder and its files and also DESCRIPTION file while roxygen2
with devtools
do the rest for me.
I want
If x <- c(1, 2) I want something like this format.
ss sss qss
3 5 9
with just a function from the package.
Please state the vector you are using with your output.
Upvotes: 2
Views: 912
Reputation: 3326
There are several ways to consolidate your functionality and its documentation.
Because you asked how to consolidate and document your existing functions, I have not improved your functions. How you choose to implement your ss*()
functions is up to you.
Strive to be consistent with the principles of modular programming. It is your responsibility to ensure that each of your functions does its own job, so that other functions can rely on them. So it is your responsibility to correct any errors at their source. If you do so, then the corrections will "bubble up" from your helper functions into the rest of your package—you will "kill two bugs with one stone".
As it stands, however, there are some noticeable issues with your code.
As of now, the question has been edited to correct the error below, according to my first suggestion. Also, the **
operator has been wisely replaced with ^
.
Your functions actually square and cube x
redundantly:
sss <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x*x, .combine = "+") %dopar% {i**2}
# ^^ ^^^
# First time squaring. Second time squaring.
}
ssq <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x*x*x, .combine = "+") %dopar% {i**3}
# ^^^^ ^^^
# First time cubing. Second time cubing.
}
The result is that sss()
actually uses the 4th (not the 2nd) power, and ssq()
uses the 9th (not the 3rd) power:
sss(x = c(1,2))
# [1] 17
ssq(x = c(1,2))
# [1] 513
You must either avoid multiplying x
by itself
sss <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x, .combine = "+") %dopar% {i**2}
# ^
# Corrected
}
ssq <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x, .combine = "+") %dopar% {i**3}
# ^
# Corrected
}
or remove the **2
and **3
after %dopar% {i
sss <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x*x, .combine = "+") %dopar% {i}
# ^
# Corrected
}
ssq <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x*x*x, .combine = "+") %dopar% {i}
# ^
# Corrected
}
to get the output you intended:
sss(x = c(1,2))
# [1] 5
ssq(x = c(1,2))
# [1] 9
The first correction is more extensible, since
foreach::foreach(i = x, .combine = "+") %dopar% {i**10}
is shorter to type than
foreach::foreach(i = x*x*x*x*x*x*x*x*x*x, .combine = "+") %dopar% {i}
for higher powers like 10
.
Frankly, your code is very convoluted for such simple operations. If you actually need custom functions at all — and a separate function for each sum — you could just do this with base
R:
ss <- function(x){
sum(x)
}
sss <- function(x){
sum(x^2)
}
ssq <- function(x){
sum(x^3)
}
Per the R documentation for...well...documenting R, you can describe several related functions within the same .Rd
document.
Consider how base::nrow()
is documented together with related functions like ncol
:
Description
nrow
andncol
return the number of rows or columns present inx
.NCOL
andNROW
do the same treating a vector as 1-column matrix, even a 0-length vector, compatibly withas.matrix()
orcbind()
, see the example.Usage
nrow(x) ncol(x) NCOL(x) NROW(x)
Arguments
x
a vector, array, data frame, or
NULL
.⋮
You might want to document ss()
, sss()
, and ssq()
all together, on the same page. This can be done via roxygen2
, by using the @describeIn
tag
#' Obtain the sum.
# ⋮
#' @param x A vector of \code{numeric} values.
# ⋮
ss <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x, .combine = "+") %dopar% {i}
}
#' @describeIn ss Obtain the sum of squares.
sss <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x, .combine = "+") %dopar% {i**2}
}
#' @describeIn ss Obtain the sum of cubes.
ssq <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x, .combine = "+") %dopar% {i**3}
}
or alternatively by using the @rdname
tag:
#' Obtain the sums of various powers: \code{ss} for original values, \code{sss} for their squares, and \code{ssq} for their cubes.
# ⋮
#' @param x A vector of \code{numeric} values.
# ⋮
ss <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x, .combine = "+") %dopar% {i}
}
#' @rdname ss
sss <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x, .combine = "+") %dopar% {i**2}
}
#' @rdname ss
ssq <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x, .combine = "+") %dopar% {i**3}
}
You might want to "declutter" your set of @export
ed functions.
On the one hand, you could create a new function one_sum()
to wrap your existing functions; where one_sum()
will be the only @export
ed function:
#' Obtain the sum of any available power.
# ⋮
#' @param x A vector of \code{numeric} values.
#' @param mode \code{character}. The approach to use when summing: \code{"ss"} to sum the values themselves; \code{"sss"} to sum their squares; and \code{"ssq"} to sum their cubes.
# ⋮
#' @export
# ⋮
one_sum <- function(x, mode = c("ss", "sss", "ssq")) {
if(mode == "ss") {
ss(x)
} else if(mode == "sss") {
sss(x)
} else if(mode == "ssq") {
ssq(x)
} else {
stop("'mode' must be one of \"ss\", \"sss\", or \"ssq\".")
}
}
On the other hand, you could replace everything with a single function any_sum()
, which has another parameter power
as the power used to compute the sum:
#' Obtain the sum of any power.
# ⋮
#' @param x A vector of \code{numeric} values.
#' @param power \code{numeric}. The power to which the addends in \code{x} should be raised.
# ⋮
any_sum <- function(x, power) {
sum(x^power)
}
To achieve the particular output you specified
I want
ss sss qss 30 300 90000
with just a function from the package.
you can either exploit your existing functions or create an entirely new function.
On the one hand, you can leverage your existing functions in a new three_sums()
function; where three_sums()
will be the only @export
ed function:
#' Obtain at once the sums of the three available powers.
# ⋮
#' @param x A vector of \code{numeric} values.
# ⋮
#' @export
three_sums <- function(x) {
setnames(c(ss(x), sss(x), ssq(x)), c("ss", "sss", "qss"))
}
On the other hand, you could replace everything with a single function all_sums()
, which has another parameter powers
as the different powers used for computing the sums.
#' Obtain at once the sums of all given powers.
# ⋮
#' @param x A vector of \code{numeric} values, to raise to powers and add.
#' @param powers A vector of \code{numeric} values: the powers to which the addends will be raised.
# ⋮
all_sums <- function(x, powers = 1:3) {
setNames(object = sapply(X = powers,
FUN = function(n){sum(x^n)},
simplify = TRUE),
nm = powers)
}
Here, you can specify each and every power, whose sum you want to see. For example, the following call
all_sums(x = c(1, 2), powers = c(3, 4, 6, 9))
will give you the sum of cubes (3
rd powers), of 4
th powers, of 6
th powers, and of 9
th powers; all for the values in the vector c(1, 2)
:
3 4 6 9
9 17 65 513
When powers
is unspecified, then by default
all_sums(x = c(1, 2))
will use the 1
st, 2
nd (square), and 3
rd (cubic) powers
1 2 3
3 5 9
as you desired in your sample output.
Upvotes: 7
Reputation: 204
EDIT: i've changed the code so that the output is a vector instead of a list.
You can combine your functions into a single function. Here's an example:
sums <- function(x, methods = c("sum", "squaredsum", "cubedsum")){
output <- c()
if("sum" %in% methods){
output <- c(output, ss = ss(x))
}
if("squaredsum" %in% methods){
output <- c(output, sss = sss(x))
}
if("cubedsum" %in% methods){
output <- c(output, ssq = ssq(x))
}
return(output)
}
by default, all three of your functions are called and the results are returned in a list.
You can specify just one or more of the functions, in that case it will only return the outputs of the called functions.
In your documentation, you can now treat each of the possible methods as variable that can be set.'
EDIT
there's a mistake in your cube function. a cube is not taken by i***2
. It's i**3
. The correct function is:
ssq <- function(x){
`%dopar%` <- foreach::`%dopar%`
foreach::foreach(i = x*x*x, .combine = "+") %dopar% {i**3}
}
Upvotes: 1