R-Basics: Part 3- All about Idexing

 Overview

  • Subset a vector based on properties of another vector.
  • Use multiple logical operators to index vectors.
  • Extract the indices of vector elements satisfying one or more logical conditions.
  • Extract the indices of vector elements matching with another vector.
  • Determine which elements in one vector are present in another vector. * Wrangle data tables using functions in the dplyr package.
  • Modify a data table by adding or changing columns.
  • Subset rows in a data table.
  • Subset columns in a data table.
  • Perform a series of operations using 'pipe operator'.
  • Create data frames.
  • Plot data in scatter plots, box plots, and histograms.
  • Sample Q/As

Indexing

R provides powerful and convenient way of indexing a vector. We can use the logical operators to index a vector.

If we compare a vector with a single number, R performs a test for each entry

Let’s see some examples:

index <- murder_rate < 0.71
#index
murders$state[index]
[1] "Hawaii"        "Iowa"          "New Hampshire" "North Dakota" 
[5] "Vermont"      
#Or
index1 <- murder_rate > 0.71
#index1
murders$state[index1]
 [1] "Alabama"              "Alaska"               "Arizona"             
 [4] "Arkansas"             "California"           "Colorado"            
 [7] "Connecticut"          "Delaware"             "District of Columbia"
[10] "Florida"              "Georgia"              "Idaho"               
[13] "Illinois"             "Indiana"              "Kansas"              
[16] "Kentucky"             "Louisiana"            "Maine"               
[19] "Maryland"             "Massachusetts"        "Michigan"            
[22] "Minnesota"            "Mississippi"          "Missouri"            
[25] "Montana"              "Nebraska"             "Nevada"              
[28] "New Jersey"           "New Mexico"           "New York"            
[31] "North Carolina"       "Ohio"                 "Oklahoma"            
[34] "Oregon"               "Pennsylvania"         "Rhode Island"        
[37] "South Carolina"       "South Dakota"         "Tennessee"           
[40] "Texas"                "Utah"                 "Virginia"            
[43] "Washington"           "West Virginia"        "Wisconsin"           
[46] "Wyoming"             

Counting total true entries using sum() function

It is possible because the logical vector above gets coerced into numeric. True is changed to 1 and False to 0.

sum(index)
[1] 5
sum(index1)
[1] 46

It was right that we have 5 states with less than 0.71 per capita murder rates and 46 including the District of Columbia with higher than 0.71 per capita murder rates.

Sometimes we may require the data points that meet a couple of conditions. Here’s the list of the logical vectors.

knitr::include_graphics("C:/Users/nirma/Documents/GitHub/Practice/logical vectors.JPG")

Setting two or more conditionals using & function

For example, somebody wants to live in the mountains but she wants the murder rate to be less than 1. So, western regions have a lot of mountains and let’s see which state has lower murder rates than 1.

west <- murders$region == "West"
safe <- murder_rate <= 1

#Defining the index
index2 <- safe & west
murders$state[index2]
[1] "Hawaii"  "Idaho"   "Oregon"  "Utah"    "Wyoming"

Based on the results, there are five Western States that have murder rates lower or equal to 1 pre 1,00,000.

Indexing Functions

  • The function which() gives us the entries of a logical vector that are true.
x <- c(FALSE, TRUE, FALSE, TRUE, TRUE, FALSE)
which(x)    # returns indices that are TRUE
[1] 2 4 5

For example, to determine the murder rate in Florida we may do the following:

index <- which(murders$state == "Florida")
index
[1] 10
murder_rate[index]
[1] 3.398069
  • The function match() looks for entries in a vector and returns the index needed to access them. For example, if we want to obtain the indices and subsequent murder rates of Montana, North Carolina, and Maryland, we do:
index <- match(c("Montana", "North Carolina", "Maryland"), murders$state)
index
[1] 27 34 21
murders$state[index]
[1] "Montana"        "North Carolina" "Maryland"      
murder_rate[index]
[1] 1.212838 2.999324 5.074866
  • We use the function %in% if we want to know whether or not each element of a first vector is in a second vector.

It is perhaps the most useful function. It helps us which items in one vector is also in other vector. For example, I am creating three vectors x, y, and z and run some tests.

