Lab 02: Vectors, Types

The Crux of R

Most R code relies heavily on

Vectors

Oh my taxes!

Suppose we’d like to compute how much sales tax we’re paying for some of our purchases.

Oh my taxes!

Suppose we’d like to compute how much sales tax we’re paying for some of our purchases.

sales_tax <- 0.1025  # in Berkeley today
boba <- 7.0
books <- 54.50
food <- 24.75

Oh my taxes!

Suppose we’d like to compute how much sales tax we’re paying for some of our purchases.

sales_tax <- 0.1025  # in Berkeley today
boba <- 7.0
books <- 54.50
food <- 24.75

boba_tax <- boba * sales_tax
books_tax <- books * sales_tax
food_tax <- food * sales_tax

Oh my taxes!

Suppose we’d like to compute how much sales tax we’re paying for some of our purchases.

sales_tax <- 0.1025  # in Berkeley today
boba <- 7.0
books <- 54.50
food <- 24.75

boba_tax <- boba * sales_tax
books_tax <- books * sales_tax
food_tax <- food * sales_tax

sum(boba_tax, books_tax, food_tax)
[1] 8.840625

Very cumbersome…

Tedius and Error Prone

We computed the tax purchase by purchase…

Boba Cost

*

Tax Rate

=

Taxes

Book Cost

*

Tax Rate

=

Taxes

Food Cost

*

Tax Rate

=

Taxes

An Easier Way?

We’d like to do it all at once.

Costs

*

Tax Rate

=

Taxes

… where Costs contains all individual purchase costs, and Taxes contains all individual taxes.

For this, R provides vectors.

Vector

A contiguous array of 1 or more objects, where all objects are the same type.

Aside: Type?

Our values are ultimately bits in our computer. How does our program know how to interpret these bits?

By assigning a type to the value!

We may wants the bits to be interpreted as

  • integers
  • real numbers
  • text (strings)
  • logical values (true or false?)

… or something else.

Types: R’s Responsibility

To make sense of the bits…

Programming languages are responsible for keeping track of the types assigned to each variable.

Some languages1 are statically typed, which means types are explicit and unchanging (usually).

An Example: C++

int x = 3;
int y = 7;
double z = 0.4;
std::string school = "UC Berkeley";
x = "Berkeley High School" # ERROR, type changed!

R: Dynamically Typed

R is dynamically typed, which means we’re free to modify the type of a variable.

x <- "Is"
x <- 7 
x <- "my favorite number?" 
x <- TRUE

Note that R infers the variable’s type for us (in C and Java we’d need to write int x = 71).

R’s Not-So-Many Types

R only has a few types you should be aware of for this class.

  • Logical: TRUE/T or FALSE/F
  • Integer: Whole numbers (e.g., 7L, -5L, 0L)1
  • Double: Fractional numbers (e.g., 5.4, -8.3211, 8.0)
  • Character: Strings (e.g., "Hello, World!", "X")

Querying Type

Use the function typeof to get the type of a variable or literal1.

typeof("It was you who killed him!")
[1] "character"
typeof(3L)
[1] "integer"
noooo <- "No. I am your father."
typeof(noooo)
[1] "character"
typeof(3.5 + 7L)
[1] "double"

Modifying Type (Casting)

Casting is the act of modifying the type of a value.

Implicit

In certain contexts, R will cast a value to a different type automatically. We call this an implicit cast.

x <- 3L
y <- x + 0.5 # 3L cast to a double to complete the operation

Modifying Type (Casting) Yourself

Casting is the act of modifying the type of a value.

Explicit

Casts you ask R to make explicitly are called explicit casts. Use the as.<type> functions for this.

x <- 1
as.logical(x)
[1] TRUE
x <- 37.39303
as.character(x)
[1] "37.39303"
as.numeric(x >= 30)
[1] 1

Did we modify x?

as.<type>(x) returns a new value with the specified type.

x <- 1
typeof(x)
[1] "double"
typeof(as.logical(x))
[1] "logical"
typeof(x)  # unchanged!
[1] "double"

To modify x, reassign x.

x <- as.logical(x)
typeof(x)
[1] "logical"

Vector: Creation

A contiguous array of 1 or more objects, where all objects are the same type.

Creating Vectors

Use c (short for combine or concatenate) to create a vector.

x <- c(1, 3, 4, 8, 0, 9, 28, 30, 3)  # type: double
y <- c("Cory", "Dwinelle", "Evans")  # type: character
z <- c(TRUE, FALSE, FALSE, FALSE)    # type: logical
short_cut <- 10:100                  # a short cut for 10, 11, ..., 100

Vector: Access

A contiguous array of 1 or more objects, where all objects are the same type.

Accessing Elements

Use <vector>[N] to access the \(Nth\) element of a vector.

x[1]  # reference: x <- c(1, 3, 4, 8, 0, 9, 28, 30, 3)
[1] 1
y[2]  # reference: y <- c("Cory", "Dwinelle", "Evans") 
[1] "Dwinelle"
z[c(1, 3, 4)]  # reference: z <- c(TRUE, FALSE, FALSE, FALSE)
[1]  TRUE FALSE FALSE

R is not 0-indexed like most programming languages.

Vector: Operations

We can apply operations to vectors directly, causing the operation to be done to all its elements (vectorization).

x <- c(1, 2, 4, 8)
x * 10  # multiply all elements in x by 10, forming a new vector
[1] 10 20 40 80
x + c(1, 2, 3, 4)  # add two vectors together, component wise 
[1]  2  4  7 12

R will recycle values (loop to the start) if the vectors used in the operation aren’t of the same size.

c(0, 1, 2, 3) + c(1, 100)
[1]   1 101   3 103

Taxes are Due…

Recall our taxes code.

sales_tax <- 0.1025  # in Berkeley today
boba <- 7.0
books <- 54.50
food <- 24.75

boba_tax <- boba * sales_tax
books_tax <- books * sales_tax
food_tax <- food * sales_tax

sum(boba_tax, books_tax, food_tax)
[1] 8.840625

Taxes are Due… Now with Vectors!

sales_tax <- 0.1025
purchases <- c(7.0, 54.50, 24.75)
taxes <- purchases * sales_tax
sum(taxes)
[1] 8.840625

Great! But we’ve lost information. What do the values in purchases represent?

purchases <- c(boba = 7.0, books = 54.50, food = 24.75)

We can associate a name with each value in a vector.

purchases
 boba books  food 
 7.00 54.50 24.75 

Access with Names

purchases <- c(boba = 7.0, books = 54.50, food = 24.75)

We can associate a name with each value in a vector.

purchases
 boba books  food 
 7.00 54.50 24.75 

Access is possible with names, <vector>[<element-name>].

purchases["boba"]
boba 
   7 
purchases[c("books", "food")]
books  food 
54.50 24.75 

On Forming Vectors

The c function can concatenate vectors (flatten them).

c(c(1, 2, 3), 4, c(5, 6))
[1] 1 2 3 4 5 6

Want a vector of \(N\) identical values? Use rep!

rep("->", 10)
 [1] "->" "->" "->" "->" "->" "->" "->" "->" "->" "->"
rep(c("->", "<-"), 5)  # also flattens
 [1] "->" "<-" "->" "<-" "->" "<-" "->" "<-" "->" "<-"

Want a sequence of values from \(A\) to \(B\) by increments of \(I\)? Use seq!

seq(0, 12, 3)   # from 0 (A) to 12 (B) by increments of 2 (I)
[1]  0  3  6  9 12