Tutorial 1

Author

Yu Cheng Hsu, BBMS1021 teaching team

Published

September 8, 2025

Installing R

First, you need to download and install the latest version of R.

  1. Go to R official website
  2. Click on “download R”
  3. Save the installation file
  4. Run the installation file and follow the prompts to install R (default settings are fine)

Installing RStudio

  1. Go to RStudio
  2. Click the big blue download button to download the installation file
  3. Run the installation file and follow the prompts to install RStudio (default settings are fine)

Cheatsheets

If you forget how to use it or are not sure, there are some cheatsheets for you: RStudio cheatsheet

Scientific computing

  • Q1: Write a function to solve a quadratic equation

\[ ax^2+bx+c=0 \]

Using only material covered so far (warns when the discriminant is negative):

With flow control (later lecture): return NaN when b^2 - 4*a*c < 0.

Lab overview

You have been hired to audit the sales records of the Downtown Pop-Up Market, which sold Snacks, Drinks, Merch, and Stickers over a three-day weekend.

Work through each section by running the code examples and answering the questions. Answer keys and worked code are in hidden instructor blocks on the live page (and in the teacher-notes pack).


1. Vector arithmetic and recycling

Before opening, the store set these standard retail prices:

  • Snacks: $12
  • Drinks: $5
  • Merch: $35
  • Stickers: $4

Scalar broadcasting vs. vector operations

Run the following chunk. You will use base_prices for the rest of this lab.

  1. Add 12.5% sales tax to each product’s base price. Store the result in taxed_prices. The tax rate is already given below.
  1. Apply the discount rates in discount_rates to the base prices (not the taxed prices). Store the result in discounted_prices.

After you have created taxed_prices and discounted_prices, run this chunk to build a data frame named price_df:

Questions

  1. What does R do when you multiply a vector of length 4 by a single number such as (1 + tax_rate) (a vector of length 1)?

  2. Suppose you scramble the names of discount_rates to c(Stickers = 0.20, Merch = 0.15, Drinks = 0.00, Snacks = 0.05) but leave base_prices in the original order. Do the usual arithmetic operators (*, +, …) match values by name or by position (1st with 1st, 2nd with 2nd)?

Answer key

  1. Recycling (often called broadcasting here). R has no separate scalar type: 1 + tax_rate is an atomic vector of length 1. R recycles that single value to length 4 so pairwise multiplication can run.

  2. By position, not by name. Binary arithmetic ignores names. Index 1 multiplies with index 1, and so on. If discount_rates is reordered and base_prices is not, the wrong discount is applied. To align by name you would need something like discount_rates[names(base_prices)].

Indexing

Extract the Sale_Price column from price_df. Hint: there are several valid approaches; try more than one.

To read the cell in row 3, column 3, you can use either of these:

Questions

  1. Compare price_df[3, 3] with price_df["Merch", "Sale_Price"]. Which is easier for another reader to understand without looking at the data?

  2. Next month the store adds a column SKU_Number as column 1, so every later column shifts one place to the right. What would price_df[, 3] refer to then, compared with price_df[, "Sale_Price"]? Which is less sensitive to that change?

  3. Compare the printed result and class() of price_df$Sale_Price, price_df["Sale_Price"], and price_df[["Sale_Price"]]. Why does [ without a comma return a one-column data frame, while $ and [[ extract a numeric vector?

Answer key

  1. price_df["Merch", "Sale_Price"] is clearer: it names the row and the column.

  2. After inserting SKU_Number at the front, price_df[, 3] would be the old column 2 (Discount). price_df[, "Sale_Price"] still means sale price no matter how many columns you add, so it is the more robust choice.

  3. $ and [[ pull out the vector stored in that column. [ with no comma subsets the data frame as a list of columns, so price_df["Sale_Price"] (and price_df[3] for the third column) stays a one-column data.frame.

Recycling rules and warnings

The market tests a packaging fee on the four catalogue items. Run the chunk below and inspect the output.

Questions

  1. Why does adding pack_fee_2 (length 2) to base_prices (length 4) run without a warning? What pattern of fees is applied to Snacks, Drinks, Merch, and Stickers?

  2. Why does adding pack_fee_3 (length 3) warn, and what values does R actually add to the four items?

  3. Why can “even” recycling (lengths that divide evenly) be more dangerous in an audit than the warning case?

Answer key

  1. R recycles the shorter vector until it matches the longer one. When length(longer) %% length(shorter) == 0 (here \(4 \bmod 2 = 0\)), R treats the repeat as intentional and stays silent. The fees are \(+1, +2, +1, +2\).

  2. \(4 \bmod 3 \neq 0\), so R still wraps around (the fourth item gets the first fee, \(+1\)) but warns: longer object length is not a multiple of shorter object length.

  3. If someone passed c(5, 0), R would add $5 to Snacks and Merch and $0 to Drinks and Stickers with no warning. The code is valid, so the accounting error is easy to miss. The mismatched-length warning at least flags that something odd happened.

Finding help with ?

Inspect taxed_prices and round(taxed_prices):

Questions

  1. Does round(taxed_prices) match what you expected? Hint: look at values that sit exactly on .5, then try a few extra examples of your own.

  2. Type ?round in the console and read the Details section.

    • Which international standard does R follow?
    • How does that standard explain what you saw for round(taxed_prices)?

Answer key

  1. Half-way cases do not always round “away from zero” or “always up”. They follow round half to even (the adjacent even integer).

  2. IEC 60559 / IEEE 754. That is why a .5 can round up or down depending on whether the neighbouring integer is even.

Data types and coercion

During peak hours, an employee types "PROMO" into the register price column instead of $0 for a free drink:

Questions

  1. What is the data type of "PROMO" on its own?

  2. After you build register_log as above, what is the data type of register_log[1]? Can you compute register_log[1] + register_log[3]?

  3. What is R’s usual coercion hierarchy for atomic vectors (from most specific to most flexible)?

Answer key

  1. Character.

  2. Character as well — one character value forces the whole vector to character — so register_log[1] + register_log[3] is not valid numeric addition.

  3. \[ \text{logical} \longrightarrow \text{integer} \longrightarrow \text{double (numeric)} \longrightarrow \text{character} \]