如何提取Python列表中一定比例的均匀分布元素?

时间:2015-02-09 10:56:06

标签: python list distribution percentage

我有一个数据点列表。对于我的程序的完整运行,我将使用所有数据点,但是为了测试代码,我想只使用它们中的一小部分,以便程序在短时间内运行。不过,我不想简单地采用列表的前n个元素;我想从列表中选择元素的均匀分布。因此,如果我使用50%的数据点,我可能希望每隔一个数据点从数据点列表中进行选择。

基本上,我想要一个以列表和百分比作为参数的函数,并返回一个由输入列表中的偶数元素分布组成的列表,其数量尽可能接近请求的百分比。

这样做的好方法是什么?

2 个答案:

答案 0 :(得分:4)

为完整起见,请考虑以下事项。

问题可以分为两部分:

  1. 在给定一定百分比或分数的情况下,确定要挑选的元素数量。

  2. 选择列表中应选择的元素。

  3. 第一点是直截了当。如果您希望获得列表的percentage = 35. #%,那么您最好选择round(len(my_list) * (percentage / 100.))个元素。请注意,仅当len(my_list)(percentage / 100.)的倍数时,您才能获得完全正确的百分比。这种不准确性是不可避免的,因为连续测量(百分比)被转换为离散测量(nbr。元素)。

    第二点将取决于您应该返回哪个元素的特殊要求。选择尽可能均匀分布的元素是可行的,但肯定不是最简单的方法。

    以下是您如何在概念上执行此操作(请参阅下面的实现):

    如果您有一个长度l的列表,那么您需要将某个平均分布的分数ff = percentage / 100.)包含在内,您必须将列表中的索引加入到大小为round(l * f)的{​​{1}}个箱子。你想要的是每个箱子中最核心元素的列表。

    为什么这样做?

    对于第一点,请注意,如果我们制作大小为l / round(l * f)的分档,我们最后会得到l / round(l * f)个分箱。哪个是理想的数量(见上文第1点)。如果对于每个这些大小相同的箱子,我们选择最中心的元素,我们得到尽可能均匀分布的元素列表。

    这是一个简单的(既不是速度优化也不是非常漂亮)的实现:

    l / l / round(l * f) = round(l * f)

    我们现在可以将这个理想算法(equal_dist_els)与@jonrsharpe的切片方法进行比较:

    absolute difference as fct of the requested fraction

    请参阅下面的代码。

    沿着x轴是要返回的元素的希望部分,并且在y轴上是所需分数和两种方法返回的分数之间的绝对差。我们看到,对于大约0.7(~70%)的分数,切片方法的偏差是显着的,即如果要求~70%切片方法返回所有元素(100%),这是几乎45%的偏差。 / p>

    总之,我们可以说@jonrsharpe的切片方法适用于小分数(from bisect import bisect_left def equal_dist_els(my_list, fraction): """ Chose a fraction of equally distributed elements. :param my_list: The list to draw from :param fraction: The ideal fraction of elements :return: Elements of the list with the best match """ length = len(my_list) list_indexes = range(length) nbr_bins = int(round(length * fraction)) step = length / float(nbr_bins) # the size of a single bin bins = [step * i for i in xrange(nbr_bins)] # list of bin ends # distribute indexes into the bins splits = [bisect_left(list_indexes, wall) for wall in bins] splits.append(length) # add the end for the last bin # get a list of (start, stop) indexes for each bin bin_limits = [(splits[i], splits[i + 1]) for i in xrange(len(splits) - 1)] out = [] for bin_lim in bin_limits: f, t = bin_lim in_bin = my_list[f:t] # choose the elements in my_list belonging in this bin out.append(in_bin[int(0.5 * len(in_bin))]) # choose the most central element return out )但在选择较大分数时变得越来越不准确。另请注意,不准确性与列表长度无关。实际上,分箱算法实现起来稍微复杂一些,而且很可能也慢得多。然而,它的不准确性只是上面提到的不可避免的不准确性,随着列表长度的增加而减少。

    图表的代码:

    >>0.1

答案 1 :(得分:2)

这可以通过设置带有步骤的切片来实现:

def select_elements(seq, perc):
    """Select a defined percentage of the elements of seq."""
    return seq[::int(100.0/perc)]

使用中:

>>> select_elements(range(10), 50)
[0, 2, 4, 6, 8]
>>> select_elements(range(10), 33)
[0, 3, 6, 9]
>>> select_elements(range(10), 25)
[0, 4, 8]

您还可以添加round,因为int会截断:

>>> int(3.6)
3
>>> int(round(3.6))
4

如果您想使用比例而不是百分比(例如0.5而不是50),只需将100.0替换为1