sample.py

Go to the documentation of this file.
00001 ##
00002 # 
00003 # This module contains functions to do sampling with and without 
00004 # replacement and random shuffling.  The algorithms are from
00005 # Knuth, vol. 2, section 3.4.2.
00006 # 
00007 # Copyright (C) 2002 GDS Software
00008 # 
00009 # This program is free software; you can redistribute it and/or
00010 # modify it under the terms of the GNU General Public License as
00011 # published by the Free Software Foundation; either version 2 of
00012 # the License, or (at your option) any later version.
00013 # 
00014 # This program is distributed in the hope that it will be useful,
00015 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 # GNU General Public License for more details.
00018 # 
00019 # You should have received a copy of the GNU General Public
00020 # License along with this program; if not, write to the Free
00021 # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00022 # MA  02111-1307  USA
00023 # 
00024 # See http://www.gnu.org/licenses/licenses.html for more details.
00025 # 
00026 
00027 import whrandom
00028 __version__ = "$Id: sample.py,v 1.4 2002/08/21 12:41:49 donp Exp $"
00029 
00030 # Note:  it's important to make the generator global.  If you put it into
00031 # one of the functions and call that function rapidly, the generator will
00032 # be initialized using the clock.  If the calls are fast enough, you'll 
00033 # see distinctly nonrandom behavior.
00034 
00035 rand_num_generatorG = whrandom.whrandom()
00036 
00037 ##
00038 # Sample without replacement from a set of integers from 1 to 
00039 #     population_size.  It returns a tuple of sample_size integers 
00040 #     that were selected.  The sampling distribution is 
00041 #     hypergeometric.
00042 #     
00043 def sample_wor(population_size, sample_size):
00044     assert type(population_size) == type(0) and            type(sample_size) == type(0)     and            population_size > 0              and            sample_size > 0                  and            sample_size <= population_size
00045     global rand_num_generatorG
00046     m = 0  # number of records selected so far
00047     t = 1  # Candidate integer to select if frac is right
00048     list = []
00049     while m < sample_size:    
00050         unif_rand = rand_num_generatorG.random()
00051         frac = 1.0 * (sample_size - m) / (population_size - (t-1))
00052         if unif_rand < frac:
00053             list.append(t)
00054             m = m + 1
00055         t = t + 1
00056     return tuple(list)
00057 
00058 ##
00059 # Sample with replacement from a set of integers from 1 to 
00060 #     population_size.  It returns a tuple of sample_size integers 
00061 #     that were selected.  The sampling distribution is binomial.
00062 #     
00063 def sample_wr(population_size, sample_size):
00064     assert type(population_size) == type(0) and            type(sample_size) == type(0)     and            population_size > 0              and            sample_size > 0
00065     global rand_num_generatorG
00066     list = []
00067     for ix in xrange(sample_size):
00068         list.append(rand_num_generatorG.randint(1, population_size))
00069     return tuple(list)
00070 
00071 ##
00072 # Moses and Oakford algorithm.  See Knuth, vol 2, section 3.4.2.
00073 #     Returns a tuple of a random permutation of the integers from 1 to 
00074 #     sample_size.
00075 #     
00076 def shuffle(sample_size):
00077     assert type(sample_size) == type(0) and sample_size > 0
00078     global rand_num_generatorG
00079     list = range(1, sample_size + 1)
00080     for ix in xrange(sample_size - 1, 0, -1):
00081         rand_int = rand_num_generatorG.randint(0, ix)
00082         if rand_int == ix:
00083             continue
00084         tmp = list[ix]
00085         list[ix] = list[rand_int]
00086         list[rand_int] = tmp
00087     return tuple(list)
00088 
00089 ##
00090 # Returns a tuple of the sequence set that has been randomly
00091 #     shuffled.  Works with lists and tuples.
00092 #     
00093 def shuffle_set(set):
00094     shuffled_set = []
00095     if type(set) != type([]) and type(set) != type(()):
00096         raise "Bad data", "must be list or tuple"
00097     numlist = shuffle(len(set))
00098     for jx in numlist:
00099         ix = jx - 1
00100         shuffled_set.append(set[ix])
00101     return tuple(shuffled_set)
00102 
00103 ##
00104 # Returns a dictionary of dealt hands from the integers 1 to
00105 #     deck_size.  Each dictionary element (indexed by 1, 2, ...,
00106 #     num_hands) is a list of num_per_hand integers.  The element
00107 #     indexed by 0 is the remaining integers that were not selected
00108 #     for one of the hands.
00109 #     
00110 def deal(deck_size, num_hands, num_per_hand):
00111     assert deck_size                             and            deck_size >= num_hands * num_per_hand and            num_hands > 0                         and            type(num_hands) == type(0)            and            num_per_hand > 0                      and            type(num_per_hand) == type(0)
00112     dict = {}
00113     # Generate the integers that will be in the hands
00114     sample = shuffle_set(range(1, deck_size + 1))
00115     for ix in range(num_hands):     # Partition into the dictionary
00116         start = ix * num_per_hand
00117         stop  = start + num_per_hand
00118         dict[ix+1] = sample[start : stop]
00119     dict[0] = sample[stop:]
00120     return dict
00121 
00122 ##
00123 # Returns a dictionary of a dealt card hand.  The deal() function
00124 #     is used, but the routine also maps the integers to a string that
00125 #     contains the card identifications.  For example, 1 -> 2S, 2 -> 3S,
00126 #     ..., 13 -> AS, 14 -> 2C, etc.
00127 #     
00128 def deal_deck(num_hands, num_per_hand):
00129     cards = deal(52, num_hands, num_per_hand)
00130     # Now go through and put identifier on the cards (and change them
00131     # from type integer to type string).
00132     suit_name = "SCHD"             # Spades, clubs, hearts, diamonds
00133     card_name = "A234567890JQK"    # Note 10 will need special handling...
00134     for hand in cards.keys():
00135         new_hand = []
00136         for card_num in cards[hand]:
00137             # We subtract 1 from card_num because cards are numbered 1 to 52
00138             suit_index, card_index = divmod(card_num-1, 13)
00139             #print "suit_index =", suit_index, " card_index =", card_index, " card_num =", card_num
00140             suit = suit_name[suit_index]
00141             card = ("1" * (card_index == 9)) + card_name[card_index]
00142             new_hand.append(card + suit)
00143         cards[hand] = new_hand
00144     return cards
00145 
00146 

© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved; If you reference this document or any part of this document you must use the citation verbatim (including the link) "© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved."

Notice: This source code contained in this document is NOT open source and is NOT being distributed as open source.

122,241 lines of code and growing...