Data Frames
In the last section, we introduced the “list” structure, which allows you to store a set of objects of any mode. A data frame is, like many R objects, a named list. However, a data frame enforces a number of constraints on this named list structure. In particular, a data frame is constrained to be a named list that can only hold vectors of the same length.
Creating a Data Frame
We create a data frame by specifying a set of named vectors to the data.frame. For example, let’s create a data frame containing New York temperature forecasts over the next five days:
> weather <- data.frame( # Create a data frame + Day = c("Saturday", "Sunday", "Monday", "Tuesday", "Wednesday"), + Date = c("Jul 4", "Jul 5", "Jul 6", "Jul 7", "Jul 8"), + TempF = c(75, 86, 83, 83, 87) + ) > weather # Print the data frame Day Date TempF 1 Saturday Jul 4 75 2 Sunday Jul 5 86 3 Monday Jul 6 83 4 Tuesday Jul 7 83 5 Wednesday Jul 8 87
Querying Data Frame Attributes
Because a data frame is simply a named list, the functions we used to query list attributes will work the same way:
- The length function returns the number of elements of the list (that is, the number of columns).
- The names function returns the element (column) names.
The following example illustrates the use of these functions:
> length(weather) # Number of columns [1] 3 > names(weather) # Column names [1] "Day" "Date" "TempF"
Selecting Columns from the Data Frame
As with lists, we can reference a single element (vector) from our data frame using either double squared brackets or the $ symbol:
> weather # The whole data frame Day Date TempF 1 Saturday Jul 4 75 2 Sunday Jul 5 86 3 Monday Jul 6 83 4 Tuesday Jul 7 83 5 Wednesday Jul 8 87 > weather[[3]] # The "third" column [1] 75 86 83 83 87 > weather$TempF # The "TempF" column [1] 75 86 83 83 87
Selecting Columns from the Data Frame
Because we can reference columns in this way, we can also use these approaches to add new columns. For example, let’s add a new column called TempC to our data containing the temperature in degrees Celsius:
> weather$TempC <- round( (weather$TempF - 32) * 5/9 ) > weather Day Date TempF TempC 1 Saturday Jul 4 75 24 2 Sunday Jul 5 86 30 3 Monday Jul 6 83 28 4 Tuesday Jul 7 83 28 5 Wednesday Jul 8 87 31
Subscripting Columns
Because the columns of data frames are vectors, we can subscript them using the approaches from Hour 3, “Single-Mode Data Structures.” Specifically, we can subscript the columns using square brackets:
DATA$COLUMN [ Input specifying the subset to return ]
As before, we can reference using blank, positive, negative, or logical inputs. Character inputs do not make sense for referencing columns because the individual elements within columns are not associated with element names.
Blank, Positive, and Negative Subscripts
If we use a blank subscript, all the values of the vector are returned:
> weather Day Date TempF TempC 1 Saturday Jul 4 75 24 2 Sunday Jul 5 86 30 3 Monday Jul 6 83 28 4 Tuesday Jul 7 83 28 5 Wednesday Jul 8 87 31 > weather$TempF [ ] # All values of TempF column [1] 75 86 83 83 87
If we use a vector of positive integers, it refers to the elements of the column (vector) to return:
> weather$TempF [ 1:3 ] # First 3 values of the TempF column [1] 75 86 83
If we use a vector of negative integers, it refers to the elements of the column (vector) to omit:
> weather$TempF [ -(1:3) ] # Omit the first 3 values of the TempF column [1] 83 87
Logical Subscripts
As you saw in the last hour, we can provide a vector of logical values to reference a vector, and only the corresponding TRUE values are returned. Here’s an example:
> weather$TempF [1] 75 86 83 83 87 > weather$TempF [ c(F, T, F, F, T) ] # Logical subscript [1] 86 87
Of course, we usually generate the logical vector with a logical statement involving a vector. For example, we could return all the TempF values greater than 85 using this statement:
> weather$TempF [ weather$TempF > 85 ] # Logical subscript [1] 86 87
Instead, we could reference a column of a data frame based on logical statements involving one or more other columns (because all columns are constrained to be the same length):
> weather$Day [ weather$TempF > 85 ] # Logical subscript [1] Sunday Wednesday Levels: Monday Saturday Sunday Tuesday Wednesday
Referencing as a Matrix
Although a data frame is structured as a named list, its rectangular output is more similar to the matrix structure you saw earlier. As such, R allows us to reference the data frame as if it was a matrix.
Matrix Dimensions
Because we can treat a data frame as a matrix, we can use the nrow and ncol functions to return the number of rows and columns:
> nrow(weather) # Number of rows [1] 5 > ncol(weather) # Number of columns [1] 4
Subscripting as a Matrix
In Hour 3, you saw that you can subscript a matrix using square brackets and two inputs (one for the rows, one for the columns). We can use the same approach to subscript a data frame, where each input can be one of the standard five input types:
DATA.FRAME [ Rows to return , Columns to return]
Blanks, Positives, and Negatives
We can use blank subscripts to return all rows and columns from a data frame:
> weather[ , ] # Blank, Blank Day Date TempF TempC 1 Saturday Jul 4 75 24 2 Sunday Jul 5 86 30 3 Monday Jul 6 83 28 4 Tuesday Jul 7 83 28 5 Wednesday Jul 8 87 31
If we use vectors of positive integers, they are used to provide an index of the rows/columns to return. This example uses positive integers to return the first four rows and the first three columns:
> weather[ 1:4, 1:3 ] # +ive, +ive Day Date TempF 1 Saturday Jul 4 75 2 Sunday Jul 5 86 3 Monday Jul 6 83 4 Tuesday Jul 7 83
We can use vectors of negative integers to indicate the rows and columns to omit in the return result, as shown in this example:
> weather[ -1, -3 ] # -ive, -ive Day Date TempC 2 Sunday Jul 5 30 3 Monday Jul 6 28 4 Tuesday Jul 7 28 5 Wednesday Jul 8 31
In the preceding examples, we have used the same input type for both rows and columns. However, we can mix up the input types, as illustrated in this example, where we select the first four rows and all the columns:
> weather[ 1:4, ] # +ive, Blank Day Date TempF TempC 1 Saturday Jul 4 75 24 2 Sunday Jul 5 86 30 3 Monday Jul 6 83 28 4 Tuesday Jul 7 83 28
Logical Subscripts
We often use logical subscripts to reference specific rows of the data to return. To perform this action, we need to provide a logical value for each row of the data:
> weather # The original data Day Date TempF TempC 1 Saturday Jul 4 75 24 2 Sunday Jul 5 86 30 3 Monday Jul 6 83 28 4 Tuesday Jul 7 83 28 5 Wednesday Jul 8 87 31 > weather[ c(F, T, F, F, T), ] # Logical, Blank Day Date TempF TempC 2 Sunday Jul 5 86 30 5 Wednesday Jul 8 87 31
As before, we more commonly apply a logical statement to a column (vector) contained in the data frame to generate the logical vector:
> weather[ weather$TempF > 85, ] # Logical, Blank Day Date TempF TempC 2 Sunday Jul 5 86 30 5 Wednesday Jul 8 87 31 > weather[ weather$Day != "Sunday", ] # Logical, Blank Day Date TempF TempC 1 Saturday Jul 4 75 24 3 Monday Jul 6 83 28 4 Tuesday Jul 7 83 28 5 Wednesday Jul 8 87 31
Character Subscripts
We often use vectors of character strings to specify the columns we wish to return. Although a data frame has “row names,” we tend not to reference rows using character strings. This example selects the Day and TempC columns from the data, filtering so that only rows with temperatures greater than 85°F are returned:
> weather[ weather$TempF > 85, c("Day", "TempC")] # Logical, Character Day TempC 2 Sunday 30 5 Wednesday 31
Summary of Subscripting Data Frames
At this point, it is worth a quick review of some of the key syntax used to select subsets of a data frame. In particular, consider the following lines of code:
> weather$Day [ weather$TempF > 85 ] # Days where TempF > 85 [1] Sunday Wednesday Levels: Monday Saturday Sunday Tuesday Wednesday > weather [ weather$TempF > 85 , ] # All data where TempF > 85 Day Date TempF TempC 2 Sunday Jul 5 86 30 5 Wednesday Jul 8 87 31 > weather [ weather$TempF > 85 , c("Day", "TempF") ] # 2 columns where TempF > 85 Day TempF 2 Sunday 86 5 Wednesday 87
In the first example, we are subscripting weather$Day. This is a vector, so we provide a single input (a logical vector in this case). It returns the two values of the Day column where the corresponding TempF column is greater than 85.
In the second example, we are now referencing data from the whole weather dataset. As such, we need two subscripts (one for rows, one for columns). In this example, we use a logical vector for the rows and blank for the columns, returning all columns but only rows where TempF is greater than 85. Attention should be paid to the use of the comma in the first example versus the second example, driven by the fact that we are referencing data from a vector (first example) versus the whole data frame (second example).
The third example extends the second example to pick only columns Day and TempF using a character vector for the column input.