# How to Use Subsets in R

Subsetting data is akin to the act of focusing a microscope, narrowing down on the specific slices of information that hold the most significance to your analysis. In the realm of data analytics, this is not just a luxury but often a necessity. The R programming language, revered for its prowess in statistics and data manipulation, recognizes this need and offers a plethora of tools and functions to make this task seamless.

This article aims to be your compass in the vast ocean of R's subsetting capabilities. Whether you're just starting your journey or have been navigating these waters for a while, there's always a new technique or a more efficient method waiting around the corner. From the fundamental subset() function to the more nuanced methods involving popular packages like dplyr, we'll traverse through the spectrum of subsetting techniques, ensuring you're equipped to handle any data challenge thrown your way.

## What are Subsets?

In the context of data analysis, a subset refers to a smaller set extracted from a larger set based on specific criteria or conditions. Imagine having a massive bookshelf with numerous books spanning various genres. If you were to pick out only the science fiction novels, that collection would be a subset of the entire bookshelf.

Similarly, when dealing with datasets, we often need to hone in on particular portions of the data that are relevant to our analysis. This act of extracting specific rows, columns, or data points based on conditions or criteria is called subsetting.

Example:

Consider a data frame containing information about students:

1 Alice 20 A
2 Bob 22 B
3 Charlie 21 A
4 David 23 C

If you wanted to extract data only for students who scored an 'A' grade, the subset would look like:

1 Alice 20 A
3 Charlie 21 A

Subsets allow us to narrow our focus, providing a clearer view of specific segments of data. This ability is vital in data analysis as it facilitates targeted analysis, aiding in deriving meaningful insights without getting overwhelmed by the entirety of the dataset.

## Using the Subset Function

The subset() function is one of R's built-in functions designed specifically for extracting subsets of arrays, matrices, or data frames. It's a versatile tool that allows you to specify both row and column conditions to narrow down your data.

The basic syntax of the subset() function is:

subset(data, subset, select)

• data: The data frame or matrix you're working with.
• subset: The conditions based on which rows are selected.
• select: The columns you want to include in your final subset. If omitted, all columns will be included.

Example 1:

Let's take a sample data frame of students:

students <- data.frame(
ID = 1:4,
Name = c("Alice", "Bob", "Charlie", "David"),
Age = c(20, 22, 21, 23),
Grade = c("A", "B", "A", "C")
)


Suppose you want to subset students who are aged 22 or older:

older_students <- subset(students, Age >= 22)


The expected result:

2 Bob 22 B
4 David 23 C

Example 2:

Let's extract data for students who scored an 'A' grade and only select their names:

a_students <- subset(students, Grade == "A", select = Name)


The expected result:

Name
Alice
Charlie

The subset() function offers a clear and intuitive syntax for data subsetting. However, always be cautious when using it within functions as it might not behave as expected due to its non-standard evaluation. For many routine tasks, it provides a straightforward and readable way to extract portions of your data.

For more details and nuances of the subset() function, always refer to the official R documentation.

## Using Square Brackets

In R, the square brackets ([]) are a foundational tool for subsetting. They offer flexibility in extracting specific rows, columns, or combinations thereof from matrices, arrays, and data frames. The syntax can be summarized as:

data[rows, columns]
• rows: The index or condition for selecting rows.
• columns: The index or condition for selecting columns.

Example 1:

Consider the following data frame:

students <- data.frame(
ID = 1:4,
Name = c("Alice", "Bob", "Charlie", "David"),
Age = c(20, 22, 21, 23),
Grade = c("A", "B", "A", "C")
)


If you wish to extract the first two rows of this data:

first_two <- students[1:2, ]


The expected result:

1 Alice 20 A
2 Bob 22 B

Example 2:

From the same data frame, let's extract the "Name" and "Grade" columns for students who are aged 22 or older:

