Random sampling for a list of tuples

Viewed 227

I have a list of 220 tuples created by "12 combination of 3". Is there a way in Python to sample from this list of tuples such that every sample I select comprises all the 12 elements in the set?

For example, if the set is [a,b,c,d,e,f,g,h,i,j,k,l], the random selection should look like [(a,b,c), (d,e,f), (g,h,i), (j,k,l)]. I tried the following

for y in range(4): 
 for x in range(2):
        print(random.sample(list, 4))

but many samples do not have all the elements of the mother set.

3 Answers

How about shuffling the original set/list and then take 3-tuples from that shuffled list?

import random

lst = range(12) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

lst_shuffle = random.sample(lst, k=len(lst)) # shuffle the list
smp = [tuple(lst_shuffle[i:i+3]) for i in range(0, len(lst_shuffle), 3)] # make chunks
print(smp) # e.g., [(0, 2, 10), (3, 5, 4), (11, 7, 8), (1, 9, 6)]

I believe this is more memory-efficient while probabilistically equivalent.

You can use random.shuffle then use zip and tuple and get what you want:

>>> import random
>>> random.seed(123)
>>> lst = list(range(12))
>>> random.shuffle(lst)
>>> lst
[7, 5, 9, 2, 3, 8, 11, 10, 6, 1, 4, 0]

>>> tuple(zip(lst[::3], lst[1::3], lst[2::3]))
((7, 5, 9), (2, 3, 8), (11, 10, 6), (1, 4, 0))

Although the time complexity is huge, with a small set of 12 items, I can safely guarantee that the code would run in less than a second or two.

In return, this code can provide you pure and unbiased random, and you can generate as many samples as you wish. The more samples you generate and the fewer items the original set has, the less time it would likely take your code to run.

def generate(n, lst):
    if n < len(lst) // 3:
        print(f'"It is impossible to generate {n} samples."')
    else:
        while True:
            stack = None

            for _ in range(n):
                tup = np.random.choice(lst, size=3, replace=False)

                if stack is None:
                    stack = tup
                else:
                    stack = np.vstack((stack, tup))

            if len(np.unique(stack.flatten())) == len(lst):
                return list(tuple(i) for i in stack)

Basically, it generates n samples until the samples meet the condition.


Results

Generating six samples with the code above gives the result.

>>> lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> generate(6, lst)

[(5, 0, 2), (8, 1, 4), (0, 4, 7), (10, 7, 2), (9, 11, 2), (3, 6, 1)]

Generating four samples gives the following result.

>>> lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> generate(4, lst)

[(7, 10, 11), (0, 4, 3), (1, 8, 5), (2, 9, 6)]

It is impossible to satisfy the condition with three samples.

>>> lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> generate(3, lst)

"It is impossible to generate 3 samples."
Related