【问题标题】:Create a list of random numbers and filter the list to only have numbers larger than 50创建一个随机数列表并过滤列表以仅包含大于 50 的数字
【发布时间】:2020-02-13 05:54:13
【问题描述】:

我正在使用列表推导来创建一个带有 numpy 的随机数列表。有没有办法检查生成的随机数是否大于 50,然后才将其附加到列表中。

我知道我可以简单地使用:

numbers = [np.random.randint(50,100) for x in range(100)]

这将解决问题,但我只想知道是否有可能以某种方式检查 np.random.randint(1,100) 生成的数字是否大于 50

类似

numbers = [np.random.randint(1,100) for x in range(100) if {statement}]

因为比较 np.random.randit 会生成另一个与第一个不同的数字。

我只是想知道是否有可能在将生成的数字添加到列表之前对其进行过滤。

【问题讨论】:

  • 有...但是您必须在嵌套循环中执行此操作,这会很难看,请使用 for 循环。仅供参考[x for x in [randint().. for _ in range(100)] if x > 50]
  • 谢谢,是的,它有点丑,但确实有效。感谢您的回答。
  • 让我知道我的回答有帮助
  • randint(50, 100) 不会生成大于 50 的数字吗?
  • @JonasPalačionis 您想控制在numbers 中获得的值的数量吗? [np.random.randint(50,100) for x in range(100)]np.random.randint(50, 100, 100) 不等同于基于 filter 的解决方案,例如 filter(lambda x: x > 50, np.random.randint(1, 100, 100))[x for x in np.random.randint(1, 100, 100) if x > 50]

标签: python numpy random


【解决方案1】:

您使用 numpy,因此我们可以利用索引方法。

my_array = np.random.randint(1, 100, size=100)
mask = my_array > 50
print(my_array[mask]) # Contain only value greater than 50

当然,做你想做的最好的方法就是这样。

results = np.random.randint(51,100, size=100)
# If you really need a list
results_list = results.tolist()

请不要在一般的 numpy 数组上循环。

编辑:根据@norok2 评论将 my_list 替换为 my_array。

Edit2:速度考虑

麻木

带面具

%%timeit
my_array = np.random.randint(1, 100, size=100)
mask = my_array > 50
my_array[mask]

每个循环 5.31 µs ± 127 ns(7 次运行的平均值 ± 标准偏差,每次 100000 次循环)

10,000,000 个元素:

1 次循环,3 次中的最佳:每个循环 198 毫秒

使用 numpy where (@Severin Pappadeux anwser)

%%timeit
q = np.random.randint(1, 100, 1000)
m = np.where(q > 50)
q[m]

每个循环 20.9 µs ± 663 ns(平均值 ± 标准偏差,7 次运行,每次 10000 次循环)

10,000,000 个元素:

1 次循环,3 次取胜:每个循环 196 毫秒

纯蟒蛇

@Alexander Cécile 回答的一部分

%%timeit
rand_nums = (random.randint(0, 99) for _ in range(10))
arr = [val for val in rand_nums if val > 50]

每个循环 19.4 µs ± 1.99 µs(7 次运行的平均值 ± 标准偏差,每次 10000 个循环)

10,000,000 个元素:

1 次循环,3 次取胜:每个循环 11.4 秒

混合 numpy 和列表​​

@DrBwts 回答

%%timeit
number = [x for x in np.random.randint(1, high=100, size=100) if x > 50]

每个循环 28.9 µs ± 1.52 µs(7 次运行的平均值 ± 标准偏差,每次 10000 个循环)

10,000,000 个元素:

1 个循环,3 次取胜:每个循环 2.76 秒

@makis 回答

%%timeit 
numbers = [x for x in (np.random.randint(1,100) for iter in range(100)) if x > 50]

每个循环 164 µs ± 19.4 µs(7 次运行的平均值 ± 标准偏差,每次 10000 个循环)

10,000,000 个元素:

1 个循环,3 次取胜:每个循环 12.2 秒

@Romero 情人节回答

rand = filter(lambda x: x>50, np.random.randint(1,100,100))
rand_list = list(rand)

每个循环 35.9 µs ± 1.97 µs(7 次运行的平均值 ± 标准偏差,每次 10000 个循环)

10,000,000 个元素:

1 个循环,3 次取胜:每个循环 3.41 秒

结论

  • 对于简单的任务,这些方法都可以。
  • 在大型阵列上,numpy 击败了竞争对手。

提供更多信息的答案

  • @norok2
  • @Alexander Cécile