name_grade <- students[students$Age >= 22, c("Name", "Grade")]  The expected result: Name Grade Bob B David C ### A Few Points to Remember: 1. Omitting the rows or columns argument (i.e., leaving it blank before or after the comma) implies selecting all rows or columns, respectively. 2. Negative indices can be used to exclude rows or columns. For instance, students[-1, ] would return all rows except the first one. 3. Logical conditions, as seen in the second example, can be used to filter rows based on specific criteria. Square brackets provide a direct and efficient way to subset data in R. Their versatility makes them indispensable for a wide range of data manipulation tasks. For more intricate details about subsetting with square brackets, the official R documentation is a valuable resource that delves into the nuances and additional capabilities of this method. ## Using Logical Indexing Logical indexing is a powerful technique in R that allows for subsetting based on conditions that return a logical vector. When you apply a condition to a vector, R assesses each element against the condition, producing a logical vector of TRUE and FALSE values. This resultant vector can then be used to subset data. ### Syntax: The general structure of logical indexing is: data[logical_condition, ]  Here, the logical_condition produces a vector of logical values (TRUE or FALSE) based on which rows from the data are selected. Example 1: Let's use the students' data frame: students <- data.frame( ID = 1:4, Name = c("Alice", "Bob", "Charlie", "David"), Age = c(20, 22, 21, 23), Grade = c("A", "B", "A", "C") )  To extract data for students aged 22 or older: older_students <- students[students$Age >= 22, ]


Expected result:

2 Bob 22 B
4 David 23 C

Example 2:

Using the same data frame, let's find students who scored an 'A' grade:

a_students <- students[students$Grade == "A", ]  Expected result: ID Name Age Grade 1 Alice 20 A 3 Charlie 21 A ### Points to Note: 1. The logical condition must be applied to a column (or a vector) to produce the corresponding logical vector. 2. It's possible to combine multiple logical conditions using & (and), | (or), and ! (not). For instance, to extract data for students aged 22 or older AND who scored an 'A': specific_students <- students[students$Age >= 22 & students$Grade == "A", ]  Logical indexing is fundamental to data manipulation in R. Its power lies in its simplicity and efficiency, enabling quick filtering based on complex conditions. For those keen on understanding the intricacies and potential applications of logical indexing, the official R documentation provides an in-depth exploration. ## Using the which() Function The which() function in R returns the indices of the elements that satisfy a given condition. While logical indexing directly returns the elements of a vector or rows of a data frame that meet a condition, which() instead provides the positions (indices) of those elements or rows. ### Syntax: The general form of the which() function is: which(logical_condition)  The function will return a vector of indices where the logical_condition is TRUE. Example 1: Let's consider the students' data frame: students <- data.frame( ID = 1:4, Name = c("Alice", "Bob", "Charlie", "David"), Age = c(20, 22, 21, 23), Grade = c("A", "B", "A", "C") )  To find the indices of students aged 22 or older: indices <- which(students$Age >= 22)


Expected result (vector of indices):

 2 4


Using these indices, you can then subset the data frame:

older_students <- students[indices, ]


Resultant table:

2 Bob 22 B
4 David 23 C

Example 2:

Using the same data frame, let's find the indices of students who scored a 'B' or 'C' grade:

