In the tenth small group practice session we will focus on writing for loops and combining them with conditional code evaluation. Our aim is to produce a correlation table similar to this one:

A1 A2 A3 A4 A5 O1 O2 O3 O4 O5
A1 <.001 <.001 <.001 <.001 .219 .004 <.001 <.001 <.001
A2 \(-\).375 <.001 <.001 <.001 <.001 .862 <.001 <.001 <.001
A3 \(-\).301 .510 <.001 <.001 <.001 .625 <.001 .020 <.001
A4 \(-\).166 .348 .378 <.001 .024 .043 .048 .014 .083
A5 \(-\).230 .406 .530 .323 <.001 .406 <.001 .361 .003
O1 \(-\).026 .127 .165 .048 .164 <.001 <.001 <.001 <.001
O2 .061 .004 \(-\).010 .043 \(-\).018 \(-\).264 <.001 <.001 <.001
O3 \(-\).096 .156 .231 .042 .230 .412 \(-\).324 <.001 <.001
O4 \(-\).100 .076 .049 \(-\).052 .019 .240 \(-\).123 .227 <.001
O5 .126 \(-\).103 \(-\).075 .037 \(-\).063 \(-\).304 .355 \(-\).370 \(-\).242

 

Now, to be straight with you, creating the table above requires neither loops nor conditional commands but it’s a good exercise.

Warm-up

 

Task 1

Let’s warm up by writing a simple loop.

 

Task 1.1

Write a skeleton of a loop that iterates 10 times.

Hint Set an iterator variable (by convention i, j, etc.) to run over a vector of integers from 1 to 10.

Solution

for (i in 1:10) {
  
}

Because there’s no code to iteratively evaluate, this loop doesn’t really do anything other than waste a few CPU cycles.

 

Task 1.2

Have the loop output the iterator variable by typing it’s name inside of the {}s.

Solution

for (i in 1:10) {
  i
}

As you can see this doesn’t seem to do anything eiter. That’s because loops, just like if(){} else{} doesn’t outpomatically print/show evaluated objects. To get them to do that, you need the print() function.

 

Task 1.3

Make the code actually print out the iterator for every iteration of the loop.

Hint Simply wrap the variable inside the {}s in a print() function.

Solution

