I am trying to write a custom function in R that takes the mean and standard deviation, if the variable is numeric; or counts the number of occurrences for each level, if the variable is categorical. As an additional twist, I would like the function to only count the number of "Yes" if the variable is categorical and its levels include "Yes". Ideally, I would like this to be an input parameter, which if called, only counts the number of "Yes".
To demonstrate, let's assume we have the following data:
Height <- round(rnorm(10, 175, 10), 0)
weight <- round(rnorm(10, 70, 10), 0)
smoke <- c(rep("Yes", 3), rep("No", 4), rep("Unknown", 3))
problem <- c(rep("depression", 3), rep("insomnia", 2), rep("IBS", 5))
data <- as.data.frame(cbind(Height, weight, smoke, problem))
data$Height <- as.numeric(data$Height)
data$weight <- as.numeric(data$weight)
data$smoke <- factor(data$smoke, levels = c("Yes", "No", "Unknown"))
data$problem <- factor(data$problem, levels = c("depression", "insomnia", "IBS"))
The function I have is:
sumfun <- function(x){
if(is.numeric(x)){
m = round(mean(x, na.rm = T), digits = 2)
s = round(sd(x, na.rm = T), digits = 2)
return(list(cbind("", paste0(m, " ", "(", s, ")", " ", "/", " ", sum(!is.na(x))))))
} else
# (is.factor(x) | is.character(x)){
n = table(x)
pro = round(prop.table(n), 2)
return(list(cbind("", levels(x), paste0(n, " ", "(", pro*100, ")", " ", "/", sum(!is.na(x))))))
}
Because I want the output to be in a specific way, I wrote another function instead of using apply family. This function is:
tabsum <- function(table){
out <- data.frame()
for(col in colnames(table)){
# out <- rbind(out, list(col, "", ""))
out[nrow(out) + 1, 1] <- col
for(row in sumfun(table[, col])){
if(is.numeric(table[,col])){
out[nrow(out), 2:3] <- row
} else {
out[nrow(out), 2:3] <- c("", "")
out <- rbind(out, as.data.frame(row))
}
}
}
colnames(out) <- c("Variable", "Levels", "Mean (SD) or N (%)")
return(out)
}
Using these two function on the data set above produces:
tabsum(data)
| Variable | Levels | Mean (SD) or N (%) |
|---|---|---|
| Height | 174.5 (8) / 10 | |
| weight | 71.7 (8.68) / 10 | |
| smoke | ||
| Yes | 3 (30) /10 | |
| No | 4 (40) /10 | |
| Unknown | 3 (30) /10 | |
| problem | ||
| depression | 3 (30) /10 | |
| insomnia | 2 (20) /10 | |
| IBS | 5 (50) /10 |
What I would like to happen is:
tabsum(sumfun(data, "smoke"))
| Variable | Levels | Mean (SD) or N (%) |
|---|---|---|
| Height | 174.5 (8) / 10 | |
| weight | 71.7 (8.68) / 10 | |
| smoke | ||
| Yes | 3 (30) /10 | |
| problem | ||
| depression | 3 (30) /10 | |
| insomnia | 2 (20) /10 | |
| IBS | 5 (50) /10 |
Any ideas are highly appreciated. Kindly note that there may be less painful ways to do this, but I am learning how to write R functions and would like to do it via a custom function.
Thanks