x <- c("k", "l", "m", "n", "o", "p", "q", "r", "s")
y <- c("k", "l", "m","t","u","v")
z <- c("e", "f", "g","o", "p", "q", "r","v")
# Now lets check
y %in% x
[1]  TRUE  TRUE  TRUE FALSE FALSE FALSE
y %in% z
[1] FALSE FALSE FALSE FALSE FALSE  TRUE
z %in% x
[1] FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE

“True” shows that the value it denotes is in both vector, while “False” doesn’t.

I want to check if Orlando, Jackson, Purchase, and Georgia are states. I can use the %in% function.

c("Orlando","Jackson","Purchase", "Georgia") %in% murders$state
[1] FALSE FALSE FALSE  TRUE

Orlando, Jackson, and Purchase are not states but Georgia is.

Basic Data Wrangling using dplyr package

We can load the dplyr package the following way:

library(dplyr)
  • To change a data table by adding a new column, or changing an existing one, we use the mutate() function.

The function mutate takes the data frame as the first argument and the name and value of the variable in the second argument. For example, we created a new vector called murder_rate previously, but it hasn’t been the part of our data frame. Now lets’ add the vector as a new column to the murders data frame.

#Checking the first few cases of murders data set
head(murders)
       state abb region population total
1    Alabama  AL  South    4779736   135
2     Alaska  AK   West     710231    19
3    Arizona  AZ   West    6392017   232
4   Arkansas  AR  South    2915918    93
5 California  CA   West   37253956  1257
6   Colorado  CO   West    5029196    65
#Adding a new column named m_rate
murders<- mutate(murders, m_rate = total/population*100000)
#Checking for changes
head(murders)
       state abb region population total   m_rate
1    Alabama  AL  South    4779736   135 2.824424
2     Alaska  AK   West     710231    19 2.675186
3    Arizona  AZ   West    6392017   232 3.629527
4   Arkansas  AR  South    2915918    93 3.189390
5 California  CA   West   37253956  1257 3.374138
6   Colorado  CO   West    5029196    65 1.292453

Second table has a new column named m_rate. How is it possible? The mutate() function looked for the vectors named ‘total’ and ‘population’ in the ‘murders’ data frame and conducted the calculation. It did not though check the work station.

  • To filter the data by subsetting rows, we use the function filter().

Suppose we are filtering the data frame that only shows the data from the states which has murder rate lower than 0.71 per capita. Filter () function takes the data table as the first argument and conditional function as the second.

filter(murders, m_rate <= 0.71)
          state abb        region population total    m_rate
1        Hawaii  HI          West    1360301     7 0.5145920
2          Iowa  IA North Central    3046355    21 0.6893484
3 New Hampshire  NH     Northeast    1316470     5 0.3798036
4  North Dakota  ND North Central     672591     4 0.5947151
5       Vermont  VT     Northeast     625741     2 0.3196211

We can see that there are five states with less than 0.71 murder rates. We got the entire table for these five states.

  • To subset the data by selecting specific columns, we use the select() function.

Some data tables contain hundred of columns, and we may have to select only a few of them. I am going to create a new object ‘my_data’ by subetting the murders data table with the help of ‘select()’ function.

my_data <- select(murders, abb, region, m_rate)
head(my_data)
  abb region   m_rate
1  AL  South 2.824424
2  AK   West 2.675186
3  AZ   West 3.629527
4  AR  South 3.189390
5  CA   West 3.374138
6  CO   West 1.292453
# Now, lets filter the sates with less than 0.90 murder rate
filter(my_data, m_rate <= 0.90)
  abb        region    m_rate
1  HI          West 0.5145920
2  ID          West 0.7655102
3  IA North Central 0.6893484
4  ME     Northeast 0.8280881
5  NH     Northeast 0.3798036
6  ND North Central 0.5947151
7  UT          West 0.7959810
8  VT     Northeast 0.3196211
9  WY          West 0.8871131

The resulting table has just 3 columns and they are stored on an object named ‘my_data’. It is much smaller and manageable table compared to the ‘murders’ table. And there are 9 states which have the murder rates equal to or higher than 0.90.

  • We can perform a series of operations by sending the results of one function to another function using the pipe operator, %>%.

Let’s put all these functions together. Using the dplyr package we can accomplish multiple tasks at the same time if we implement the pipe operator. For example: We can take some data, ‘select’ required columns, and ‘filter’ some rows. Doing so, we can avoid creating new data table like my_data above.

