Chapter 4: Structures

Transparency, Indexing, and Logical Vectors

Overview

Chapter 3 introduced R Notebook memos as a way to keep your code, output, checks, and learning visible. In this chapter, you will apply transparency while deciding which vector values to select and filter.

Your memos will record what you intended to select, which indexing method you used, how you checked the result, and what the output showed. This creates a record that you and another reader can follow later.

This chapter also finishes the vector-selection skills you need before working with larger datasets. You will learn how vector elements can be labeled with names, how indexing lets you select specific values, and how logical values can be used to filter a vector.

The point of this chapter is control: selecting the values you mean to select, checking whether your selection worked, and documenting your process clearly enough that someone else could follow it.

By the end of Chapter 4, you should be able to practice transparency in your notebook memos, select vector elements by position and name, build logical vectors using comparison operators, and use logical indexing to filter values from a vector.

In Chapter Four, you will practice how to:

  • ✍️ Apply transparency by documenting what you intended to select, how you checked the result, and what the output showed.

  • 🧾 Create named vectors using element names.

  • 📍 Use indexing to select vector elements by position.

  • 🏷️ Use indexing to select vector elements by name.

  • ⚠️ Recognize that character indexing requires exact matching and returns NA when a name is not found.

  • 🛠 Build logical vectors using TRUE, FALSE, and NA.

  • 🔎 Use comparison operators such as >, <, ==, >=, <=, and != to create logical results.

  • 🧮 Use logical indexing to filter values from a vector.

  • ✅ Verify that your selected or filtered vector contains the expected values.


R Notebooks—Part 2

In Chapter 3, you learned how to use an R Notebook (.Rmd) as a “reproducible thinking” document: code + output + memo-style writing in one place, in order. This section is a quick setup review before you begin the Chapter 4 work.

Here’s what you can do now:

  1. Create and save an R Notebook (File > New File > R Notebook) and store it in your course folder.

  2. Recognize the YAML header at the top of the file and edit the title.

  3. Insert code chunks using the Insert button, a shortcut, or typed fences, and use chunks to organize the R code in your notebook.

  4. Run chunks using the play button, Run menu, or keyboard shortcuts and view output below the chunk or in another relevant pane, depending on your RStudio settings.

  5. Memo correctly:

    • Inside a code chunk: explanatory text must start with #; otherwise, R tries to run it as code.

    • Outside a code chunk: write normal paragraphs with no # needed.

    • Use the notebook to document your learning process, including your goal, checks, explanations, and resources used.

An R Notebook is only useful if a person can read and understand it. In this chapter, you will keep building clean notebook habits: preserving the YAML header, organizing your work clearly, writing readable memos, and preparing a notebook that can knit successfully to HTML.

Default Text

🎯 Please open a new R Notebook in your course folder named chapter4_notes.Rmd.

When you create a new R Notebook or R Markdown file, RStudio provides a template. It is designed to demonstrate the three core components of a notebook:

  • The YAML header: The block of text at the very top, enclosed between two lines of three dashes (---). This tells RStudio how to knit, or render, your document.

  • Markdown text: Text outside code chunks, such as “This is an R Markdown Notebook.” This shows you how to write regular prose.

  • Code Chunks: Fenced blocks containing code, such as plot(cars). This shows you how to embed executable R code.

Clear the Default Notebook Body

To start fresh, delete all the default text in the R Notebook so you have a blank canvas to work with.

Keep the Header

Do not delete the text at the very top between the --- lines. This is the notebook’s metadata, including its title and output format. If this header is deleted or malformed, the notebook may not render as intended.

Your header should look something like this:

---
title: "Chapter 4"
output: html_notebook
---

Keep this top section. Delete the example text and code below it.

Delete the Body

You can safely delete everything below the second --- line. Keep the YAML header at the top.

  1. Place your cursor on the line immediately following the second ---.

  2. Highlight everything all the way to the bottom of the document.

  3. Press Delete or Backspace.

Save the Blank Notebook

After clearing the default text, save your blank notebook as chapter4_notes.Rmd in your course folder. This will be your working file for Chapter 4.

Type a memo

🗣 Add Comments: In 1–3 sentences, explain what you did to clear the default text and why you kept the YAML header.

I cleared the default text because the default text is just an example and I want to start with a blank notebook to practice writing my own memos and code. I kept the YAML header because it contains important information about the document, such as the title and output format, that control how the notebook is knitted.

