# Assigning Objects
height <- 47.5
age <- 122
# We can do math with objects
height <- height * 2 # multiply
# Notice how we are overwriting the original value of height. R replaces the old value with the new one.
age <- age - 20 # subtract
height_index <- height/age # divide
height_sq <- height^2 # raise to an exponent
# This is simplistic and you'll rarely do it in real-world scenarios. 1.2: Intro to Coding in R
Introduction to Coding
Learning Outcomes
- Students will be able to define the following terms: object, assignment, vector, function, data frame
- Students will be able to run code line-by-line and as code chunks from a Quarto file.
- Students will be able to write code assigning values to variables and use these variables to perform various operations.
- Students will be able to recall and explain how functions operate, and the basic syntax around functions (arguments, auto-completion, parentheses).
- Students will be able to differentiate different data classes in R.
Assigning Objects
An object is simply a name that stores a value in R so that we can reuse it later.
Assignments are really key to almost everything we do in R. This is how we create permanence in R. Anything can be saved to an object, and we do this with the assignment operator, <-.
The short-cut for <- is Alt + - (or Option + - on a Mac)
1-Dimensional Data: Vectors
We can also assign more complex group of elements of the same type to a particular object. This is called a vector, a basic data structure in R.
All elements in a vector must be the same type (all numbers, all text, etc.).
weight_kg <- c(3, 2, 4, 9, 7, 3, 6)
weight_kg[1] 3 2 4 9 7 3 6
animals <- c("cat", "rat", "bat", "rat")
animals[1] "cat" "rat" "bat" "rat"
Data classes
There are a few main types of data in R, and they behave differently. We call these types of data “classes.”
- numeric / double (numbers, decimals allowed)
- integer (no decimals allowed)
- character (letters or mixture)
- logical (True or False; T or F)
- factors (best used for data that need to be in a specific order; levels indicate the order)
# Examples of different data classes
weight_kg # numeric, integer, double[1] 3 2 4 9 7 3 6
animals # character[1] "cat" "rat" "bat" "rat"
animal_size <- c("medium", "large", "small", "medium")
animal_size <- factor(animal_size, levels = c("small", "medium", "large"))
animal_size # factor, put in order [1] medium large small medium
Levels: small medium large
logic <- c(T, F, F, T) # logical
logic[1] TRUE FALSE FALSE TRUE
Vectors have to contain elements that are all of the same class. What happens if we put data of different classes into one vector?
vec <- c(1, 1.000, "1")
# R converts everything to character because one element is text.Subsetting Vectors
Sometimes we want to keep specific values from a vector. This is called subsetting (taking a smaller set of the original).
We can subset vectors in two different ways:
- by index (position)
- by condition
Regardless of which type of subsetting we choose, we indicate that we want to subset by using square brackets: [].
Subsetting by Index
When we subset by index, we are subsetting based on the position of an element in the vector.
# Use square brackets
weight_kg[2] # returns the 2nd element in the vector[1] 2
weight_kg[2:4] # returns the 2nd, 3rd, and 4th elements in the vector[1] 2 4 9
Subsetting by Condition
Sometimes we don’t know or don’t want to list out all of the locations for the data we need. Instead, we might want to subset based on a quality of the data itself.
To do this, we set a “condition” that must be met in order for the data to be returned.
# let's start with a condition
weight_kg > 5[1] FALSE FALSE FALSE TRUE TRUE FALSE TRUE
# this returns a logical vector (true/false) that tells us which positions meet the condition.
# we now put that condition inside the square brackets
weight_kg[weight_kg > 5][1] 9 7 6
# we can also do this with characters
animals == "cat"[1] TRUE FALSE FALSE FALSE
animals[animals == "cat"][1] "cat"
Functions
Functions are pre-written bits of code that perform specific tasks for us. Functions are always followed by parentheses.
Anything you type into the parentheses are called arguments. Arguments are pieces of information that we give to a function so it performs its task the way we want it to. To add more than one argument, you separate them with a comma.
## Functions
weight_kg_mean <- mean(weight_kg) # average of the weight_kg vector from above
weight_kg_mean[1] 4.857143
# separate arguments with commas
round(weight_kg_mean) # rounding[1] 5
round(weight_kg_mean, digits = 2) # round to 2 digits past 0[1] 4.86
To get more information about a function, use the help() function or ?name_of_function.
help(round) # or type ?roundWe can use a function called class() to figure out the data type of a vector.
class(weight_kg)[1] "numeric"
Small Group Challenge
Let’s practice! Write a few lines of code that do the following:
- create a vector with numbers from 6 to 1 (6, 5, 4, 3, 2, 1)
- assign the vector to an object named
six_to_one - subset
six_to_oneto include the last 3 numbers (should include 3, 2, 1) - find the sum of the numbers (hint: use the
sum()function)
# Write your code hereFinished early? See if you can condense your code down any further or turn around and help out a neighbor.
Answer: 6
six_to_one <- c(6, 5, 4, 3, 2, 1)
six_to_one[1] 6 5 4 3 2 1
# subsetting by index (position)
last_three <- six_to_one[4:6]
last_three[1] 3 2 1
# alternate: subsetting by condition
last_three <- six_to_one[six_to_one < 4]
last_three[1] 3 2 1
sum(last_three)[1] 6
# more condensed version
six_to_one <- seq(6,1)
sum(six_to_one[4:6])[1] 6
2-Dimensional Data: Data Frames
Most of the data you will encounter is two-dimensional (i.e., it has columns and rows). Its structure resembles a spreadsheet. R is really good with these types of data. We call these 2D object data frames.
- rows go side-to-side
- columns go up-and-down
Columns typically represent variables (a factor, trait, or condition) we are interested in.
Rows represent observations. Each row will be one set of observations.