murders %>% #take murders data table
  select(state,region,m_rate) %>% #select state, region, and m_rate columns
  filter(m_rate <= 0.90) #filter the rows which has m_rate <= 0.90
          state        region    m_rate
1        Hawaii          West 0.5145920
2         Idaho          West 0.7655102
3          Iowa North Central 0.6893484
4         Maine     Northeast 0.8280881
5 New Hampshire     Northeast 0.3798036
6  North Dakota North Central 0.5947151
7          Utah          West 0.7959810
8       Vermont     Northeast 0.3196211
9       Wyoming          West 0.8871131

Here we go. We got the same result here.

Creating Data Frames

  • We can use the data.frame() function to create data frames. I am going to create a data frame named ‘test_scores’ with three columns and four rows. First column is the ‘name’ column followed by ‘pretest’ and ‘posttest’ scores.
test_scores <- data.frame(names = c("Sushila", "Aanishma", "Nikita", "Arjun"), pretest = c(85, 98, 74, 69),
                          posttest = c(95, 99, 86, 79))
test_scores
     names pretest posttest
1  Sushila      85       95
2 Aanishma      98       99
3   Nikita      74       86
4    Arjun      69       79

Yey. We just created the data frame with 3 columns and 4 rows.

Formerly, the data.frame() function turned characters into factors by default. To avoid this, we could utilize the stringsAsFactors argument and set it equal to false. As of R 4.0, it is no longer necessary to include the stringsAsFactors argument, because R no longer turns characters into factors by default.

Basic Plots

Exploratory data analysis is perhaps the most important aspect of R. We can quickly go from idea to data to data visualization without much effort.

  • We can create a simple scatterplot using the function plot().
population_in_millions <- murders$population/10^6
total_gun_murders <- murders$total
plot(population_in_millions, total_gun_murders)

It is easy to see that there is linear relationship between population and the total gun murders.

  • Histograms are powerful graphical summaries that give us a general overview of the types of values you have. In R, they can be produced using the hist() function.
hist(murder_rate)

murders$state[which.max(murders$m_rate)]
[1] "District of Columbia"
  • Boxplots provide a more compact summary of a distribution than a histogram and are more useful for comparing distributions. They can be produced using the boxplot() function.
boxplot(m_rate ~ region, data = murders)

We can see that South has higher murder rate than the rest of the regions.

Sample Q/As

For these questions we need the heights data set included in the dslabs package. Lets invoke the library, get the data ready and set the decimal points for rest of the analyses.

library(dslabs)
data(heights)
options(digits = 3)#Reports 3 significant digits for all answers
head(heights)
     sex height
1   Male     75
2   Male     70
3   Male     68
4   Male     74
5   Male     61
6 Female     65
summary(heights)
     sex          height    
 Female:238   Min.   :50.0  
 Male  :812   1st Qu.:66.0  
              Median :68.5  
              Mean   :68.3  
              3rd Qu.:71.0  
              Max.   :82.7  

The data set has only two variables, ‘sex’ and ‘height’. Of all the data points, 238 are Females and 812 males. The average height is 68.5 inch.

Q.1. First, determine the average height in this dataset. Then create a logical vector ind* with the indices for those individuals who are above average height. How many individuals in the dataset are above average height?*

# calculating the average height of the sample
average_height <- mean(heights$height)
#indexing the data for the individuals who are higher than average height
ind <- heights$height > average_height
# heights$height[ind] #Gives all the heights higher than average. I don't want to make my paper messy. 
sum(ind)
[1] 532

There are 532 individuals in the data set who are above average tall.

Q.2. How many individuals in the dataset are above average height and are female?

# Calculating Female only Population
female_sample <- heights$sex == "Female"
taller_female <- heights$height > mean(heights$height)
# calculating above average tall females
indf <- female_sample & taller_female
sum(indf)
[1] 31

There are total of 31 females who are taller than the average height.

Q.3. If you use mean() on a logical (TRUE/FALSE) vector, it returns the proportion of observations that are TRUE. What proportion of individuals in the dataset are female?

mean(heights$sex == "Female")
[1] 0.227

The result shows that 0.227% of the indviduals in the dataset are females.

Q.4. Determine the minimum height in the heights dataset.

min(heights$height)
[1] 50

The minimum height among the sample is 50 inches.

Q.5. Use the match() function to determine the index of the first individual with the minimum height.

match(50,heights$height)
[1] 1032

