【问题标题】:Return random sub-sub-list and its indexes from list从列表中返回随机子子列表及其索引
【发布时间】:2014-01-20 14:13:07
【问题描述】:

我有一个具有以下排列的列表:N 子列表的数量和 N_i 每个子列表中的子列表数量,其中 N_i 在整个子列表中不一定相等.每个子子列表包含两个元素(对于所有子子列表都是如此)。这是具有 3 个子列表和 4、3、5 和 1 个子子列表的此类列表的简短版本:

a = [[[0.3, 1.2], [0.3, 2.3], [0.3, 4.6], [0.3, 3.4]], [[0.6, 4.5], [0.6, 2.5], [0.6, 7.8]], [[0.2, 1.4], [0.2, 6.3], [0.2, 5.2], [0.2, 2.1], [0.2, 3.6]], [[0.4, 1.3]]]

我需要一种方法来从所有可用的子列表中选择一个随机子列表并存储指向它的索引。

我可以使用random.choice 并这样做:

import random.choice as r_c
s_s_list = r_c(r_c(a))
print s_s_list
[0.6, 7.8]

这有效地从所有可用的子列表中返回一个随机子列表,但它有以下问题:

a- 它没有给我指向它的i,j 索引(在这种情况下:[1, 2]),我不能直接使用a.index(s_s_list),因为它是一个 sub-sub-列出

b- 因为我需要重复这个过程M 次来获得M 随机 distinct 子子列表(以及指向它们的索引),所以这不起作用。

c- 正如 cmets 中所指出的那样,这使得被选择到具有较少元素的子列表中的那些子子列表的概率更高,我需要以相同的概率选择每个子子列表.

【问题讨论】:

  • 你为什么不使用random.choiceenumerate结合?
  • 你事先知道每个子列表的大小吗?
  • 既然我们正在修复您的问题表述:所有子列表是否应该具有相同的被选择概率,或者您应该首先在列表中平等选择?例如,在[ range(10, 1000), range(1, 2) ] 的第二种情况下,您有 50% 的机会选择 2
  • 请再次查看我更新的问题,您和 arshajii 指出这一点是正确的。

标签: python list random


【解决方案1】:

要跟踪索引,您可以 (a) 随机选择索引,并使用它们检索子子列表;或 (b) 使用 enumerate 将索引放入您的列表中。

由于您希望在不替换的情况下进行抽样(即M distinct 子子列表),请使用random.sample 而不是M 调用random.choice。要以相等的概率在子列表中进行选择,您必须首先“展平”列表。在添加索引的同时很容易做到这一点。

下面是使用enumerate的方法:

a_flat = [(i, j, item) for i, sublst in enumerate(a) for j, item in enumerate(sublst)]
choices = random.sample(a_flat, 3)

for c in choices:
    print c

(2, 3, [0.2, 2.1])
(3, 0, [0.4, 1.3])
(1, 0, [0.6, 4.5])

【讨论】:

  • 您提出了一个非常重要的观点,我在最初的问题中忘记提及:M 选择的随机子子列表必须完全不同。抱歉各位,我马上更新问题。
  • 那么您的示例使用了错误的方法,无论索引问题如何。使用random.sample
  • 现在选择不替换,子子列表上的概率一致。
  • 两个都是很好的答案,但我选择这个是因为它还输出元素的值,而不仅仅是索引。谢谢你们!
【解决方案2】:

只需使用random.randint():

i = random.randint(0, len(a) - 1)
j = random.randint(0, len(a[i]) - 1)

例如:

>>> a = [[[0.3, 1.2], [0.3, 2.3], [0.3, 4.6], [0.3, 3.4]], [[0.6, 4.5], [0.6, 2.5], [0.6, 7.8]], [[0.2, 1.4], [0.2, 6.3], [0.2, 5.2], [0.2, 2.1], [0.2, 3.6]], [[0.4, 1.3]]]
>>> 
>>> import random
>>> i = random.randint(0, len(a) - 1)
>>> j = random.randint(0, len(a[i]) - 1)
>>> 
>>> a[i][j]  # <-- this is the actual random element
[0.2, 2.1]

一个重要说明:上面的代码与您的代码在如何选择随机元素方面类似。 然而,并不是所有的子子列表都有相同的机会通过这种方法被选中。例如,考虑:

[[l1, l2, l3, l4, l5, ...], [l0]]

在这种情况下,第一个子列表中的每个子列表被选中的机会很低,因为我们必须首先为i 选择第一个子列表,然后然后选择正确的j 的子列表。相比之下,l0 有 50% 的机会被选中,因为我们所要做的就是为 i 选择第二个子列表,此时唯一的选择是为 j 选择 l0


您的问题编辑会有所改变,因为您确实需要选择 M 唯一 子子列表。现在你可以试试这个,使用random.sample():

>>> from random import sample
>>> 
>>> M = 4
>>> 
>>> random.sample([(i,j) for i in range(len(a)) for j in range(len(a[i]))], M)
[(1, 1), (2, 3), (2, 4), (1, 0)]

在 Python 2.x 中,使用 xrange() 而不是 range()

请注意,使用这种方法,每个子列表确实有相同的机会被选中。

我们在这里所做的实际上是创建一个“索引列表”

[(i,j) for i in range(len(a)) for j in range(len(a[i]))]

其中包含平面列表中每个子列表的索引:

>>> [(i,j) for i in range(len(a)) for j in range(len(a[i]))]
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0)]

然后我们从这个列表中采样,得到想要的结果。

【讨论】:

  • @JoelCornett 为什么重要?我们的j 索引取决于我们使用i 索引选择的子列表的大小(即“len(a[i]) - 1”)。
  • 哦,哇,我肯定没有正确阅读您的代码。触摸。
  • 对不起@arshajii,我忘了在亚历克西斯指出的问题中添加一条非常重要的信息。我已经更新了,给您带来的不便再次抱歉。
  • 嗯,这又是另一个非常重要的一点。我显然没有充分考虑这一点。我会一次又一次地更新问题,对于仓促发布一个半途而废的问题,我深表歉意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多