Python中random.sample和random.shuffle的区别是什么

Python中random.sample和random.shuffle的区别是什么,python,random,Python,Random,我有一个包含1500个元素的列表,我想把这个列表随机分成两个列表。列表a_1将有1300个元素,列表a_2将有200个元素。我的问题是关于用1500个元素将原始列表随机化的最佳方法。当我将列表随机分组后,我可以将一个切片与1300个切片和另一个切片与200个切片进行比较。 一种方法是使用random.shuffle,另一种方法是使用random.sample。两种方法的随机化质量有什么不同吗?列表1中的数据应该是随机样本,也应该是列表2中的数据。 有什么建议吗? 使用随机播放: random.s

我有一个包含1500个元素的列表,我想把这个列表随机分成两个列表。列表a_1将有1300个元素,列表a_2将有200个元素。我的问题是关于用1500个元素将原始列表随机化的最佳方法。当我将列表随机分组后,我可以将一个切片与1300个切片和另一个切片与200个切片进行比较。 一种方法是使用random.shuffle,另一种方法是使用random.sample。两种方法的随机化质量有什么不同吗?列表1中的数据应该是随机样本,也应该是列表2中的数据。 有什么建议吗? 使用随机播放:

random.shuffle(a_tot)    #get a randomized list
a_1 = a_tot[0:1300]     #pick the first 1300
a_2 = a_tot[1300:]      #pick the last 200
使用样本

new_t = random.sample(a_tot,len(a_tot))    #get a randomized list
a_1 = new_t[0:1300]     #pick the first 1300
a_2 = new_t[1300:]      #pick the last 200

我认为它们是完全相同的,除了一个更新了原始列表,一个使用(只读)它。质量无差异。

random.shuffle()
将给定的
列表
洗牌到位。它的长度保持不变


random.sample()
从给定序列中挑选
n
项而不进行替换(也可以是一个元组或任何东西,只要它有一个
\u len\u()
)并以随机顺序返回它们。

这两个选项的随机性应该一样好。我建议使用shuffle,因为读者更清楚它的功能。

shuffle的来源:

def shuffle(self, x, random=None, int=int):
    """x, random=random.random -> shuffle list x in place; return None.

    Optional arg random is a 0-argument function returning a random
    float in [0.0, 1.0); by default, the standard random.random.
    """

    if random is None:
        random = self.random
    for i in reversed(xrange(1, len(x))):
        # pick an element in x[:i+1] with which to exchange x[i]
        j = int(random() * (i+1))
        x[i], x[j] = x[j], x[i]
样本来源:

def sample(self, population, k):
    """Chooses k unique random elements from a population sequence.

    Returns a new list containing elements from the population while
    leaving the original population unchanged.  The resulting list is
    in selection order so that all sub-slices will also be valid random
    samples.  This allows raffle winners (the sample) to be partitioned
    into grand prize and second place winners (the subslices).

    Members of the population need not be hashable or unique.  If the
    population contains repeats, then each occurrence is a possible
    selection in the sample.

    To choose a sample in a range of integers, use xrange as an argument.
    This is especially fast and space efficient for sampling from a
    large population:   sample(xrange(10000000), 60)
    """

    # XXX Although the documentation says `population` is "a sequence",
    # XXX attempts are made to cater to any iterable with a __len__
    # XXX method.  This has had mixed success.  Examples from both
    # XXX sides:  sets work fine, and should become officially supported;
    # XXX dicts are much harder, and have failed in various subtle
    # XXX ways across attempts.  Support for mapping types should probably
    # XXX be dropped (and users should pass mapping.keys() or .values()
    # XXX explicitly).

    # Sampling without replacement entails tracking either potential
    # selections (the pool) in a list or previous selections in a set.

    # When the number of selections is small compared to the
    # population, then tracking selections is efficient, requiring
    # only a small set and an occasional reselection.  For
    # a larger number of selections, the pool tracking method is
    # preferred since the list takes less space than the
    # set and it doesn't suffer from frequent reselections.

    n = len(population)
    if not 0 <= k <= n:
        raise ValueError, "sample larger than population"
    random = self.random
    _int = int
    result = [None] * k
    setsize = 21        # size of a small set minus size of an empty list
    if k > 5:
        setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets
    if n <= setsize or hasattr(population, "keys"):
        # An n-length list is smaller than a k-length set, or this is a
        # mapping type so the other algorithm wouldn't work.
        pool = list(population)
        for i in xrange(k):         # invariant:  non-selected at [0,n-i)
            j = _int(random() * (n-i))
            result[i] = pool[j]
            pool[j] = pool[n-i-1]   # move non-selected item into vacancy
    else:
        try:
            selected = set()
            selected_add = selected.add
            for i in xrange(k):
                j = _int(random() * n)
                while j in selected:
                    j = _int(random() * n)
                selected_add(j)
                result[i] = population[j]
        except (TypeError, KeyError):   # handle (at least) sets
            if isinstance(population, list):
                raise
            return self.sample(tuple(population), k)
    return result
def样本(自身、总体、k):
“”“从总体序列中选择k个唯一的随机元素。”。
返回一个新列表,其中包含填充中的元素,而
保留原始人口不变。结果列表为
以选择顺序排列,以便所有子切片也是有效的随机切片
样本。这允许对抽奖优胜者(样本)进行分区
分为大奖和二等奖(二等奖)。
人口的成员不需要是可散列的或唯一的
总体包含重复,则每次发生都是可能的
在样本中进行选择。
要选择整数范围内的样本,请使用xrange作为参数。
这对于从数据源进行采样尤其快速且节省空间
大群体:样本(X范围(10000000),60)
"""
#尽管文件上说“人口”是“一个序列”,
#XXX试图迎合任何带有_; len的iterable__
#XXX方法。这取得了喜忧参半的成功。两者的例子
#XXX方面:设置工作精细化,并应得到官方支持;
#XXX的口述要难得多,在各种微妙的方面都失败了
#XXX跨越尝试的方式。应该支持映射类型
#删除XXX(用户应传递mapping.keys()或.values())
#XXX明确表示)。
#无需更换的取样需要跟踪两种可能性
#列表中的选项(池)或集合中以前的选项。
#当选择的数量比
#人口,然后跟踪选择是有效的,需要
#只有一小部分和偶尔的重选。对于
#选择的数量越多,池跟踪方法越有效
#首选,因为列表占用的空间比
#设置后,它不会受到频繁重新选择的影响。
n=len(总体)
如果不是0
shuffle更新同一列表中的输出,但sample返回更新
列表示例提供pic facility中的参数编号,但为shuffle
提供相同长度输入的列表


shuffle()和sample()之间有两个主要区别:

1) Shuffle将就地更改数据,因此其输入必须是可变序列。相反,sample生成一个新的列表,其输入可以更加多样化(tuple、string、xrange、bytearray、set等)

2) 示例允许您可能做更少的工作(即部分洗牌)

有趣的是,通过演示在sample()中实现shuffle()是可能的,从而展示两者之间的概念关系:

反之亦然,根据shuffle()实现sample():

这两种方法在真正实现shuffle()和sample()时都没有那么有效,但它确实显示了它们的概念关系。

请注意注释——如果您有一个列表,可以使用shuffle(取决于大小),它可能更有效,因为您不必检查以确保已经选择了特定元素。
from random import shuffle
from random import sample 
x = [[i] for i in range(10)]
shuffle(x)
sample(x,10)
def shuffle(p):
   p[:] = sample(p, len(p))
def sample(p, k):
   p = list(p)
   shuffle(p)
   return p[:k]