The first person with the minimum height in the data set is located in the 1032th row of the height column.

Q.6. Subset the sex column of the dataset by the index in 5 to determine the individual’s sex.

heights$sex[match(50,heights$height)]
[1] Male
Levels: Female Male

The 1032th person with the height of 50 inches is a Male.

Q.6. Determine the maximum height.

max(heights$height)
[1] 82.7

The maximum heights among the sample population is 82.7 inches.

Which integer values are between the maximum and minimum heights? For example, if the minimum height is 10.2 and the maximum height is 20.8, your answer should be x <- 11:20 to capture the integers in between those values. (If either the maximum or minimum height are integers, include those values too.)

Q.7. Write code to create a vector x that includes the integers between the minimum and maximum heights (as numbers).

x <- 50:83 

Q.8. How many of the integers in x are NOT heights in the dataset?

sum(!(x %in% heights$height))
[1] 4

There are four integers that are not heights in heights$height.

Using the heights dataset, create a new column of heights in centimeters named ht_cm. Recall that 1 inch = 2.54 centimeters. Save the resulting dataset as heights2.

heights <- mutate(heights, ht_cm = height*2.54)
head(heights)
     sex height ht_cm
1   Male     75   190
2   Male     70   178
3   Male     68   173
4   Male     74   188
5   Male     61   155
6 Female     65   165

The new dataset has the third column I just created.

Q.9. What is the height in centimeters of the 18th individual (index 18)?

heights$ht_cm[18]
[1] 163

The height of the 18th individual in the data set is 163 cm.

Q.10. What is the mean height in centimeters?

mean(heights$ht_cm)
[1] 174

The mean height of the sample in the data set is 174 centimeters.

Create a data frame females by filtering the heights2 data to contain only female individuals.

females <- filter(heights, sex == "Female")
head(females)
     sex height ht_cm
1 Female     65   165
2 Female     66   168
3 Female     62   157
4 Female     66   168
5 Female     64   163
6 Female     60   152

The new data frame females has been created and it contains the information regarding the female, only.

Q.11. How many females are in the heights2 dataset?

nrow(females)
[1] 238

There are total of 238 females in the data set.

Q.12. What is the mean height of the females in centimeters?

mean(females$ht_cm)
[1] 165

The mean height of the females in the data set is 165 cm.

The olive dataset in dslabs contains composition in percentage of eight fatty acids found in the lipid fraction of 572 Italian olive oils:

data(olive)
head(olive)
          region         area palmitic palmitoleic stearic oleic linoleic
1 Southern Italy North-Apulia    10.75        0.75    2.26  78.2     6.72
2 Southern Italy North-Apulia    10.88        0.73    2.24  77.1     7.81
3 Southern Italy North-Apulia     9.11        0.54    2.46  81.1     5.49
4 Southern Italy North-Apulia     9.66        0.57    2.40  79.5     6.19
5 Southern Italy North-Apulia    10.51        0.67    2.59  77.7     6.72
6 Southern Italy North-Apulia     9.11        0.49    2.68  79.2     6.78
  linolenic arachidic eicosenoic
1      0.36      0.60       0.29
2      0.31      0.61       0.29
3      0.31      0.63       0.29
4      0.50      0.78       0.35
5      0.50      0.80       0.46
6      0.51      0.70       0.44

The data has been set. Now

Q.13. Plot the percent palmitic acid versus palmitoleic acid in a scatterplot. What relationship do you see?

palmitic_acid <- olive$palmitic
palmitoleic_acid <- olive$palmitoleic
plot(palmitic_acid,palmitoleic_acid)

We see the positive linear relationship between these variables.

Q.13. Create a histogram of the percentage of eicosenoic acid in olive.

hist(olive$eicosenoic)

The most common value of eicosenoic acid is below 0.05%.

Q.14. Make a boxplot of palmitic acid percentage in olive with separate distributions for each region. Which region has the highest median palmitic acid percentage? Which region has the most variable palmitic acid percentage?

boxplot(palmitic ~ region, data = olive)

Southern Italy has the highest median palmitic acid percentage, and the same region has the most variable data.


Comments

Popular posts from this blog

Education Matters: Understanding Nepal’s Education (Publication Date: June 19, 2023, Ratopati-English, Link at the End)

Multiple Correspondence Analysis (MCA) in Educational Data

charting Concept and Computation: Maps for the Deep Learning Frontier