In 03 - >2 Conditions, we matched three conditions by multiple variables. This might sometimes have unexpected effects, however. To explain why, we need to look at match nulls.

Setup

Load Packages

library(tidyverse)
library(LexOPS)  # package with functions for item-wise matching

Import the Data

stim_pool <- read_csv("stim_pool.csv")

Using the Default Match Null

In 03 - >2 Conditions, we matched three conditions on multiple control variables. Here is a recreation of those stimuli:

stim1 <- stim_pool %>%
  set_options(id_col = "stim_id") %>%
  split_by(age, 1:28 ~ 35:45 ~ 50:100) %>%
  control_for(face_width, -0.5:0.5) %>%
  control_for(face_length, -2:2) %>%
  control_for(task_rt, -25:25) %>%
  control_for(gender) %>%
  generate(n=100, seed=42)
## Generated 5/100 (5%). 9 total iterations, 0.56 success rate.
Generated 10/100 (10%). 15 total iterations, 0.67 success rate.
Generated 15/100 (15%). 21 total iterations, 0.71 success rate.
Generated 20/100 (20%). 26 total iterations, 0.77 success rate.
Generated 25/100 (25%). 36 total iterations, 0.69 success rate.
Generated 30/100 (30%). 44 total iterations, 0.68 success rate.
Generated 35/100 (35%). 51 total iterations, 0.69 success rate.
Generated 40/100 (40%). 68 total iterations, 0.59 success rate.
Generated 45/100 (45%). 74 total iterations, 0.61 success rate.
Generated 50/100 (50%). 83 total iterations, 0.60 success rate.
Generated 55/100 (55%). 92 total iterations, 0.60 success rate.
Generated 60/100 (60%). 98 total iterations, 0.61 success rate.
Generated 65/100 (65%). 105 total iterations, 0.62 success rate.
Generated 70/100 (70%). 116 total iterations, 0.60 success rate.
Generated 75/100 (75%). 122 total iterations, 0.61 success rate.
Generated 80/100 (80%). 133 total iterations, 0.60 success rate.
Generated 85/100 (85%). 143 total iterations, 0.59 success rate.
Generated 90/100 (90%). 149 total iterations, 0.60 success rate.
Generated 95/100 (95%). 159 total iterations, 0.60 success rate.
Generated 100/100 (100%). 169 total iterations, 0.59 success rate.

This gives us the following result - notice the match_null column at the end. Each row has a different match null, one of the three conditions, which dictates which condition the other conditions are matched to. For example, for the first matched row, the conditions A2 and A3 are matched to condition A1.

stim1
## # A tibble: 100 x 5
##    item_nr A1        A2        A3        match_null
##      <int> <chr>     <chr>     <chr>     <chr>     
##  1       1 face_4884 face_1865 face_2334 A1        
##  2       2 face_3851 face_740  face_3854 A3        
##  3       3 face_3301 face_160  face_4826 A2        
##  4       4 face_2181 face_1713 face_2558 A1        
##  5       5 face_3282 face_3330 face_1218 A3        
##  6       6 face_341  face_3098 face_4026 A2        
##  7       7 face_121  face_3052 face_3084 A3        
##  8       8 face_1817 face_720  face_3491 A3        
##  9       9 face_1243 face_4788 face_1334 A1        
## 10      10 face_4854 face_3816 face_2268 A3        
## # ... with 90 more rows

By default, matching will be done in a balanced way, where a match null is pseudo-randomly chosen from the possible conditions, but with equal frequency in the final stimuli. This approach makes a lot of sense, but might give some unexpected results.

As an example, imagine we set a tolerance of -1:1. The match null for a given item is A1, so A2 and A3 will be within ±1 of the item for condition A1. The problem is that A2 could equal A1-1, and A3 could be A1+1. This means that A2 and A3 could have a difference of up to ±2. If you have a tolerance of -1:1, you might want A2 and A3 to also be matched within ±1.

The solution is to set the match null to “inclusive”.

Using Inclusive Match Nulls

If you want each condition to be matched to every other condition within your tolerance, you need to use an inclusive match null. You can do this by setting the match_null argument in generate():

stim2 <- stim_pool %>%
  set_options(id_col = "stim_id") %>%
  split_by(age, 1:28 ~ 35:45 ~ 50:100) %>%
  control_for(face_width, -0.5:0.5) %>%
  control_for(face_length, -2:2) %>%
  control_for(task_rt, -25:25) %>%
  control_for(gender) %>%
  generate(n=100, seed=42, match_null="inclusive")