【讨论】:

  • 所以,已经为您提供了许多 awsers。但是,我仍然坚持这一点,如果您使用 numpy,请尝试使用其内置方法。
  • 顺便说一下,这通常比任何基于理解的解决方案都更快(但不一定更节省内存)。 my_list 的名称也有点误导,因为它实际上是一个 NumPy 数组。
  • @JonasPalačionis 为什么您只想使用列表推导式? FlorianBernard 是对的,在使用 numpy 时,您应该编写惯用的 numpy 代码。这意味着没有显式循环等。
  • 我对时间进行了一点编辑,以创建一个包含 10,000,000 个元素的数组,让我知道您的想法:) 我可能还会添加一些内存基准。
  • 我也是,但它实际上很有意义。事实上,docs for where 提到:“当仅提供条件时,此函数是 np.asarray(condition).nonzero() 的简写。”这里condition 将是arr > 50,这是一个布尔掩码。这归结为,在这种情况下,掩蔽方法和 where 方法实际上是相同的:arr = arr[arr > 50]arr = arr[(arr > 50).nonzero()] 我将进行编辑以将其包含在答案中,因为我们正在比较所有方法.
【解决方案2】:

在您的问题中,您有一些代码:

numbers = [np.random.randint(50, 100) for x in range(100)]

应该是这样的

numbers = np.random.randint(50, 100, 100)

然后你问是否有一种方法可以使用list-comprehension 结合过滤来复制它,从如下内容开始:

numbers = [np.random.randint(1, 100) for x in range(100) if ...]

这个问题的答案通常是NO

这样做的原因是条件过滤语法将充当生成数字的过滤器,数字被生成并暂时生成之后。

因此,虽然代码 [np.random.randint(50,100) for x in range(100)] 将生成 100 个项目,但任何基于理解过滤甚至显式使用 filter() 的方法都将具有未知数量的元素(通常少于 100,具体取决于满足的项目数量)指定的条件)。

要达到该级别的控制,您可以使用基于while 的生成器(cannot be included in a comprehension),例如:

import numpy as np


def my_brand_new_generator(n, a=1, b=100):
    i = 0
    while i < n:
        x = np.random.randint(a, b)
        if x > 50:
            yield x
            i += 1


numbers = list(my_brand_new_generator(100))
print(numbers[10])
# [94 97 50 53 53 89 59 69 71 86]

print(len(numbers))
# 100

相比之下:

numbers = [x for x in (np.random.randint(1,100) for iter in range(100)) if x > 50]
print(len(numbers))
# 54

x = np.random.randint(1, 100, 100)
numbers = x[x > 50]
print(len(numbers))
# 43

附注:

  • my_brand_new_generator() 仅被视为一个玩具示例来说明上述想法。
  • 一般而言,NumPy 提供了比显式迭代更好的替代方案,因此,如果可用,请使用 that
  • 要生成单个随机整数,您可以使用 Python 标准库中的 random.randint()

【讨论】:

  • “任何基于理解过滤甚至显式使用 filter() 的方法都无法控制生成值的数量”是什么意思?
  • @AlexanderCécile 这意味着您无法预先知道以下列表中有多少项目:[x for x in (random.randint(1, 100) for _ in range(100)) if x &gt; 50]
  • 好吧,有道理!编辑您的答案以使其更清晰可能是个好主意,因为我们确实可以控制生成的值的数量,而不是过滤后的结果数量/数量。
  • 是的,好多了:)
【解决方案3】:

是的,这是可能的,首先在此处生成 1 到 100 之间的 100 个数字(或您需要多少个),但这又取决于您,然后遍历它们检查每个数字,只保留超过 50 个的数字...

y = np.random.randint(1, high=100, size=100)
number = [x for x in y if x > 50]

或者在一行中...

number = [x for x in np.random.randint(1, high=100, size=100) if x > 50]

【讨论】:

  • 是的,我想我可以先生成它们。我想检查一下我是否可以使用偷偷摸摸的单线。谢谢。
  • @JonasPalačionis 刚刚添加了一个班轮
  • 请注意,这会创建一个不必要的临时容器,因此它的内存效率并不高。
  • 当然,但这不是所要求的
  • 我认为@norok2 提出了一个很好的观点。即使它与问题没有直接关系,最好编写整体上可靠的代码。这是一个好习惯。您不会在代码中包含恶意软件,因为 OP 没有询问“创建随机数列表并过滤列表以仅包含大于 50 的数字,而不会出现任何恶意软件”,对吗? ;)
【解决方案4】:

@FlorianBernard 是对的,不要混合使用 Python 列表和 NumPy 数组。留在 NumPy 世界中,无论如何事情会更快。在 NumPy 中,python 列表理解没有等价物,因为它对数组进行操作,而不是对单个项目进行操作。

无论如何,使用numpy.where function@FlorianBernard 答案有一个更复杂但更强大的替代方法

F.e.,它允许将过滤后的数组和基线数组融合到新的数组中。 简单的代码开始

import numpy as np
q = np.random.randint(1, 100, 1000)
m = np.where(q > 50)
print(q[m])

【讨论】:

  • 我还要添加一条关于np.where() 和布尔掩码之间速度和内存效率比较的注释。
  • 别怕,这种情况下where基本相当于屏蔽了!请参阅@FlorianBernard 对答案的编辑/评论
  • Here 你可以找到一些np.where() 与布尔掩码切片比较。
  • @norok2 好吧,Florian 回答中的时间已经完成,所以我没有打扰
【解决方案5】:

当你没有理由时,小心不要混合使用 numpy 和普通 python!您写道您可以使用numbers = [np.random.randint(50,100) for x in range(100)],但最好只使用np.random.randint(low=50, high=100, size=100) 来创建一个包含100 个随机数的数组。

这是一个纯python解决方案:

import random

rand_nums = (random.randint(0, 99) for _ in range(10))
arr = [val for val in rand_nums if val > 50]

显然可以写成一行:

arr = [val for val in (random.randint(0, 99) for _ in range(10)) if val > 50]

这是一个 numpy 解决方案:

import numpy as np

arr = np.random.randint(low=0, high=100, size=10)
arr = arr[arr > 50]

【讨论】:

    【解决方案6】:

    使用

    numbers = [x for x in (np.random.randint(1,100) for iter in range(100)) if x > 50]
    

    第 1 步:(np.random.randint(1,100) for iter in range(100)):这会生成 100 次,一个介于 1 和 100 之间的随机整数。

    第二步:if x &gt; 50:比较生成的数字。如果大于 50,则通过并附加到列表中。

    【讨论】:

    • 不幸的是,这不起作用 - 因为如果数字小于 50,则跳过迭代。
    • 仍然只得到 56 个数字,而不是 100 个。&gt;&gt;&gt; n = [x for x in (np.random.randint(1,100) for iter in range(100)) if x &gt; 50] &gt;&gt;&gt; len(n) 56
    • 你不能总是得到 100。如果数字小于 50,则不附加。我认为你错过了一些东西
    • 请注意,在 Python 3.8 中,您可以稍微简化一下:numbers = [x := random.randint(1, 100) for _ in range(100) if x &gt; 50]
    • 另外值得注意的是,使用生成器不会为生成的随机项目创建一个临时无用的容器。
    【解决方案7】:

    只需使用filter 函数:

    rand = filter(lambda x: x>50, np.random.randint(1,100,100))
    rand_list = list(rand)
    

    不需要列表理解。

    【讨论】:

    • OP 要求提供仅限列表理解的解决方案
    【解决方案8】:
    import random
    ml=random.sample(range(100),100)
    
    
    # Get list of items larger than 50 using list comprehension approach
    filtered = [x for x in ml if x > 50]
    print(filtered)
    
    
    # Get list of items larger than 50 using filter approach
    filtered = list(filter(lambda x: x > 50, ml))
    print(filtered)
    

    【讨论】:

      【解决方案9】:

      通过创建一个仅在数字大于 50 时才会展开的递归函数来欺骗它。

      import numpy as np
      
      def genrandx():
          # Using a function allows you do to all sorts of crazy stuff and checks.
          x = np.random.randint(1,100)
          x = int((x*.5)**2)
          if (
              (x > 50) and
              (x < 1000) and 
              ( (x%3 == 0) or (x%3 == 0) )
             ): 
              return x 
          else: 
              return genrandx() 
      
      numbers = [ genrandx() for x in range(100)]
      print("({}){}".format(len(numbers), numbers))
      

      输出:

      (100)[930, 729, 306, 576, 600, 225, 324, 324, 462, 324, 462, 756, 324, 225, 702, 552, 576, 72, 81, 900, 600, 225, 930, 900, 576, 240, 552, 702, 441, 72, 462, 132, 144, 324, 72, 702, 462, 930, 72, 306, 240, 225, 870, 210, 729, 600, 420, 132, 240, 420, 441, 420, 72, 756, 225, 900, 72, 90, 72, 600, 72, 420, 210, 702, 240, 462, 600, 156, 81, 900, 144, 72, 225, 324, 144, 420, 600, 576, 729, 156, 900, 81, 756, 729, 702, 90, 462, 306, 600, 930, 729, 240, 552, 144, 90, 900, 420, 225, 600, 156]
      

      【讨论】:

      • OP 要求提供仅限列表理解的解决方案
      • @makis - 这是一个列表理解
      • 使用外部函数。我已经提供了仅使用列表理解的答案。
      • @Sayse 它包含一个列表理解,但它不是一个,因为您还定义了一个函数
      • 参见Can a lambda function call itself recursively in Python? 并使用递归 lambda 设置列表项。然后你可以称它为单数列表理解-
      猜你喜欢
      • 1970-01-01
      • 2021-10-28
      • 2021-03-06
      • 2014-06-20
      • 1970-01-01
      • 1970-01-01
      • 2020-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多