Commenting Protocol

This page shows you how we comment our code and what the general protocol is.

  • Each assigned function needs to have properly documented parameters, a title, one line of description and at least one example. It should follow roxygen2 syntax, and should be written in markdown. See the below Conjoint function for a good example of an overly detailed function (as all our functions should be!)
#' @import dplyr
#' @importFrom aws.s3 s3read_using
#' @importFrom readr read_csv
#' @importFrom readxl read_xlsx
#' @importFrom tools file_ext
#'
#' @title Read Conjoint Data
#'
#' @description Read conjoint data and return a list with Design and Answers
#'  suitable for the rest of the `cjt_` functions family.
#'
#' @param path Path to a file (character) to be read or a dataframe object.
#'
#' This file or object should be a dataframe with `response_id` and columns containing `cjt` and `des_`.
#' We use [tidyselect::select_helpers] to determine the answers (`cjt`) and design (`des_`)
#'
#' @param type A character(1).
#' Type of conjoint experiment:
#'   * `"CBC-FP"`: (default value) A full profile option with both attributes and levels.
#'   * `"CBC-PP-NOLEV"`: A choice based conjoint that consists solely of attributes without any
#'   levels that vary in an attribute. Typically contains a large number of attributes (50+) and is
#'   thus required to be a partial profile design.
#'
#' @param none A character(1).
#' Type of none response option:
#'   * `"NN"`: No None - (default value) There was no `none` choice option.
#'   * `"SRN"`: Single-Response None. There was a third choice called none in the choices provided.
#'   * `"DRN"`: Dual-Response None. There was a follow-up question asking if given the choice,
#'  they'd actually choose it (e.g. would you actually buy the product).
#'
#' @param bucket A character(1). Name of the AWS S3 bucket. If provided data is read from AWS.
#'
#' @return A list.
#'   * Two character(1) elements:
#'     * `type`: Type of conjoint experiment
#'     * `none`: Type of none response option
#'   * Two tbl elements:
#'     * `design`: Dataset with the design for each respondent
#'     * `answers`: Dataset with the choices for each respondent
#'
#' @details
#'
#'
#'The Choice-based conjoint analysis (CBC) (also known as discrete-choice conjoint analysis) is the
#'most common form of conjoint analysis. Choice-based conjoint requires the respondent to choose their
#'most preferred full-profile concept. This choice is made repeatedly from sets of 3–5 full profile
#'concepts.
#'
#'This choice activity is thought to simulate an actual buying situation, thereby mimicking actual
#'shopping behavior. The importance and preference for the attribute features and levels can be
#'mathematically deduced from the trade-offs made when selecting one (or none) of the available choices.
#'Choice-based conjoint designs are contingent on the number of features and levels.
#'Often, that number is large and an experimental design is implemented to avoid respondent fatigue.
#'
#'The output of a Choice-based conjoint analysis provides excellent estimates of the importance of
#'the features, especially in regards to pricing. Results can estimate the value of each level
#'and the combinations that make up optimal products. Simulators report the preference and value
#'of a selected package and the expected choice share (surrogate for market share).
#'
#' @export
#'
#' @examples
#' # Read one of three example datasets available in the package.
#' cbc_fp <- cjt_read_toy_data("CBC-FP", none = 'SRN')
#' cbc_fp_drn <- cjt_read_toy_data("CBC-FP", none = 'DRN')
#' cbc_pp_nolev <- cjt_read_toy_data("CBC-PP-NOLEV")
#'
#' \dontrun{
#' # All the sources could also be read from the rds files.
#' # If bucket is provided the data is read from aws.
#' cjt_read_data(path = "path/to/spss/data/file.sav",
#'              type = "yougov",
#'              design_file = "path/to/design/data/file.csv",
#'              bucket = "bucket/name")
#' }
cjt_read_data <- function(path,
                          type = c("CBC-FP",
                                   "CBC-PP-NOLEV"),
                          none = c("NN",
                                   "SRN",
                                   "DRN"),
                          bucket = NULL) {

  type <- match.arg(type)
  none <- match.arg(none)

  path_is_character <- is.character(path)

  # If the path is a character, read the filepath. If not, we assume the object is the data frame.
  if(path_is_character){
    file_extension <- file_ext(path)

    read_fnc <- switch(file_extension,
                       rds = readRDS,
                       sav = read_spss,
                       csv = read_csv,
                       xlsx = read_xlsx)

    bucket_is_null <- is.null(bucket)

    if (bucket_is_null) {
      if (!file.exists(path)) {
        stop("Incorrect file path.")
      }
      df <- read_fnc(path)

    } else {
      df <- s3read_using(FUN = read_fnc, object = path, bucket = bucket)
    }
  } else{
    df <- path
  }


  answers <- df %>% select(response_id, contains('cjt'))
  design <- df %>% select(response_id, contains('des_'))



  list(type = type, none = none, design = design, answers = answers)
}

#' @export
#'
#' @rdname cjt_read_data
cjt_read_toy_data <- function(type = c("CBC-FP", "CBC-PP-NOLEV"),
                              none = c("NN",
                                       "SRN",
                                       "DRN")) {
  type <- match.arg(type)
  none <- match.arg(none)
  switch(type,
         `CBC-FP` = cjt_read_data(
           get_package_data_path(paste0(type,
                                        ifelse(none == "DRN", '-DRN', ''),
                                        ".csv")), type, none = none
         ),
         `CBC-PP-NOLEV` = cjt_read_data(
           get_package_data_path(paste0(type, ".csv")), type, none = none
         ))
}

get_package_data_path <- function(file) {
  system.file("extdata", file, package = "g6tr.cjt")
}

globalVariables(c("read_spss"))
  • Function’s code are explained with comments every 2-3 lines like above