Data frames are made up of multiple vectors. Each vector becomes a column.
# Create a simple data frame from scratch
plants <- data.frame(height = c(55, 17, 42, 47, 68, 39, 51, 23),
nitrogen = c("Y", "N", "N", "Y", "Y", "N", "Y", "N"))
plants height nitrogen
1 55 Y
2 17 N
3 42 N
4 47 Y
5 68 Y
6 39 N
7 51 Y
8 23 N
Subsetting Data Frames
Because data frames are two-dimensional, we can subset the data in a data frame by selecting specific columns, specific rows, or both!
R always takes information for the row first, then the column.
Think of it as: data[row, column]
Just like with vectors, we can subset data frames by index or by condition using square brackets.
The pattern is dataframe[rows, columns].
Subsetting by Index
# Sub-setting data frames
# 2-dimensional, so you need to specify row and then column
# plants[3] # doesn't work
# row then column
plants[4,1][1] 47
plants[,2][1] "Y" "N" "N" "Y" "Y" "N" "Y" "N"
Another way to pull out a single column from a data frame is with the $ operator. This can really come in handy when you know the name of the column but not the position.
plants$height[1] 55 17 42 47 68 39 51 23
# The $ operator allows you to refer to a column by name instead of position.Regardless of how you specify the column, you can put that code inside of a function, such as the mean().
mean(plants$height)[1] 42.75
Subsetting by Condition
This is a simple data set, but we can use it to ask a question.
Example: Are the heights of plants treated with nitrogen different from those not treated?
First, we will need to keep only the plants that were treated with nitrogen.
# filter rows based on values in the nitrogen column
plants[plants$nitrogen == "Y", ] height nitrogen
1 55 Y
4 47 Y
5 68 Y
7 51 Y
# notice how the comma is still required. leaving it blank after the comma means "keep all columns."
# calculate the mean
mean(plants[plants$nitrogen == "Y", 1])[1] 55.25
We can create a new data frame by saving the subset data frame to a new object.
plants_no_nitrogen <- plants[plants$nitrogen == "N", ]Small Group Challenge (5 min)
As a group, find the standard deviation (sd()) of the height of plants treated with nitrogen and those not treated with nitrogen. Which group has the larger standard deviation? Any ideas what that means?
# Write your code hereAnswer:
sd(plants[plants$nitrogen == "Y", 1])[1] 9.105859
sd(plants[plants$nitrogen == "N", 1])[1] 12.14839
Instructor Note: The no-nitrogen group has the larger standard deviation. Discuss: a larger SD means more variability in plant heights among untreated plants. Ask students why that might be? Without nitrogen, other factors like light or water availability may drive more variation in growth outcomes. This is a preview of the statistical thinking they will develop in later modules!
Helpful Functions
Below are some particularly useful functions when working with vectors and data frames:
str(): shows the structure of the object (e.g., rows and columns)head()andtail(): shows the first six and last six rows, respectivelylength(): counts the number of elements in an objectncol()andnrow(): counts the number of columns or rows, respectivelynames(): shows the names of the columns in a data frameunique(): shows one of each element in an object (removes duplicate values)
str(plants) # structure of the object'data.frame': 8 obs. of 2 variables:
$ height : num 55 17 42 47 68 39 51 23
$ nitrogen: chr "Y" "N" "N" "Y" ...
head(plants) # first 6 values or rows height nitrogen
1 55 Y
2 17 N
3 42 N
4 47 Y
5 68 Y
6 39 N
head(plants, n = 4) # first n values or rows height nitrogen
1 55 Y
2 17 N
3 42 N
4 47 Y
tail(plants, n = 4) # last n values or rows height nitrogen
5 68 Y
6 39 N
7 51 Y
8 23 N
length(plants) # for a dataframe, number of columns[1] 2
length(plants$height) # for a column, number of rows[1] 8
ncol(plants) # number of columns[1] 2
nrow(plants) # number of rows[1] 8
names(plants) # list of column or object names[1] "height" "nitrogen"
unique(plants$nitrogen) # one of each value present in the column, duplicates removed[1] "Y" "N"