## Generated 5/100 (5%). 18 total iterations, 0.28 success rate.
Generated 10/100 (10%). 28 total iterations, 0.36 success rate.
Generated 15/100 (15%). 41 total iterations, 0.37 success rate.
Generated 20/100 (20%). 52 total iterations, 0.38 success rate.
Generated 25/100 (25%). 66 total iterations, 0.38 success rate.
Generated 30/100 (30%). 87 total iterations, 0.34 success rate.
Generated 35/100 (35%). 95 total iterations, 0.37 success rate.
Generated 40/100 (40%). 116 total iterations, 0.34 success rate.
Generated 45/100 (45%). 132 total iterations, 0.34 success rate.
Generated 50/100 (50%). 147 total iterations, 0.34 success rate.
Generated 55/100 (55%). 165 total iterations, 0.33 success rate.
Generated 60/100 (60%). 197 total iterations, 0.30 success rate.
Generated 65/100 (65%). 236 total iterations, 0.28 success rate.
Generated 70/100 (70%). 258 total iterations, 0.27 success rate.
Generated 75/100 (75%). 270 total iterations, 0.28 success rate.
Generated 80/100 (80%). 300 total iterations, 0.27 success rate.
Generated 85/100 (85%). 328 total iterations, 0.26 success rate.
Generated 90/100 (90%). 347 total iterations, 0.26 success rate.
Generated 95/100 (95%). 377 total iterations, 0.25 success rate.
Generated 100/100 (100%). 406 total iterations, 0.25 success rate.

This time, the match_null column will all equal NA, because every condition is matched to every other condition.

stim2
## # A tibble: 100 x 5
##    item_nr A1        A2        A3        match_null
##      <int> <chr>     <chr>     <chr>     <chr>     
##  1       1 face_2897 face_4923 face_779  <NA>      
##  2       2 face_337  face_4709 face_2957 <NA>      
##  3       3 face_3946 face_3317 face_637  <NA>      
##  4       4 face_1081 face_1984 face_3014 <NA>      
##  5       5 face_1044 face_4701 face_3354 <NA>      
##  6       6 face_3059 face_2313 face_4200 <NA>      
##  7       7 face_2596 face_4752 face_4156 <NA>      
##  8       8 face_3172 face_1579 face_3653 <NA>      
##  9       9 face_4240 face_3644 face_3247 <NA>      
## 10      10 face_1312 face_1629 face_765  <NA>      
## # ... with 90 more rows

Using Conditions as Match Nulls

On the other hand, you may have a design where you wish to use the same match null for each matched set. For example, you might want to treat faces as a null in your experimental design, and wish for a set of young faces matched to middle-aged faces, and a list of older faces matched to the same items. You can do this by giving a specific condition to the match_null argument of generate():

stim3 <- stim_pool %>%
  set_options(id_col = "stim_id") %>%
  split_by(age, 1:28 ~ 35:45 ~ 50:100) %>%
  control_for(face_width, -0.5:0.5) %>%
  control_for(face_length, -2:2) %>%
  control_for(task_rt, -25:25) %>%
  control_for(gender) %>%
  generate(n=100, seed=42, match_null="A2")
## Generated 5/100 (5%). 10 total iterations, 0.50 success rate.
Generated 10/100 (10%). 16 total iterations, 0.62 success rate.
Generated 15/100 (15%). 25 total iterations, 0.60 success rate.
Generated 20/100 (20%). 34 total iterations, 0.59 success rate.
Generated 25/100 (25%). 44 total iterations, 0.57 success rate.
Generated 30/100 (30%). 53 total iterations, 0.57 success rate.
Generated 35/100 (35%). 58 total iterations, 0.60 success rate.
Generated 40/100 (40%). 66 total iterations, 0.61 success rate.
Generated 45/100 (45%). 73 total iterations, 0.62 success rate.
Generated 50/100 (50%). 82 total iterations, 0.61 success rate.
Generated 55/100 (55%). 87 total iterations, 0.63 success rate.
Generated 60/100 (60%). 101 total iterations, 0.59 success rate.
Generated 65/100 (65%). 110 total iterations, 0.59 success rate.
Generated 70/100 (70%). 127 total iterations, 0.55 success rate.
Generated 75/100 (75%). 135 total iterations, 0.56 success rate.
Generated 80/100 (80%). 145 total iterations, 0.55 success rate.
Generated 85/100 (85%). 155 total iterations, 0.55 success rate.
Generated 90/100 (90%). 166 total iterations, 0.54 success rate.
Generated 95/100 (95%). 171 total iterations, 0.56 success rate.
Generated 100/100 (100%). 180 total iterations, 0.56 success rate.

Now, the match_null column will all equal "A2", because for all sets, conditions A1 and A3 are matched relative to A2.

stim3
## # A tibble: 100 x 5
##    item_nr A1        A2        A3        match_null
##      <int> <chr>     <chr>     <chr>     <chr>     
##  1       1 face_2991 face_2698 face_3974 A2        
##  2       2 face_3779 face_90   face_2811 A2        
##  3       3 face_606  face_1737 face_3467 A2        
##  4       4 face_1460 face_2587 face_2939 A2        
##  5       5 face_2365 face_4296 face_329  A2        
##  6       6 face_1466 face_1101 face_637  A2        
##  7       7 face_4377 face_94   face_4468 A2        
##  8       8 face_2385 face_1727 face_4100 A2        
##  9       9 face_2575 face_3606 face_4879 A2        
## 10      10 face_3024 face_796  face_3247 A2        
## # ... with 90 more rows