🧐 Notice: Regular paragraph text outside a code chunk does not need #. Explanatory comments inside a code chunk do need # so R does not interpret them as code.


Applying Transparency

The Transparency module introduction explains why methods, decisions, checks, and resource use should remain visible. Chapter 3 introduced the R Notebook practices that support this record.

✍️ In this chapter, apply those practices to indexing and filtering. Add a short memo when you need to explain:

  • what value or group you intended to select,
  • whether you selected by position, name, or logical condition,
  • how you checked that the intended values were returned,
  • what an unexpected NA or omitted value showed,
  • and what resource helped if you used outside assistance.

You do not need every memo prompt for every line of code. Document choices and results that would be difficult to reconstruct later.

Indexing Vectors

The indexing operator [ is the standard way to extract parts of a vector. The basic pattern is x[i], where x is the vector and i is the index, or indices, of the elements you want to extract. For the atomic vectors in this chapter, [ ] can select one element or many, and it returns an object of the same type as x.

An index is a value used to identify elements in an object. In R, indices are often integers for positions, character values for names, or logical values such as TRUE and FALSE.

Positional Indexing

Positional indexing uses the numeric positions of elements in the vector to retrieve specific values.

🎯 Goal Use [ ] with index positions to extract values from a vector.

# ⚡ Type this in your R Notebook
z <- c(10, 20, 30, 40, 50) # create a vector
# ⚡ Type this in your R Notebook
z[1]       
[1] 10

🗣 This returns the first element by position.

# ⚡ Type this in your R Notebook
z[3]      
[1] 30

🗣 This returns the third element by position.

# ⚡ Type this in your R Notebook
z[2:4]     
[1] 20 30 40

🗣 This returns the second, third, and fourth elements by position.

🧐 Notice: z[2:4] selects positions 2 through 4. It does not search for the values 2, 3, and 4.

# ⚡ Type this in your R Notebook
z[-c(1, 5)] 
[1] 20 30 40

🗣 Negative indexing excludes specified positions from the returned result. z[-c(1, 5)] returns all elements except the first and last. The stored z object remains unchanged because the result was not assigned to an object.

🧐 Notice: R counts positions starting at 1, not 0. Negative positions exclude those positions from the returned result. They do not delete values from the original vector.

Character Indexing

When a vector has names, you can use those names to index into the vector. Character indexing uses the names of the elements to retrieve specific values.

There are two different naming ideas here.

  1. Object name is the variable name nerdy_palette that you use to refer to the entire vector.

  2. Element names are the labels assigned to each element within the vector (e.g., "Octarine", "TARDIS Blue").

Element names can be used in indexing to access specific elements of the vector. A named vector works like a small lookup table: each value has a label, and you can use the label to retrieve the matching value.

🎯 Goal: Create a named vector of color codes, then use character indexing to return the hexadecimal color code for "Octarine".

# Create nerdy_palette
nerdy_palette <- c(
  "Octarine" = "#7F00FF",
  "TARDIS Blue" = "#003B6F",
  "Rebeccapurple" = "#663399",
  "Hooloovoo" = "#4F97A3",
  "Cosmic Latte" = "#FFF8E7",
  "Vantablack" = "#000000",
  "Matrix Green" = "#03A062",
  "Source Engine Magenta" = "#FF00FF",
  "Command Red" = "#CC0000",
  "Impossible Green" = "#4D9E68"
)

# Use character indexing to return the hex code for Octarine
nerdy_palette["Octarine"]
 Octarine 
"#7F00FF" 

🗣 When you run this chunk, it should return the hexadecimal color code for "Octarine" from the nerdy_palette vector.

Character indexing requires exact matching on names. If you ask for a name that doesn’t exist, you get NA for that element.

🎯 Use character indexing to retrieve the color codes for “Octarine,” “TARDIS Blue,” and “NotAColor” from the nerdy_palette vector.

# ⚡ Type this in your R Notebook
nerdy_palette[c("Octarine", "TARDIS Blue", "NotAColor")]
   Octarine TARDIS Blue        <NA> 
  "#7F00FF"   "#003B6F"          NA 

🗣 The output should return the color codes for "Octarine" and "TARDIS Blue", plus NA for "NotAColor" because that name does not exist in the vector.

More Indexing by Position

🎯 Use positional indexing to return the first and third color codes from the nerdy_palette vector.

# ⚡ Type this in your R Notebook
nerdy_palette[c(1, 3)]
     Octarine Rebeccapurple 
    "#7F00FF"     "#663399" 

🗣 The output shows the hexadecimal color codes for Octarine and Rebeccapurple in the nerdy_palette vector.

We will return to indexing in later chapters when we learn about data frames.

Logical Vectors

📖 Review from Chapter 2.

Logical vectors are used for conditions and comparisons.

🎯 Create a logical vector named real that contains the values TRUE, FALSE, and NA using the c() function.

# ⚡ Type this in your R Notebook
real <- c(FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, NA)
# ✅ Check the real vector
print(real)
 [1] FALSE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE    NA

🗣 The output prints the logical values stored in the real vector.


Comparison Operators

Logical vectors can also be created using comparison operators. These operators compare values and usually return TRUE or FALSE. A comparison involving a missing value will usually return NA because R cannot determine whether the comparison is true or false.

Comparison operators include:

  • > greater than

  • < less than

  • == equal to

  • >= greater than or equal to

  • <= less than or equal to

  • != not equal to

🎯 Create a logical vector named logicals that contains the results of the following comparisons: 1 > 2, 3 < 5, and 4 == 4 using the c() function.

# ⚡ Type this in your R Notebook
logicals <- c(1 > 2, 3 < 5, 4 == 4) 
# ✅ Check the logicals vector
print(logicals)
[1] FALSE  TRUE  TRUE

🗣 The output shows the results of the comparisons stored in the logicals vector. There is one FALSE value and two TRUE values. The first value is FALSE because 1 is not greater than 2. The second value is TRUE because 3 is less than 5. The final value is TRUE because 4 is equal to 4.

Logical Indexing

Logical indexing uses a logical vector inside [ ]. Values paired with TRUE are kept, and values paired with FALSE are left out. An NA in the logical vector produces an NA in the result because R cannot determine whether the matching value should be kept.

🎯 Create a new vector called smaller that contains only the values in number_list that are less than or equal to 20.

# ⚡ Type this in your R Notebook
number_list <- c(10, 25, 5, 30, 15, 40)

🗣 The number_list vector contains the values 10, 25, 5, 30, 15, and 40.

# ⚡ Step 1: create the logical "mask"
mask <- number_list <= 20

# ✅ Check the mask
print(mask)
[1]  TRUE FALSE  TRUE FALSE  TRUE FALSE

🗣 This prints a logical vector (TRUE/FALSE) the same length as number_list. Each TRUE marks a value that is less than or equal to 20.

⚠️ For predictable logical indexing, use a logical vector with the same length as the vector being filtered. If the logical vector is shorter, R may recycle it. If it is longer, the result can extend beyond the available values and include NA. A length mismatch is a reason to stop and check the mask.

# ⚡ Step 2: use the logical vector inside [ ]
smaller <- number_list[mask]
print(smaller)
[1] 10  5 15

🗣 This keeps only the values where mask is TRUE, so smaller contains 10, 5, and 15.

The key idea is that the condition number_list <= 20 creates a logical vector, and [ ] uses that logical vector as a filter.


Summary

In this chapter, you strengthened your R Notebook habits by practicing transparency in your code memos. You learned to document your goals, explain what your code produced, verify your results, and record outside resources when you used help. These habits make your work easier to understand, check, revise, and share.

You also learned how to select values from vectors. You practiced positional indexing to select elements by number, negative indexing to exclude positions from a returned result, and character indexing to select elements from named vectors. You saw that character indexing requires exact matching and returns NA when a requested name does not exist.

Finally, you learned how logical vectors support filtering. You created logical values with comparison operators, stored those results in a logical vector, and used logical indexing to keep only the values that met a condition.

Your main takeaway is that transparent notebooks make your coding choices inspectable, and indexing gives you control over which vector values you select or filter.

Chapter Terms

Character Indexing: Indexing a named vector using element names (character strings) instead of numbers. Names must match exactly; a missing name returns NA.

Code Chunks: Fenced blocks in an R Markdown or Quarto document that contain executable code, usually beginning with ```{r} and ending with three backticks. Code in a chunk can run interactively or during rendering. Depending on RStudio settings, output may appear below the chunk or in another relevant pane.

Comparison Operators: Operators that compare values. Common comparison operators are ==, !=, <, >, <=, and >=. They usually return TRUE or FALSE; a comparison involving a missing value will usually return NA.

Element Names: The individual labels assigned to elements inside a named vector (for example, "Octarine" or "TARDIS Blue"). Element names let you index by label (e.g., nerdy_palette["Octarine"]) to retrieve specific values.

Index: A value used inside a subsetting operator to identify which part of an object to extract or replace. In R, an index can use positions, names, or logical values; for example, x[2] uses a positional index to select the second element, while df[rows, columns] uses row and column indices to select parts of a data frame. R documentation also calls these values indices or subscripts.

Indexing Operator: The single square-bracket operator [ used to extract or replace selected parts of an object. For a vector, x[i] returns the elements identified by the positions, names, or logical values supplied in i.

Logical Indexing: Using a logical vector inside [ to select values. TRUE keeps the matching value, FALSE excludes it, and NA produces an unknown element represented by NA. A shorter logical index may be recycled, so checking that the index and source vector have the same length helps prevent unintended results.

Logical Mask: A logical vector used inside the single square-bracket operator [ to filter another object. TRUE keeps the matching value, FALSE excludes it, and NA produces an unknown element represented by NA. For predictable results, the mask should have the same length as the object being filtered.

Logical Vector: A vector that stores TRUE, FALSE, and sometimes NA for missing values. Logical vectors are commonly produced by comparisons, such as x > 0, and are used for filtering and conditional code.

Markdown: A lightweight plain-text formatting syntax used to write structured documents (headings, lists, links, emphasis, code) in a way that stays readable as plain text and can be rendered into formats like HTML on many platforms and tools.

NA: A special constant that marks a missing value (“Not Available”)—meaning the data point is unknown or not recorded. R also provides typed missing values like NA_integer_, NA_real_, NA_character_, and NA_complex_ to match the underlying data type.

Named Vectors: Vectors that have labels attached to their elements via the names() attribute, so you can refer to values by name instead of only by position. Named vectors are useful as simple lookup tables (for example, retrieving a hex code by a color name).

Negative Indexing: Using negative integers inside [ to exclude positions from the returned result. For example, x[-2] returns every element except the second. The original object remains unchanged unless the result is assigned to an object. Positive and negative indices cannot be mixed in the same subset, except for 0.

Object Name: The variable name you assign with <- that refers to the entire object in your environment. You use the object name to print, modify, or pass the whole object to functions.

Positional Indexing: Indexing a vector using numeric positions (for example, x[1] for the first element or x[c(1, 3)] for the first and third). Positions are based on the current order of the vector.

R Notebook: An .Rmd document that combines written explanation with executable R code chunks. Depending on your RStudio settings, interactive output may appear below a chunk or in another relevant pane. Rendering creates a finished document that keeps the writing, code, and computed output together.

YAML Header: The metadata section at the top of an R Markdown or Quarto document, written between --- lines, that controls document settings like the title, author, date, output format (HTML/PDF/Word), and options for rendering.

📝 Practice Space

Complete the following coding and reflection tasks in your R Notebook.

Before you begin:

  1. Create a new R Notebook in RStudio.
  2. Save it in your course folder as chapter4_practice.Rmd.
  3. Complete all Practice Space tasks in that notebook.

As you work, add short comments or memo notes explaining what your code is doing and what the output shows.

  • 🗣 Add Comments asks you to explain what the code or output shows.
  • 🪞 Reflect asks you to explain your thinking process, what confused you, what changed in your understanding, or what strategy you would use next.

These are there to help you practice the habit of writing memos as you work. Keep responses short: 1–3 thoughtful sentences is enough. For this Practice Space, answer the 🗣 Add Comments prompt for each coding task. Then answer 🪞 Reflect prompts where your thinking, prediction, confusion, or troubleshooting changed.

If you encounter an error, practice tenacity by choosing an informed next step. Practice ✍️ transparency by recording what happened, what you tried, what you checked, and what remains unclear. If a resource helped you troubleshoot, identify it and explain what it contributed.

If you use generative AI, follow the policies or guidance that apply to your work. Document the tool, what you asked, what the response contributed, and how you checked it. If you quote AI output, mark it clearly as quoted material and explain in your own words why you included it.

Before you finish, clear your Environment and run the notebook from top to bottom. Then knit to HTML to check that the notebook works in order.

Task 1

🧑‍🎓 Create a named vector

Practice creating a named vector by pairing values with element names. Some labels and some values are missing. The blanks test both parts of the name-value pair.

💡 Tip: Remember to include quotes around the element names.

🎯 Create a named vector called student_counts that stores the number of students in four campus groups. Use the exact group names and counts: "First Year" count is 18, "Sophomore" count is 22, "Junior" count is 16, and "Senior" count is 14.

# ⚡ Type this in your R Notebook. Fill in the blanks.
student_counts <- c(
  ______ = 18,
  "Sophomore" = ___,
  ______ = 16,
  "Senior" = ___
)

# ✅ Check the vector
print(student_counts)

🗣 Add Comments: In 1–3 sentences, explain what print(student_counts) shows. Include how the group names help you understand what each number means.

🪞 Reflect: Which part of this task was easier to keep track of: the values or the names? Explain how you checked that each group name matched the correct count.

Task 2

➖ Use negative indexing

Practice using negative positions inside [ ] to return all elements except selected positions.

🎯 Use negative indexing by placing a negative sign before c() to return all quiz scores except the values in positions 1 and 5.

# ⚡ Type this in your R Notebook.
quiz_scores <- c(85, 92, 78, 88, 61, 95)

# ⚡ Fill in the blank to exclude positions 1 and 5 from the output.
quiz_scores[____(1, 5)]

🗣 Add Comments: In 1–3 sentences, explain which quiz scores were excluded from the output and which scores remained. The original quiz_scores vector still contains all six scores unless a new result is assigned to it.

The output excluded __________.

🪞 Reflect: How did you know that 1 and 5 meant positions, not score values? Explain what you would check if the output removed the wrong scores.

Task 3

🏷️ Use character indexing

Practice selecting a named vector element using an exact character name.

🎯 Use character indexing to retrieve the number of "Junior" students from the student_counts vector you created in Task 1.

# ⚡ Fill in the blank with the exact element name.
____["____"]

🗣 Add Comments: In 1–3 sentences, explain what the code returns. Include both the name and the value shown in the output.

🪞 Reflect: Does the exact spelling of "Junior" matter here? Why? Explain what you would check if R returned NA or did not find the value.

Task 4

⚖️ Create a logical vector

Practice using a comparison operator to create a logical vector.

🎯 Create a logical vector called meets_goal that checks whether each value in the quiz_scores vector from Task 2 is greater than or equal to 80.

# ⚡ Use the quiz_scores vector from Task 2.

# ⚡ Fill in the blank with the correct comparison operator.
meets_goal <- quiz_scores ____ 80

# ✅ Check the logical vector
print(meets_goal)

🗣 Add Comments: In 1–3 sentences, explain what each TRUE and FALSE means in meets_goal. Be specific about the cutoff value of 80.

`TRUE` means __________. `FALSE` means __________.

🪞 Reflect: Before running the code, how many TRUE values did you expect? Explain how you compared your prediction to the printed output.

Task 5

🔎 Use logical indexing

Practice using a logical vector as a mask to filter another vector.

🎯 Use meets_goal from Task 4 to keep only the values in quiz_scores that are greater than or equal to 80.

# ⚡ Use the logical vector from Task 4 to filter quiz_scores.
passing_scores <- ____[____]

# ✅ Check the new vector
print(passing_scores)

🗣 Add Comments: In 1–3 sentences, explain which scores were kept in passing_scores and why those scores matched the meets_goal mask.

`passing_scores` kept __________ because __________.

🪞 Reflect: Explain how the logical vector worked like a filter. What would happen if meets_goal had FALSE in a position where you expected TRUE?

Task 6

🪞 Reflect on logical masks

🎯 In 1–3 sentences, explain how the logical mask controls which values are kept from quiz_scores. Use the words TRUE, FALSE, and position in your answer.

Task 7

✅ Final checks

🎯 Step 1: Save your notebook.

Save the current version of chapter4_practice.Rmd.

🎯 Step 2: Sweep your Environment. Start clean.

Click the 🧹 broom icon in the Environment pane to clear objects.

🎯 Step 3: Run everything from top to bottom.

Use Run → Run All to execute every chunk in order. If an error appears, document what happened, what you tried, and how you resolved it or what remains unclear.

🎯 Step 4: Knit to HTML.

Knit your notebook to HTML to check that the document works from beginning to end.

🎯 Step 5: Review your work.

Review the rendered HTML. If you make corrections to the .Rmd file, repeat the clean run and knit. Follow any submission directions provided by your instructor.