Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating multiple pairs in R

Tags:

random

r

match

I have a list of people:

people<-c("Betty", "Joe", "Bob", "Will", "Frank")

I would like to randomly assign two people to each person (self-assignment is not allowed) and I would like each person to be assigned to another an equal amount of times (in the example above each person can only be assigned to another twice).

So for example the match up could be

Betty (Joe and Bob), Joe (Bob and Will), Bob (Will and Frank), Will (Frank and Betty)

Of course I have just used their ordering but it would be nice if this could be randomised.

Any ideas where to start?

like image 946
Elizabeth Avatar asked Jan 20 '26 09:01

Elizabeth


1 Answers

New (easier) solution: Using shift function from TaRifx package from Ari B. Friedman

tt <- sample(people)
lapply(seq_len(length(tt))-1, function(x) shift(tt, x)[1:3])
# if you don't want it to be ordered, just add a sample(.)
lapply(seq_len(length(tt))-1, function(x) sample(shift(tt, x)[1:3]))
# [[1]]
# [1] "Bob"   "Frank" "Betty"
# 
# [[2]]
# [1] "Frank" "Betty" "Joe"  
# 
# [[3]]
# [1] "Betty" "Joe"   "Will" 
# 
# [[4]]
# [1] "Joe"  "Will" "Bob" 
# 
# [[5]]
# [1] "Will"  "Bob"   "Frank"

Old solution (for the idea): I'd go this way. Basically, once you sample "people", you can always go, 1,2,3, 2,3,4, 3,4,5, 4,5,1. So, let's do that. That is, generate these indices and then sample people and get the triplets.

# generate index
len <- length(people)
choose <- 3 # at a time 
idx <- outer(seq(choose), seq(choose+2)-1, '+')
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    1    2    3    4    5
# [2,]    2    3    4    5    6
# [3,]    3    4    5    6    7

# sample people
tt <- sample(people)
# [1] "Joe"   "Will"  "Bob"   "Frank" "Betty"
max.idx <- 2*choose + 1
tt[(len+1):max.idx] <- tt[seq(max.idx-len)]
# [1] "Joe"   "Will"  "Bob"   "Frank" "Betty" "Joe"   "Will" 

tt[idx]
#  [1] "Joe"   "Will"  "Bob"   "Will"  "Bob"   "Frank" "Bob"   "Frank" "Betty" "Frank" 
#  [15] "Betty" "Joe"  "Betty" "Joe"   "Will" 

split(tt[idx], gl(ncol(idx), nrow(idx)))
# $`1`
# [1] "Joe"  "Will" "Bob" 
# 
# $`2`
# [1] "Will"  "Bob"   "Frank"
# 
# $`3`
# [1] "Bob"   "Frank" "Betty"
# 
# $`4`
# [1] "Frank" "Betty" "Joe"  
# 
# $`5`
# [1] "Betty" "Joe"   "Will" 

Now we can put this all in a function:

my_sampler <- function(x, choose) {
    len <- length(x)
    idx <- outer(seq(choose), seq(choose+2)-1, '+')
    sx  <- sample(x)
    max.idx <- 2*choose + 1
    sx[(len+1):max.idx] <- sx[seq(max.idx-len)]
    split(sx[idx], gl(ncol(idx), nrow(idx)))
}
# try it out
my_sampler(people, 3)
my_sampler(people, 4) # 4 at a time

# if you want this and want a non-ordered solution, wrap this with `lapply` and `sample`

lapply(my_sampler(people, 3), sample)
like image 121
Arun Avatar answered Jan 22 '26 02:01

Arun



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!