Mathematica Stack Exchange is a question and answer site for users of Mathematica. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Lets say I have 101 instances of data with multiple attributes. In particular case, one attribute has 7 unique values. I want to get 7<=n<=101 element positions from data, in a way that it contains at least 1 of each unique attribute case.

First I get the example data and gather it by particular attribute:

data = Import[""];
g = GatherBy[data, #[[18]] &];

List g of lists with element sizes h

h = Length[#] & /@ g (*{41,13,20,10,8,4,5}*)

Following works in the best case scenario

n = RandomInteger[{Length[g], Length[data]}]
l = RandomSample[RandomSample[#] & /@ IntegerPartitions[n, {Length[g]}], 1][[1]]
s = Table[RandomSample[g[[i]], l[[i]]], {i, 1, Length[g]}]
p = Sort[Position[data, #][[1]][[1]] & /@ #] & /@ s

Example result:


I can bruteforce, but I do not like the idea.

While[MemberQ[Table[h[[i]] >= l[[i]], {i, 1, Length[h]}], False], 
 l = RandomSample[RandomSample[#] & /@ IntegerPartitions[n, {Length[g]}], 1][[1]]]

How do I find random sample l so it is less then gap sizes h?


If n = 7

enter image description here

If n = 21

enter image description here

Problem is that h = {41,13,20,10,8,4,5} and even if n = 11 then l = {1,1,1,1,1,5,1} that is invalid as there are not enough elements in that sublist.

edit 2

f[data_List, n_Integer] := Module[{data1 = data, h, k},
  k = RandomSample[DeleteCases[data1, Alternatives @@
      (h = RandomChoice /@ GatherBy[data1, #[[18]] &])], n - 7];
share|improve this question
Sorry, I'm having trouble understanding this. Could you try again to explain, please? – Mr.Wizard Jan 2 '13 at 15:21
If 'n = 7', i want to take sample positions of 7 unique elements from the data. If n is larger, i want to take more elements. Selection must have 1 element of each attribute 18 category {mammal, fish, bird, ...}(7 in total). – Margus Jan 2 '13 at 15:59
I can't understand your sentence "How do I find random sample l so it is less then gap sizes h?" – Dr. belisarius Jan 2 '13 at 16:20
Why not base the number of elements chosen in a given sublist on the length of that sublist? That way you will never request more than you have. [Note: You really have not stated clearly what is your "randomness" requirement. Thus it is difficult to give a specific answer.] – Daniel Lichtblau Jan 2 '13 at 16:36
up vote 1 down vote accepted

This first chooses one element from each subset, and then takes the rest from the complement using the whole set (discarding those previously taken). It doesn't assume a fixed number of classes, and calculates it from the length of the first choice.

f[data_List, n_Integer] := 
   #~Union~RandomSample[DeleteCases[data, Alternatives @@ #], n - Length@#] &@
                                              (RandomChoice /@ GatherBy[data, #[[18]] &])
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.