Homework 2
Descriptive Statistics and Reading and Transforming Data with R
Homework 2 Question Scores
The table summarizes earned points divided by the maximum points for each question, on a 0–1 scale. A score of 1 means full credit; 0.75 and 0.50 indicate partial credit. The mean score shows the average fraction of credit earned, not the percentage of students who answered perfectly.
Instructions
This homework covers Lectures 4 and 5. Answer all 35 questions: Questions 1–17 are conceptual questions (14 multiple-choice questions and three fill-in-the-blank questions), and Questions 18–35 ask you to fill in one R-code blank.
- For each multiple-choice question, select the one best answer.
- For each conceptual fill-in-the-blank question, enter only the requested term.
- For each coding question, enter only the R code that replaces
[?], not the full line or code block. Each question has one blank. - Run the data-loading code below once, then write and test your answers in an R script before submitting them.
- Submit your answers through Brightspace. Check Brightspace for the due date.
For Questions 21–35, use this data frame. Questions 18–20 use the local-file scenario stated in Part III.
library(tidyverse)
# URL for the CSV file
CSV_url <- 'https://bcdanl.github.io/data/custdata_rev.csv'
custdata <- read_csv(CSV_url)Variable descriptions
Each row represents one customer.
| Variable | Description |
|---|---|
custid |
Unique customer identifier, stored as text. |
sex |
Reported sex: Female or Male. |
is_employed |
Employment status: TRUE = employed; FALSE = unemployed; NA = unknown or not applicable. |
income |
Customer income in U.S. dollars. |
marital_status |
Marital status, such as married, never married, divorced/separated, or widowed. |
housing_type |
Housing situation, such as renting or owning a home. |
recent_move |
Whether the customer moved in the past year: TRUE = yes; FALSE = no. |
num_vehicles |
Number of vehicles in the household; 6 means six or more. |
age |
Customer age in years. |
state_of_res |
State of residence, including the District of Columbia. |
gas_usage |
Monthly gas-bill field; values 4–999 represent dollar amounts, with special codes below. |
health_ins |
Health-insurance status: TRUE = insured; FALSE = uninsured. |
For gas_usage, 1 means included in rent or condo fees, 2 means included in the electricity payment, and 3 means no charge or gas not used. The gas questions use the recorded values. In any column, NA represents a missing or not-applicable value.
Reference: Customer data dictionary.
Part I: Multiple Choice
Question 1
Group A has ages 29, 30, and 31. Group B has ages 20, 30, and 40. Both groups have a mean age of 30. Which statement is correct?
- Group A has greater variability because its ages are closer together.
- Group B has greater variability because its ages are farther from the mean.
- The groups have equal variability because their means are equal.
- Variability cannot be compared unless the groups have different medians.
b. Group B has greater variability because its ages are farther from the mean. Both means are 30, but Group B’s deviations from 30 are larger.
Question 2
The mean income in a customer dataset is higher this year than last year. What does this descriptive comparison establish by itself?
- A new marketing program caused the increase.
- Every customer’s income increased.
- The observed mean is higher, but the reason for the change is not established.
- The median income must also have increased.
c. The observed mean is higher, but the reason for the change is not established. A descriptive comparison does not by itself identify a cause or establish what happened to every customer.
Question 3
A customer’s gas_usage value appears beyond the upper fence of a boxplot. What is the most appropriate first interpretation?
- The value is certainly a data-entry error and must be deleted.
- The value is a possible outlier that should be checked in context.
- The value must be replaced by the mean gas usage.
- The value proves that all other gas-usage records are correct.
b. The value is a possible outlier that should be checked in context. A point beyond a boxplot fence may be unusual without being erroneous.
Question 4
For x <- c(4, 10, 18), what does R return from range(x)?
c(4, 18), the minimum and maximum14, the width from minimum to maximum32, the sum of the valuesc(10, 14), the median and range width
a. c(4, 18), the minimum and maximum. R’s range(x) returns both endpoints; the range width is 18-4=14.
Question 5
Suppose the third quartile (Q_3) of customer age is 62 years. Which interpretation is best?
- About 25% of ages are at or below 62.
- About 50% of ages are at or below 62.
- About 75% of ages are at or below 62.
- Every customer is older than 62.
c. About 75% of ages are at or below 62. Q_3 is the 75th-percentile cut point. Ties may make the exact fraction differ from 75%.
Question 6
Ten customers each spend 20 dollars, and 90 customers each spend 50 dollars. Which expression gives the mean spending per customer across all 100 customers?
- (20+50)/2
- (10\times20+90\times50)/(10+90)
- (10+90)/(20+50)
- 20\times50
b. (10\times20+90\times50)/(10+90). The groups must be weighted by their customer counts. The result is 47 dollars per customer.
Question 7
Which description of a CSV file is correct?
- It is an R-only file that cannot be opened outside R.
- It is a plain-text table whose values are separated by commas; its first line often contains column names.
- It stores only one numeric vector and no column names.
- It automatically records the meaning of every variable and every missing value.
b. It is a plain-text table whose values are separated by commas; its first line often contains column names. A CSV does not automatically document variable meanings.
Question 8
If custdata is organized as tidy data with one row per customer, which description is correct?
- Each column is a customer, and each row is a variable.
- Each row is a customer, each column is a variable, and each cell holds one value.
- Each cell is a customer, and each row holds a complete variable.
- Each row must contain only numeric values.
b. Each row is a customer, each column is a variable, and each cell holds one value. This is the tidy-data layout for the stated observational unit.
Question 9
What does the native pipe |> do in custdata |> filter(age >= 65)?
- It assigns
filterto the namecustdata. - It passes
custdataas the first input tofilter(), equivalent tofilter(custdata, age >= 65). - It joins
custdatato a second data frame. - It changes every age to 65.
b. It passes custdata as the first input to filter(). The piped expression is equivalent to filter(custdata, age >= 65).
Question 10
You want to keep only rows for customers aged 65 or older, then keep only the custid and age columns. Which functions perform these two tasks, in order?
select(), thenfilter()filter(), thenselect()arrange(), thendistinct()rename(), thenarrange()
b. filter(), then select(). filter() keeps rows meeting the age condition; select() keeps the requested columns.
Question 11
A filter should keep customers who live in New York or New Jersey. Which operator combines the two state comparisons correctly?
&, because each row must match both states|, because each row may match either state!, because each row must match neither state==, because it combines two complete logical conditions
b. |, because each row may match either state. An & condition would require the same state value to equal both names simultaneously.
Question 12
Some values of is_employed are missing. Why should you use is.na(is_employed) rather than is_employed == NA to find them?
NAis the same asFALSE.- Comparing a value with
NAusing==returnsNA, not a usefulTRUE/FALSEmissingness test. is.na()replaces missing values with zero.== NAworks only when the column is numeric.
b. Comparing a value with NA using == returns NA, not a useful TRUE/FALSE missingness test. is.na(is_employed) identifies which values are missing.
Question 13
How does arrange(custdata, state_of_res, desc(age)) order the rows?
- By age from oldest to youngest, then by state only when ages tie
- By state alphabetically; within each state, by age from oldest to youngest
- By state alphabetically; within each state, by age from youngest to oldest
- It removes rows with repeated states.
b. By state alphabetically; within each state, by age from oldest to youngest. arrange() uses the first variable as the primary sort key, and desc(age) breaks state ties in descending age order.
Question 14
What does distinct(custdata, state_of_res) return?
- One row for each unique state value, with a
state_of_rescolumn - The number of customers in each state
- All original customer rows, sorted by state
- Only customers with missing state values
a. One row for each unique state value, with a state_of_res column. distinct(custdata, state_of_res) returns the unique values of that selected column, not customer counts.
Part II: Conceptual Fill in the Blanks
For Questions 15–17, consider a new Posit Cloud project whose working directory has not been changed from the default, /cloud/project. A copy of custdata_rev.csv has been uploaded to a folder named data_files directly inside the project folder.
Question 15
R uses /cloud/project as the starting folder for interpreting relative pathnames. This starting folder is called R’s [Blank].
Enter only the two-word term that replaces the blank.
Working directory
In the stated Posit Cloud scenario, /cloud/project is the starting folder for relative pathnames.
Question 16
The pathname /cloud/project/data_files/custdata_rev.csv gives the file’s full location, beginning at the root folder /. It is an [Blank] pathname.
Enter only the term that replaces the blank.
Absolute
/cloud/project/data_files/custdata_rev.csv begins at the root folder / and gives the file’s full location.
Question 17
With R’s working directory set to /cloud/project, the pathname data_files/custdata_rev.csv locates the file starting from that working directory. It is a [Blank] pathname.
Enter only the term that replaces the blank.
Relative
data_files/custdata_rev.csv is interpreted from the working directory /cloud/project.
Part III: R Programming — Fill in the Code Blank
For Questions 18–20, use the same local-file scenario: R’s working directory is /cloud/project, and a copy of custdata_rev.csv is in the project’s data_files folder. Complete the code using these stated locations; you do not need to upload a file to answer these questions. Reading the CSV from the web in the Instructions does not save a local copy. For Questions 21–35, use the custdata data frame loaded from the web in the Instructions.
Question 18
Use an R function to obtain the current working directory. Enter only the function call that replaces [?].
current_folder <- [?]getwd()
In the stated scenario, the returned pathname is /cloud/project.
Question 19
Read the local CSV using its absolute pathname. Enter only the pathname that replaces [?], including quotation marks.
custdata_absolute <- read_csv([?])"/cloud/project/data_files/custdata_rev.csv"
custdata_absolute <- read_csv("/cloud/project/data_files/custdata_rev.csv")The absolute pathname begins at /. Single quotation marks are also valid.
Question 20
Read the same local CSV using its relative pathname from /cloud/project. Enter only the pathname that replaces [?], including quotation marks.
custdata_relative <- read_csv([?])"data_files/custdata_rev.csv"
custdata_relative <- read_csv("data_files/custdata_rev.csv")R starts at /cloud/project and looks in its data_files subfolder. Single quotation marks are also valid.
Question 21
Count the number of rows in custdata. Enter only the code that replaces [?].
row_count <- [?]nrow(custdata)
The data frame has 73,262 rows.
Question 22
Extract the num_vehicles column as a vector. Enter only the code that replaces [?].
vehicle_counts <- [?]custdata$num_vehicles
The $ operator extracts the column as a vector.
Question 23
For this question, use the custdata_filtered data frame created below.
First, keep only rows where gas_usage is greater than or equal to 4, since values of 1, 2, and 3 represent categories rather than dollar amounts.
custdata_filtered <- custdata |>
filter(gas_usage >= 4)Using the resulting custdata_filtered data frame, calculate the mean of gas_usage, excluding missing values. Enter only the code that replaces [?].
mean_gas_usage <- [?]mean(custdata_filtered$gas_usage, na.rm = TRUE)
The mean is approximately 76.01. Use custdata_filtered, which keeps only recorded gas-usage values greater than or equal to 4. The na.rm = TRUE argument excludes any missing values from the calculation.
Question 24
Calculate the third quartile (Q_3) of age using quantile(). Enter only the code that replaces [?].
third_quartile_age <- [?]quantile(custdata$age, probs = 0.75)
The third quartile is 62 years. quantile(custdata$age, 0.75) is equivalent.
Question 25
Calculate the interquartile range of income. Enter only the code that replaces [?].
income_iqr <- [?]IQR(custdata$income)
The income IQR is 41,000.
Question 26
Calculate the sample standard deviation of income. Enter only the code that replaces [?].
income_sd <- [?]sd(custdata$income)
The sample standard deviation is approximately 58,113.76, in the same units as income.
Question 27
Keep rows for female customers aged 65 or older. Enter only the condition or conditions that replace [?].
older_women <- custdata |>
filter([?])sex == "Female" & age >= 65
The completed filter retains 8,684 rows. Within filter(), sex == "Female", age >= 65 is an equivalent answer.
Question 28
Keep rows for customers living in either New York or New Jersey. Enter only the condition that replaces [?].
ny_nj_customers <- custdata |>
filter([?])state_of_res == "New York" | state_of_res == "New Jersey"
The completed filter retains 6,490 rows.
Question 29
Keep rows where is_employed is missing. Enter only the condition that replaces [?].
employment_missing <- custdata |>
filter([?])is.na(is_employed)
The completed filter retains 25,774 rows.
Question 30
Keep rows where gas_usage is not missing. Enter only the condition that replaces [?].
gas_usage_known <- custdata |>
filter([?])!is.na(gas_usage)
The completed filter retains 71,542 rows.
Question 31
Sort all customer rows by income from highest to lowest. Enter only the code that replaces [?].
highest_income_first <- custdata |>
arrange([?])desc(income)
The completed arrange() call puts the largest incomes first.
Question 32
Sort by state_of_res alphabetically and, within each state, by age from oldest to youngest. Enter only the second sorting expression that replaces [?].
state_then_oldest <- custdata |>
arrange(state_of_res, [?])desc(age)
The first sorting key, state_of_res, stays alphabetical; desc(age) orders ages within each state from oldest to youngest.
Question 33
Create a one-column data frame containing each distinct state of residence once. Enter only the column name that replaces [?].
states <- custdata |>
distinct([?])state_of_res
The result is a one-column data frame with 51 distinct state-of-residence values.
Question 34
Keep only the custid, age, and income columns, in that order. Enter only the column-name arguments that replace [?].
id_age_income <- custdata |>
select([?])custid, age, income
select() keeps those three columns in the order listed.
Question 35
The pipeline below keeps female customers aged 65 or older, puts the highest incomes first, and keeps three columns. In the final step, rename income to annual_income. Enter only the function call that replaces [?].
older_women_income <- custdata |>
filter(sex == "Female", age >= 65) |>
arrange(desc(income)) |>
select(custid, age, income) |>
[?]rename(annual_income = income)
The full pipeline returns 8,684 rows and the columns custid, age, and annual_income. rename() uses new_name = old_name.