for (i in 1:10) {
  print(i)
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10

 

Task 1.4

Above your loop, write code that creates a vector vec containing 20 NAs.

Hint The rep() fuction is handy here.

Solution

vec <- rep(NA, 20)
# printout just to show it worked
vec
 [1] NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA

 

Task 1.5

Change the code inside the loop to assign the value of i to the ith element of vec (assuming i is the name of your iterator).

Hint You will need to index vec using i.

Solution

vec <- rep(NA, 20)
for (i in 1:10) {
  vec[i] <- i
}
vec # see result
 [1]  1  2  3  4  5  6  7  8  9 10 NA NA NA NA NA NA NA NA NA NA

 

Task 1.6

Let’s say we changed our mind and want the values of i in the last 10 rather than the first 10 places of vec. Can you figure out how to do that?

Hint Use maths!

Solution

vec <- rep(NA, 20)
for (i in 1:10) {
  vec[i+10] <- i
}
vec
 [1] NA NA NA NA NA NA NA NA NA NA  1  2  3  4  5  6  7  8  9 10

 

Task 1.7

Can you edit the code so that the loop populates the vec vector like this?

 [1] NA NA NA NA NA NA NA NA NA NA 10  9  8  7  6  5  4  3  2  1
Hint There are two solutions to this problem.

Solution

vec <- rep(NA, 20)
for (i in 1:10) {
  vec[21-i] <- i
}
vec

# alternatively
vec <- rep(NA, 20)
for (i in 1:10) {
  vec[i + 10] <- 11 - i
}
vec

 

Task 1.8

Last one before we move on. Can you use the loop to recreate this vector?

 [1] NA 19 NA 17 NA 15 NA 13 NA 11 NA  9 NA  7 NA  5 NA  3 NA  1
Hint There are two solutions to this problem.

Solution

vec <- rep(NA, 20)
for (i in 1:10) {
  vec[2*i] <- 21- 2* i
}
vec

Main course

OK, let’s make the correlation table with p-values now.

Again, there are several ways of creating such a table; some of them use loops, some of them don’t. But for the sake of practice, let’s zoom in on one of the loopy solutions.

 

Task 2

Let’s first get our data. To save time, here’s the code that selects only complete cases and only the “agreeableness” and “openness” items from the psych::bfi data set. You can click on the code to copy it.

bfi <- psych::bfi
bfi <- bfi[complete.cases(bfi),
           grep("^A|^O", names(bfi))] # columns beginning with A or O

 

Task 3

Create a matrix cor_mat containing only NAs that has the required dimensions. We are looking at 10 variables, so we need a 10× 10 matrix.

Hint Matrices are created using the matrix() function.

Solution

cor_mat <- matrix(NA, nrow = 10, ncol = 10)
cor_mat
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [2,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [3,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [4,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [5,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [6,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [7,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [8,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [9,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
[10,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA

 

Task 4

Let’s run a correlation test noe.

 

Task 4.1

First, write two separate base R commands that subset the first two columns of bfi . Use indexing with column numbers rather than names to get the columns out of the data frame.

Hint You need to use the [[x]] or the [ , x] notation for subsetting.

Solution

# both work equally well
bfi[[1]] # list notation: first list element (in data.frames, that's a column)
   [1] 6 4 4 4 1 2 4 1 2 2 4 2 1 5 1 1 1 1 1 5 2 1 5 2 1 1 1 1 3 4 1 1 1 3 1 3 2 2 4 2 1 4 2 1 4 4 1 3 2 1 2 1 1 1 1 4 1 1 1 1 1 2 1 2 2 3 1
  [68] 4 2 3 2 1 1 1 2 3 1 1 1 1 4 1 5 2 1 4 2 6 2 2 2 2 2 2 2 3 2 1 1 1 1 2 2 2 1 5 2 1 2 2 1 1 1 2 4 2 3 1 2 2 2 1 2 1 1 2 2 1 3 4 1 2 1 1
 [135] 6 4 3 4 3 4 3 1 1 2 2 1 2 1 2 5 1 2 1 3 2 1 2 2 2 1 2 5 5 1 1 1 1 3 1 2 5 5 3 3 2 1 3 3 4 1 4 3 3 3 3 4 6 3 5 3 5 1 1 4 5 3 6 2 4 3 2
 [202] 1 1 4 3 1 2 3 1 1 4 2 3 2 2 2 3 1 2 1 1 1 2 3 1 4 3 1 1 2 3 4 5 1 3 1 2 1 3 2 3 2 2 2 2 5 4 3 1 1 2 1 4 1 3 1 2 1 2 1 2 1 2 5 2 2 4 2
 [269] 3 2 1 4 3 1 1 1 4 1 4 1 6 1 3 1 2 1 1 1 4 2 2 4 2 5 1 2 4 2 2 1 1 2 1 2 1 3 3 4 4 1 1 3 3 1 3 1 1 3 4 1 3 3 1 1 1 2 1 2 2 2 2 2 2 2 2
 [336] 2 2 4 2 5 1 4 1 2 2 6 1 3 5 1 2 1 2 2 5 2 2 1 3 1 1 2 1 3 2 1 2 2 4 6 2 2 1 1 1 1 2 1 2 1 2 1 1 4 2 4 4 2 4 1 3 1 5 2 1 1 2 1 3 6 2 3
 [403] 2 2 1 1 1 3 4 1 1 6 1 1 2 1 3 1 2 1 1 5 3 3 4 1 1 2 2 2 1 4 1 4 4 1 3 1 2 1 1 2 5 3 1 1 1 1 1 5 2 1 1 3 6 1 3 1 1 2 4 1 3 1 2 2 4 2 6
 [470] 1 1 4 1 1 5 2 3 1 2 3 4 2 3 1 1 1 2 1 2 3 2 1 2 2 4 2 3 3 4 2 4 2 3 1 1 1 2 3 2 1 4 1 1 1 2 2 1 2 4 1 5 1 1 1 3 6 5 1 2 5 4 2 3 2 1 2
 [537] 1 5 1 4 2 2 1 1 3 1 3 2 2 5 1 3 1 1 3 1 1 1 1 2 2 2 2 2 2 3 2 2 2 1 2 2 1 2 1 1 1 2 3 1 1 1 5 3 1 3 2 3 2 3 2 1 2 1 3 2 1 1 2 1 2 4 3
 [604] 1 3 1 1 1 3 5 4 2 3 1 1 2 1 3 4 4 5 2 2 2 2 1 1 4 3 2 4 2 1 5 3 2 1 1 1 2 3 2 1 4 3 3 3 6 6 3 1 2 2 1 2 1 2 1 5 4 1 1 1 2 1 6 3 4 1 3
 [671] 1 1 2 2 5 1 6 4 4 2 2 1 4 3 1 1 6 5 2 1 1 3 2 2 2 4 1 1 3 5 1 2 2 1 2 1 2 1 2 2 2 1 2 1 2 4 2 2 1 1 2 1 2 2 2 4 1 2 3 1 5 3 1 1 2 2 2
 [738] 4 2 4 1 4 3 2 1 2 2 5 1 1 2 1 5 1 6 2 1 2 1 3 4 1 1 2 4 3 3 1 4 1 4 2 2 2 1 6 4 1 2 2 1 3 1 2 3 1 3 1 2 2 4 4 5 1 1 1 1 2 3 5 2 2 3 1
 [805] 1 1 1 1 1 5 5 1 4 2 5 1 3 4 1 2 2 5 3 2 1 1 5 4 4 2 3 3 5 3 6 1 4 1 1 3 1 3 1 2 1 4 2 4 2 1 1 2 2 1 1 2 1 2 2 2 5 1 2 3 2 3 2 4 2 2 3
 [872] 2 2 2 3 2 2 1 2 1 4 3 1 1 1 1 6 1 2 3 2 1 3 1 1 2 4 1 2 4 1 5 1 2 1 1 2 3 4 3 3 4 2 1 1 2 2 3 6 3 1 3 3 3 2 2 2 2 2 3 2 3 3 1 1 2 5 1
 [939] 2 1 1 2 2 4 2 6 2 2 4 2 2 2 1 1 2 2 4 2 2 2 2 1 5 1 2 2 2 5 1 2 2 2 4 2 2 5 2 1 3 5 4 5 1 1 3 3 1 2 1 2 2 1 5 2 1 2 4 2 2 3
 [ reached getOption("max.print") -- omitted 1236 entries ]
bfi[ , 2] # matrtix notation: all rows of the second column
   [1] 6 3 4 5 5 6 5 6 4 5 5 5 5 3 6 4 5 5 5 6 6 6 5 6 5 6 6 5 6 3 6 4 4 4 6 3 3 4 5 6 5 3 3 6 5 4 5 5 5 2 5 5 6 6 6 4 5 6 6 5 5 4 6 6 3 1 4
  [68] 3 6 4 5 4 6 6 6 6 6 6 6 6 2 5 2 5 5 6 5 5 5 4 5 5 5 5 4 5 4 6 6 6 6 3 4 5 6 4 5 6 6 6 5 5 6 5 4 6 5 6 5 4 4 6 6 5 6 4 4 5 4 4 5 6 2 6
 [135] 5 3 4 3 5 2 4 6 5 2 4 6 3 6 3 4 5 5 5 3 5 5 3 5 4 6 4 5 3 5 5 5 6 5 5 6 4 4 5 6 5 6 4 5 5 6 3 5 3 5 5 5 1 5 5 4 6 6 6 4 5 4 6 6 1 5 4
 [202] 5 6 5 5 5 4 5 5 4 6 6 4 6 2 5 4 5 5 6 6 5 5 6 5 5 4 5 5 6 5 5 2 6 4 6 5 6 5 4 5 5 6 2 6 2 4 3 6 5 2 6 4 4 5 6 5 5 4 6 4 5 4 5 5 5 6 5
 [269] 5 3 5 3 4 6 5 6 5 6 6 6 6 4 5 6 5 5 6 5 4 3 6 4 6 6 5 5 2 5 6 6 6 5 5 6 5 4 5 5 3 4 5 4 4 6 6 6 2 5 6 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5
 [336] 5 5 5 6 4 4 4 6 6 5 1 6 6 6 6 5 6 5 2 4 5 5 5 6 5 5 5 5 5 6 6 2 4 2 5 6 5 6 6 6 3 6 5 5 4 6 5 6 5 5 3 4 6 5 5 6 6 6 4 6 6 4 5 5 1 5 2
 [403] 4 4 6 5 6 5 6 4 6 6 6 6 4 5 4 4 5 5 5 4 5 4 5 6 6 4 4 5 6 3 6 5 5 6 6 5 5 4 6 5 5 6 5 1 6 6 5 4 5 5 6 5 6 6 6 6 5 6 5 4 6 5 5 5 5 6 2
 [470] 5 6 6 5 6 6 6 6 6 5 4 6 6 4 6 5 6 5 6 6 4 5 6 5 6 6 5 5 5 4 6 3 6 6 3 6 5 5 5 5 5 6 6 4 6 4 5 5 4 4 5 6 6 5 6 6 1 5 6 5 5 6 5 4 6 5 6
 [537] 6 5 5 5 6 5 6 6 6 6 4 4 6 2 6 5 6 5 4 6 6 5 6 3 4 5 5 6 4 1 4 5 6 6 5 6 6 5 6 5 3 6 6 1 6 5 4 5 6 4 4 4 5 5 5 5 6 5 6 5 6 6 5 5 6 5 4
 [604] 5 3 6 5 5 4 6 3 5 3 5 5 5 6 5 6 3 2 5 5 6 5 6 6 4 5 6 5 5 6 5 5 5 5 6 5 4 5 6 6 6 5 5 4 3 2 5 6 5 5 5 5 6 5 6 5 6 4 4 4 6 6 6 5 6 5 5
 [671] 2 6 4 4 4 5 6 6 3 5 5 6 3 4 6 5 6 4 6 6 4 5 6 3 6 5 6 3 5 6 6 3 5 5 4 4 5 4 4 5 5 6 3 5 5 4 5 4 4 6 2 5 5 5 2 4 5 6 4 6 5 4 5 4 6 4 6
 [738] 4 5 5 5 4 5 5 6 6 6 5 6 6 5 5 5 5 6 4 5 5 5 5 6 6 5 3 4 6 5 4 2 6 6 4 5 5 5 5 4 6 4 5 6 5 6 5 6 5 5 5 4 6 6 6 5 6 5 5 6 3 5 5 5 5 5 4
 [805] 5 6 5 6 5 6 3 5 5 6 5 6 4 5 6 5 5 2 5 4 6 6 6 4 4 4 5 4 4 4 1 6 5 5 6 5 6 3 6 5 6 4 5 4 3 6 5 5 6 5 5 3 6 3 4 6 5 6 5 5 4 4 4 2 5 4 5
 [872] 2 4 4 6 5 5 6 5 6 5 4 4 6 6 6 5 5 6 6 5 5 4 6 6 5 5 3 6 3 4 4 1 5 6 4 5 4 5 4 5 5 6 5 5 5 6 6 4 4 5 2 2 3 5 5 5 6 6 3 4 4 4 5 5 5 4 4
 [939] 3 6 6 5 4 2 5 5 5 5 2 5 5 5 6 6 6 5 5 6 5 6 5 6 5 6 6 5 6 5 6 6 4 4 5 5 4 4 4 6 3 5 4 5 5 6 5 6 6 5 5 5 4 5 4 4 5 6 6 5 6 5
 [ reached getOption("max.print") -- omitted 1236 entries ]

 

Task 4.2

Run a Spearman correlation test, correlating these two columns, and store its output in an object called test.

Hint The cor.test() function takes a method= argument.

Solution

test <- cor.test(bfi[[1]], bfi[[2]], method = "spearman", exact = F)
The function is telling us that, because there are tied ranks in the data, it cannot compute exact p-values and the values it gives us are computed via the asymptotic t approximation. This is not a cause for concern, it’s simply a message. To get rid of the message, we can explicitly ask for approximate p-values using the exact=FALSE argument.

 

Task 4.3

Now, write two lines of code: one that gets the value of rho out of test and one that gets the p-value. Save the rho value in the second row of the first column of cor_mat and the p-value in the first row of its second column. WHile you’re at it, make the code round the values to 3 dp.

Hint Again, this is just matrix subsetting and assignment.

Solution

cor_mat[2, 1] <- round(test$estimate, 3)
cor_mat[1, 2] <- round(test$p.value, 3)
cor_mat
        [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]     NA    0   NA   NA   NA   NA   NA   NA   NA    NA
 [2,] -0.375   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [3,]     NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [4,]     NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [5,]     NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [6,]     NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [7,]     NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [8,]     NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
 [9,]     NA   NA   NA   NA   NA   NA   NA   NA   NA    NA
[10,]     NA   NA   NA   NA   NA   NA   NA   NA   NA    NA

 

Notice that in all our subsetting, we only used the numbers 1 and 2. These correspond to both the columns in the dataset we are correlating as well as positions in the correlation matrix in which we are storing the extracted values. If we wanted to correlate the first and third columns of bfi, we would store the rho in cor_mat[3, 1] and the p-value in cor_mat[1, 3].

 

Unfortunately, the cor.test() function can only test a single correlation so we need to populate our matrix one test at a time.

 

Task 5

OK, let’s populate cor_mat!

 

Task 5.1

Using the code above, write a for loop that iterates over each column of bfi and correlates if with the 1st column of bfi, each time saving the test object into test and populating the appropriate cell of the cor_mat matrix. Use i as the iterator variable.

The result of the loop should be this partially filled matrix:

        [,1] [,2] [,3] [,4] [,5]  [,6]  [,7] [,8] [,9] [,10]
 [1,]  0.000    0    0    0    0 0.219 0.004    0    0     0
 [2,] -0.375   NA   NA   NA   NA    NA    NA   NA   NA    NA
 [3,] -0.301   NA   NA   NA   NA    NA    NA   NA   NA    NA
 [4,] -0.166   NA   NA   NA   NA    NA    NA   NA   NA    NA
 [5,] -0.230   NA   NA   NA   NA    NA    NA   NA   NA    NA
 [6,] -0.026   NA   NA   NA   NA    NA    NA   NA   NA    NA
 [7,]  0.061   NA   NA   NA   NA    NA    NA   NA   NA    NA
 [8,] -0.096   NA   NA   NA   NA    NA    NA   NA   NA    NA
 [9,] -0.100   NA   NA   NA   NA    NA    NA   NA   NA    NA
[10,]  0.126   NA   NA   NA   NA    NA    NA   NA   NA    NA
Hint Apart from being the iterator variable, i can also be used to subset bfi and the rows/columns of cor_mat.

Solution

# let's start with a fresh cor_mat
cor_mat <- matrix(NA, nrow = 10, ncol = 10)

# i might equally well iterate over:
# 1:10
# 1:ncol(bfi)
for (i in seq_along(bfi)) {
  test <- cor.test(bfi[[i]], bfi[[1]], method = "spearman", exact = F)
  cor_mat[i, 1] <- round(test$estimate, 3)
  cor_mat[1, i] <- round(test$p.value, 3)
}

 

If you look in your GLobal Environment pane, you’ll see that the i variable got created and, because the loop is not completed, it contains the number 10 (10L means 10 as integer). Let’s make use of this variable.

 

Task 5.2

Edit the loop you just created so that it now uses j as the iterator variable and correlates ith and jth columns of bfi, storing the results into appropriate cells of cor_mat again. Starting with an empty matrix, this is what we are after:

       [,1]   [,2]   [,3]  [,4]   [,5]   [,6]  [,7]  [,8]   [,9] [,10]
 [1,]    NA     NA     NA    NA     NA     NA    NA    NA     NA 0.000
 [2,]    NA     NA     NA    NA     NA     NA    NA    NA     NA 0.000
 [3,]    NA     NA     NA    NA     NA     NA    NA    NA     NA 0.000
 [4,]    NA     NA     NA    NA     NA     NA    NA    NA     NA 0.083
 [5,]    NA     NA     NA    NA     NA     NA    NA    NA     NA 0.003
 [6,]    NA     NA     NA    NA     NA     NA    NA    NA     NA 0.000
 [7,]    NA     NA     NA    NA     NA     NA    NA    NA     NA 0.000
 [8,]    NA     NA     NA    NA     NA     NA    NA    NA     NA 0.000
 [9,]    NA     NA     NA    NA     NA     NA    NA    NA     NA 0.000
[10,] 0.126 -0.103 -0.075 0.037 -0.063 -0.304 0.355 -0.37 -0.242 0.000
Hint cor_mat[i, j] should contain the rho, while cor_mat[j, i] should contain the p=value.

Solution

cor_mat <- matrix(NA, nrow = 10, ncol = 10)

# remember, i is still 10 thanks to the loop we ran earlier
for (j in seq_along(bfi)) {
  test <- cor.test(bfi[[i]], bfi[[j]], method = "spearman", exact = F)
  cor_mat[i, j] <- round(test$estimate, 3)
  cor_mat[j, i] <- round(test$p.value, 3)
}

 

Task 5.3

Now, combine the two loops using nesting. The outer loop should use i and the inner one j as iterator variables. This way, for each value of i, there will be 10 cycles of the j loop. The code inside the inner loop can stay the same while the outer loop does not need any code of its own.

Hint Nesting loops, just like if statements is perfectly kosher:

for (i in some_vector) {
  for (j in same_or_another_vector) {
    some.code
  }
}

Solution

cor_mat <- matrix(NA, nrow = 10, ncol = 10)

for (i in seq_along(bfi)) {
  for (j in seq_along(bfi)) {
    test <- cor.test(bfi[[i]], bfi[[j]], method = "spearman", exact = F)
    cor_mat[i, j] <- round(test$estimate, 3)
    cor_mat[j, i] <- round(test$p.value, 3)
  }
}

cor_mat
        [,1]   [,2]   [,3]   [,4]   [,5]   [,6]   [,7]   [,8]   [,9] [,10]
 [1,]  0.000  0.000  0.000  0.000  0.000  0.219  0.004  0.000  0.000 0.000
 [2,] -0.375  0.000  0.000  0.000  0.000  0.000  0.862  0.000  0.000 0.000
 [3,] -0.301  0.510  0.000  0.000  0.000  0.000  0.625  0.000  0.020 0.000
 [4,] -0.166  0.348  0.378  0.000  0.000  0.024  0.043  0.048  0.014 0.083
 [5,] -0.230  0.406  0.530  0.323  0.000  0.000  0.406  0.000  0.361 0.003
 [6,] -0.026  0.127  0.165  0.048  0.164  0.000  0.000  0.000  0.000 0.000
 [7,]  0.061  0.004 -0.010  0.043 -0.018 -0.264  0.000  0.000  0.000 0.000
 [8,] -0.096  0.156  0.231  0.042  0.230  0.412 -0.324  0.000  0.000 0.000
 [9,] -0.100  0.076  0.049 -0.052  0.019  0.240 -0.123  0.227  0.000 0.000
[10,]  0.126 -0.103 -0.075  0.037 -0.063 -0.304  0.355 -0.370 -0.242 0.000

 

As you can see, the diagonal of the matrix contains 0s. This is because when i and j are equal, the code first populates the corresponding cell of cor_mat with the rho and then overwrites it with the p-value.

 

Task 5.4

Include a conditional statement inside your loop that tells R to only evaluate the code if i and j are not equal. That way, the diagonal cell will not get populated at all.

Solution

cor_mat <- matrix(NA, nrow = 10, ncol = 10)

for (i in seq_along(bfi)) {
  for (j in seq_along(bfi)) {
    if (i != j) {
      test <- cor.test(bfi[[i]], bfi[[j]], method = "spearman", exact = F)
      cor_mat[i, j] <- round(test$estimate, 3)
      cor_mat[j, i] <- round(test$p.value, 3)
    }
  }
}

cor_mat
        [,1]   [,2]   [,3]   [,4]   [,5]   [,6]   [,7]   [,8]   [,9] [,10]
 [1,]     NA  0.000  0.000  0.000  0.000  0.219  0.004  0.000  0.000 0.000
 [2,] -0.375     NA  0.000  0.000  0.000  0.000  0.862  0.000  0.000 0.000
 [3,] -0.301  0.510     NA  0.000  0.000  0.000  0.625  0.000  0.020 0.000
 [4,] -0.166  0.348  0.378     NA  0.000  0.024  0.043  0.048  0.014 0.083
 [5,] -0.230  0.406  0.530  0.323     NA  0.000  0.406  0.000  0.361 0.003
 [6,] -0.026  0.127  0.165  0.048  0.164     NA  0.000  0.000  0.000 0.000
 [7,]  0.061  0.004 -0.010  0.043 -0.018 -0.264     NA  0.000  0.000 0.000
 [8,] -0.096  0.156  0.231  0.042  0.230  0.412 -0.324     NA  0.000 0.000
 [9,] -0.100  0.076  0.049 -0.052  0.019  0.240 -0.123  0.227     NA 0.000
[10,]  0.126 -0.103 -0.075  0.037 -0.063 -0.304  0.355 -0.370 -0.242    NA

 

Task 5.5

Finally add a condition that populates the p-value cell with a character string "<.001", if the p-value, rounded to 3 dp, is zero. For this, you may need an intermediate step, first saving round(test$p.value, 3) into some object, e.g., pval, and then populating the given cell of cor_mat with either its value or "<.001" based on whether or not it’s zero.

Solution

cor_mat <- matrix(NA, nrow = 10, ncol = 10)

for (i in seq_along(bfi)) {
  for (j in seq_along(bfi)) {
    if (i != j) {
      test <- cor.test(bfi[[i]], bfi[[j]], method = "spearman", exact = F)
      pval <- round(test$p.value, 3)
      cor_mat[i, j] <- round(test$estimate, 3)
      cor_mat[j, i] <- ifelse(pval, pval, "<.001")
    }
  }
}

cor_mat
      [,1]     [,2]     [,3]     [,4]     [,5]     [,6]     [,7]     [,8]    [,9]     [,10]  
 [1,] NA       "<.001"  "<.001"  "<.001"  "<.001"  "0.219"  "0.004"  "<.001" "<.001"  "<.001"
 [2,] "-0.375" NA       "<.001"  "<.001"  "<.001"  "<.001"  "0.862"  "<.001" "<.001"  "<.001"
 [3,] "-0.301" "0.51"   NA       "<.001"  "<.001"  "<.001"  "0.625"  "<.001" "0.02"   "<.001"
 [4,] "-0.166" "0.348"  "0.378"  NA       "<.001"  "0.024"  "0.043"  "0.048" "0.014"  "0.083"
 [5,] "-0.23"  "0.406"  "0.53"   "0.323"  NA       "<.001"  "0.406"  "<.001" "0.361"  "0.003"
 [6,] "-0.026" "0.127"  "0.165"  "0.048"  "0.164"  NA       "<.001"  "<.001" "<.001"  "<.001"
 [7,] "0.061"  "0.004"  "-0.01"  "0.043"  "-0.018" "-0.264" NA       "<.001" "<.001"  "<.001"
 [8,] "-0.096" "0.156"  "0.231"  "0.042"  "0.23"   "0.412"  "-0.324" NA      "<.001"  "<.001"
 [9,] "-0.1"   "0.076"  "0.049"  "-0.052" "0.019"  "0.24"   "-0.123" "0.227" NA       "<.001"
[10,] "0.126"  "-0.103" "-0.075" "0.037"  "-0.063" "-0.304" "0.355"  "-0.37" "-0.242" NA     

 

And there’s our correlation table. You will have probably noticed that this is now a character matrix (hence the quotes). This conversion happened because we entered "<.001" in some of the cells. Since, as you will recall, matrices can only contain elements of the same class, combining character strings with numeric elements will result in the entire matrix being coerced into character. It looks a little odd printed out like this but, since this is the kind of matrix we might be exporting to a paper and not one we would want to use for any further calculations, it does not matter.

 

You might have also spotted the fact that the cells of our matrix get populated exactly twice (for instance when i = 2 and j = 5 and when it’s the other way around). This means that we are running twice as many iterations that we necessarily need. Here is what the process looks like: