-1

given a list of (e.g.) integers, I would like to sample n elements without replacement, remove the sampled items from the original list and repeat this process until now elements in the original list remains. Returning a list of round(len(list)/n).

I know about random.sample(), however I didnt find a implementation for repeated sampling without replacement. My pseudo code below is missing the removement of the sampled elements from the original list. However while I am writing this function I am wondering if there isnt something like this already implemented or a more elegant solution to this?

Pseudo-Code

def repeated_sample_without_replacement(my_list, n):
    # where n = number of samples,
    k = int(len(my_list) / n)
    if len(my_list)%n != 0:
        samples = np.repeat(n,k)
        samples = np.append(samples, len(my_list) % n)
    else:
        samples = np.repeat(n,k)
    k = len(my_list) / n
    out = []
    for s in samples:
        out.append(random.sample(my_list, s))
        # remove the now sample elements from my_list
    
    return out

x = repeated_sample_without_replacement(ids,10)
print(x)

Example Data

# Sample Data
ids_clean = [*range(1,40)]
In[71]: # Remove Some ID to Better Represent my Purpose
ids = ids_clean[:12] + ids_clean[13:26] + ids_clean[27:]
ids
Out[73]: 
[1,
 2,
 3,
 4,
 5,
 6,
 7,
 8,
 9,
 10,
 11,
 12,
 14,
 15,
 16,
 17,
 18,
 19,
 20,
 21,
 22,
 23,
 24,
 25,
 26,
 28,
 29,
 30,
 31,
 32,
 33,
 34,
 35,
 36,
 37,
 38,
 39]
len(ids)
Out[74]: 37

Desired Output

[[1,4,5,6..],[2,8,9,...],[13,15,16,...][27,10,..]]
Björn
  • 1,610
  • 2
  • 17
  • 37
  • Python is so close to pseudocode that the pseudocode you wrote there is actually valid python ;) –  Nov 17 '20 at 17:26
  • Initially I wanted to write pseudo :D however I switch to python as what I wrote was already pretty close to it – Björn Nov 17 '20 at 17:34
  • Btw. It is not a duplicate. The linked answer is 7 years ago and not easily adopted in Pythom 3. I Tried, and way to complicated if you compare to the correctly provided answere here – Björn Nov 17 '20 at 17:39
  • Hmm, what do you mean with "not easily adopted in Pythom 3"? – superb rain Nov 17 '20 at 18:07
  • @BjörnB It's not an *exact* duplicate, but [Tim Peter's answer](https://stackoverflow.com/a/18921596/984421) essentially gives the same solution as you got here. The main difference is in how to split the randomised list into `n` chunks, which is dealt with in [this question](https://stackoverflow.com/q/24483182/984421). – ekhumoro Nov 17 '20 at 18:38
  • @superbrain The answer provided in the alleged duplicate (as well as many others) are working with a generator (`yield`). Their usage example `gen.next()` gives me the error `AttributeError: 'generator' object has no attribute 'next'` beyond the typical py2 py3 shaningans (like `print "abc"` need to be `print("abc")`). I just found out about the dunder method `.__next()__` or `next(gen)`. However I don't think it hurts that there is a shorter and better python 3 solution visible in this thread. – Björn Nov 18 '20 at 08:30

1 Answers1

4

Your code shows that you're overall trying to sample the entire given list. So just random.shuffle it once and then split it into chunks. Or even just slices with step n, which makes it easier:

from random import shuffle

def repeated_sample_without_replacement(my_list, n):
    shuffle(my_list)
    return [my_list[i::n] for i in range(n)]

Demo:

>>> repeated_sample_without_replacement(list(range(10)), 3)
[[7, 5, 0, 1], [2, 6, 8], [4, 3, 9]]

Note that this actually produces exactly n samples. Not more or less like yours.

Demo of yours:

>>> repeated_sample_without_replacement(list(range(10)), 3)
[[3, 0, 2], [5, 4, 6], [6, 1, 7], [3]]
>>> repeated_sample_without_replacement(list(range(10)), 13)
[[1, 0, 3, 7, 8, 2, 5, 4, 9, 6]]
superb rain
  • 5,300
  • 2
  • 11
  • 25