grade_indices <- which(students$Grade %in% c("B", "C"))  Expected result:  2 4  Using these indices to subset: specific_grades <- students[grade_indices, ]  Resultant table: ID Name Age Grade 2 Bob 22 B 4 David 23 C ### Key Takeaways: 1. The which() function is especially useful when you want to know the positions of elements or rows meeting a condition, not just the values themselves. 2. It returns a vector of indices, which can then be used for further operations or subsetting. 3. which() works with vectors, matrices, and data frames. The which() function provides a nuanced approach to data subsetting in R, offering an intermediary step between identifying and extracting data based on conditions. For those seeking a deeper understanding and more examples of its usage, the official R documentation is an excellent resource. ## Using the dplyr Package dplyr is not just a function but an entire package within the tidyverse ecosystem that revolutionized data manipulation in R. Developed by Hadley Wickham and his team, dplyr provides a cohesive set of verbs that make data manipulation tasks intuitive and readable. Some of the primary functions (verbs) within dplyr include filter(), select(), arrange(), mutate(), and summarize(). To use dplyr, you first need to install and load it: install.packages("dplyr") library(dplyr)  Example 1: Filtering and Selecting Given our familiar students' data frame: students <- data.frame( ID = 1:4, Name = c("Alice", "Bob", "Charlie", "David"), Age = c(20, 22, 21, 23), Grade = c("A", "B", "A", "C") )  To filter students aged 22 or older and only select their names: older_students <- students %>% filter(Age >= 22) %>% select(Name)  Expected result: Name Bob David Example 2: Arranging and Mutating From the same students' data frame, let's arrange students by age in descending order and add a new column that classifies them as "Adult" if they are 22 or older and "Young" otherwise: classified_students <- students %>% arrange(desc(Age)) %>% mutate(Status = ifelse(Age >= 22, "Adult", "Young"))  Expected result: ID Name Age Grade Status 4 David 23 C Adult 2 Bob 22 B Adult 3 Charlie 21 A Young 1 Alice 20 A Young ### Key Points: 1. The %>% operator (pipe operator) is used to chain multiple dplyr operations. It takes the result of the left expression and uses it as the first argument of the right expression. 2. dplyr operations are generally more readable than base R operations, especially when multiple operations are chained together. 3. While dplyr can be a bit slower than data.table for very large datasets, its syntax and readability make it a favorite for many R users. dplyr offers a wide array of other functionalities beyond the examples provided. For those who want to delve deeper and explore the versatility of dplyr, the official documentation is a treasure trove of information, examples, and best practices. ## Using the apply() Family of Functions in R The apply() family in R offers a set of functions to perform operations on chunks of data, such as vectors, matrices, or lists, often eliminating the need for explicit loops. This set of functions is particularly useful for operations on subsets of data, either by row, column, or a combination of both. The primary members of this family include: • apply(): Apply functions over array margins (typically matrices). • lapply(): Apply a function over a list or vector, returning a list. • sapply(): Like lapply(), but attempts to simplify the result into a vector or matrix if possible. • mapply(): A multivariate version of lapply(). • tapply(): Apply a function over subsets of a vector, conditioned by another vector (or vectors). ### 1. Using apply() Given a matrix of student scores: scores <- matrix(c(80, 85, 78, 92, 87, 88, 76, 95), ncol=2) rownames(scores) <- c("Alice", "Bob", "Charlie", "David") colnames(scores) <- c("Math", "History")  To calculate the mean score for each student: student_means <- apply(scores, 1, mean)  Expected result:  Alice Bob Charlie David 82.5 86.5 82.0 85.5  ### 2. Using lapply() and sapply() Given a list of numeric vectors: data_list <- list(Alice = c(80, 85), Bob = c(87, 88), Charlie = c(76, 95))  To calculate the mean score for each student using lapply(): student_means_list <- lapply(data_list, mean)  Expected result (as a list): $Alice
 82.5

$Bob  87.5$Charlie
 85.5


If you'd prefer a simpler structure (like a vector), you can use sapply():

student_means_vector <- sapply(data_list, mean)


Expected result (as a named vector):

  Alice     Bob  Charlie
82.5    87.5      85.5


### Key Takeaways:

1. The apply() family of functions is designed to help avoid explicit loops in R, leading to more concise and often faster code.
2. Each function in the family has a specific use case, depending on the type of data (vector, matrix, list) and the desired output.
3. While these functions can be more efficient than loops for some tasks, they're not always the fastest. Functions from the data.table and dplyr packages can often be faster for data frame operations.

For more in-depth understanding and additional functionalities of the apply() family, the official R documentation provides comprehensive insights, examples, and guidelines.

## Conclusion

Subsetting in R is not merely a technical skill; it's an art that requires a blend of precision, knowledge, and intuition. As with any art form, mastering it opens up a world of possibilities. The techniques we've discussed, ranging from the foundational to the advanced, represent just the tip of the iceberg in R's vast arsenal of data manipulation tools. Each method has its unique strengths and ideal use cases, and discerning which to use when can significantly enhance the efficiency and clarity of your data analysis.

Yet, as with any tool, its power is maximized in the hands of the informed. Continuous learning and practice are key. The world of R is dynamic, with new packages and methods emerging regularly. Stay curious, consult the official R documentation, engage with the community, and never hesitate to experiment with new techniques. By doing so, you ensure that your subsetting skills remain sharp, relevant, and ready to tackle the ever-evolving challenges of data analysis.