- Carpentries: Data Structures Part 2
- Carpentries: dplyr
- gapminder_data.csvDownload to your rawdata/ folder if not already there
Open your R project. Create a new script called day5.R.
gap <- read.csv("rawdata/gapminder.csv")
dim(gap) # dimensions: rows × columns
nrow(gap) # number of rows
R stores data in different types. Look at the Environment panel to see what type each column is.
int— integer (whole number)num— numeric (floating point / decimal)chr— character (text)logi— logical (TRUE/FALSE)
# Add a logical column
gap$big_countries <- gap$pop >= 100000000
- Data frame — tabular data; columns must be the same length
- Vector — one-dimensional, all elements the same type
- List — like a data frame but elements can have different lengths and types
- Factor — categorical data with defined levels
Vectorization Is Faster Than Loops
# Vectorized — fast
system.time(gap$pop - 1000)
# Loop — slow
system.time(
for(i in 1:nrow(gap)) {
print(gap[i,]$pop - 1000)
}
)
Working with Vectors and Data Frames
# Create a data frame
cats <- data.frame(coat = c("calico", "black", "tabby"),
weight = c(2.1, 5.0, 3.2),
likes_catnip = c(1, 0, 1))
write.csv(x = cats, file = "rawdata/feline-data.csv", row.names = FALSE)
# Vectorization on character vectors
paste("My cat is", cats$coat)
Type Coercion — Watch Out
R will silently convert types when you mix them. The hierarchy: logical → integer → double → complex → character
coercion_vector <- c(0, TRUE) # what do you predict?
coercion_vector
# Explicit type conversion
coercion_vector <- c('0', '2', '4')
str(coercion_vector)
coercion_vector <- as.numeric(coercion_vector)
str(coercion_vector)
Lists
list_example <- list(nums = c(1,2,3,4,5), chars = "a", logis = c(TRUE,TRUE,FALSE))
list_example[[1]] # access by position
list_example$nums[1] # access by name + index
# Index by position [row, column]
gap[1,1]
gap[1:5, 1:2]
gap[1:5, ] # all columns
gap[1:5, c("country", "continent")] # select by name
# Logical subsetting
gap[gap$year == 1957, ]
gap[gap$year %in% c(1957, 1958, 1959), ]
gap[gap$year == 1957, c("country", "continent", "pop")]
Make a new data frame containing life expectancies for all countries, but only for "big" countries between 1970 and 1990. Hint: use & to combine conditions.
Answer: LifeExpBigs <- gap[gap$year >= 1970 & gap$year <= 1990 & gap$big_countries == TRUE, c("country", "lifeExp")]
install.packages("tidyverse") # run once
library(tidyverse) # run each session (put at top of script)
The key dplyr verbs:
select()— choose columnsfilter()— choose rowsmutate()— add or edit columnsgroup_by()— group datasummarize()— compute summaries
Pipelines with %>%
# Select columns
gap_smaller <- gap %>%
select(country, continent, pop)
# Filter rows
tidyGap <- gap %>%
select(year, country, pop, gdpPercap) %>%
filter(between(year, 1970, 1990)) %>%
rename(population = pop)
# Summarize by group
gdp_bycontinents <- gap %>%
group_by(continent) %>%
summarize(mean_gdpPercap = mean(gdpPercap))
# Multi-variable summary
gdp_pop_bycontinents_byyear <- gap %>%
group_by(continent, year) %>%
summarize(mean_gdpPercap = mean(gdpPercap),
sd_gdpPercap = sd(gdpPercap),
mean_pop = mean(pop),
sd_pop = sd(pop),
countriesInContinent = n())
# Mutate — add a new column
gap %>%
mutate(gdp_billion = pop * gdpPercap / 10^9)
Calculate the mean life expectancy per country. Which country has the longest average life expectancy? The shortest?
dplyr is where AI really shines — describe what you want in plain English and let AI write the pipeline. Then run it and make sure the output makes sense.
After running it, follow up: "Can you modify this to also calculate the standard deviation of life expectancy for each group?"