为什么numpy的fromiter函数不需要其他数组创建例程就需要指定dtype?

mpacer

为了提高内存效率,我一直在努力将我的一些代码从列表转换为可能的生成器/迭代器。我发现很多情况下,我只是将np.array使用代码模式转换成的列表转换为np.array(some_list)

值得注意的是,some_list列表理解通常是在生成器上进行迭代的。

我一直在研究np.fromiter是否可以更直接地使用生成器(而不是必须先将其转换为列表然后将其转换为numpy数组),但是我注意到该np.fromiter函数与使用该数组的任何其他数组创建例程不同现有数据需要指定dtype

在我的大多数特定情况下,我可以做到这一点(大多数情况下是处理对数似然的,所以float64会很好),但让我感到奇怪的是,为什么这仅对fromiter数组创建者有用,而对其他数组创建者不是必需的

首先尝试猜测:

内存预分配?

我的理解是,如果您知道dtypecount,它将允许为结果预分配内存np.array,并且如果您未指定可选count参数,它将“按需调整输出数组的大小”。但是,如果您未指定计数,则似乎应该能够dtype像在正常np.array通话中一样即时推断运行时间

数据类型重铸?

我可以看到这对于将数据重播到new中很有用dtype,但是这对于其他数组创建例程也同样适用,并且似乎值得将放置作为可选但不是必需的参数。

重申问题的几种方法

那么为什么需要指定dtype要使用的呢np.fromiter或者换种方式说,dtype如果指定是否要根据需要调整数组的大小,指定的结果是什么?

与我的问题更直接相关的同一个问题的更微妙的版本:我知道np.ndarrays的许多效率增益在不断调整大小时会丢失,那么使用np.fromiter(generator,dtype=d)over np.fromiter([gen_elem for gen_elem in generator],dtype=d)over会带来np.array([gen_elem for gen_elem in generator],dtype=d)什么?

hpaulj

如果此代码是十年前编写的,并且没有更改它的压力,那么旧的原因仍然适用。大多数人都乐于使用np.arraynp.fromiter主要用于试图从迭代生成值的方法中加快速度的人。

我的印象是np.array,主要选择方案是在决定dtype(和其他属性)之前读取/处理整个输入:

我可以通过更改一个元素来强制返回浮点数:

In [395]: np.array([0,1,2,3,4,5])
Out[395]: array([0, 1, 2, 3, 4, 5])
In [396]: np.array([0,1,2,3,4,5,6.])
Out[396]: array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.])

我用的不是fromiter很多,但是我的感觉是通过require dtype,它可以从一开始就将输入转换为该类型。尽管需要时间测试,但最终可能会产生更快的迭代。

我知道np.array一般性要付出一定的时间成本。通常,对于小型列表,使用列表理解要比将其转换为数组更快,即使数组操作很快速。

一些时间测试:

In [404]: timeit np.fromiter([0,1,2,3,4,5,6.],dtype=int)
100000 loops, best of 3: 3.35 µs per loop
In [405]: timeit np.fromiter([0,1,2,3,4,5,6.],dtype=float)
100000 loops, best of 3: 3.88 µs per loop
In [406]: timeit np.array([0,1,2,3,4,5,6.])
100000 loops, best of 3: 4.51 µs per loop
In [407]: timeit np.array([0,1,2,3,4,5,6])
100000 loops, best of 3: 3.93 µs per loop

差异很小,但表明我的推理是正确的。要求dtype有助于保持fromiter更快。count如此小的尺寸并没有什么不同。

奇怪的是,指定dtypefornp.array会减慢它的速度。好像它追加了一个astype呼叫:

In [416]: timeit np.array([0,1,2,3,4,5,6],dtype=float)
100000 loops, best of 3: 6.52 µs per loop
In [417]: timeit np.array([0,1,2,3,4,5,6]).astype(float)
100000 loops, best of 3: 6.21 µs per loop

使用时,np.array之间的区别np.fromiter更加明显range(1000)(Python3生成器版本)

In [430]: timeit np.array(range(1000))
1000 loops, best of 3: 704 µs per loop

实际上,将范围转换为列表会更快:

In [431]: timeit np.array(list(range(1000)))
1000 loops, best of 3: 196 µs per loop

fromiter仍然更快:

In [432]: timeit np.fromiter(range(1000),dtype=int)
10000 loops, best of 3: 87.6 µs per loop

这是更快以应用intfloat产生/迭代期间转换整个阵列上,而不是每个元件

In [434]: timeit np.fromiter(range(1000),dtype=int).astype(float)
10000 loops, best of 3: 106 µs per loop
In [435]: timeit np.fromiter(range(1000),dtype=float)
1000 loops, best of 3: 189 µs per loop

注意,astype调整大小的操作并不是那么昂贵,只有大约20 µs。

===========================

array_fromiter(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *keywds) 在以下位置定义:

https://github.com/numpy/numpy/blob/eeba2cbfa4c56447e36aad6d97e323ecfbdade56/numpy/core/src/multiarray/multiarraymodule.c

https://github.com/numpy/numpy/blob/97c35365beda55c6dead8c50df785eb857f843f0/numpy/core/src/multiarray/ctors.c中处理keywds和调用PyArray_FromIter(PyObject *obj, PyArray_Descr *dtype, npy_intp count)

这将ret使用定义的初始数组dtype

ret = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype, 1,
                                            &elcount, NULL,NULL, 0, NULL);

data数组属性与一起增长50% overallocation => 0, 4, 8, 14, 23, 36, 56, 86 ...,并缩小以适合末尾。

PyArray_DESCR(ret)显然,此数组的dtype具有可以接受value(由iterator提供next),对其进行转换并将其设置在中的函数data

`(PyArray_DESCR(ret)->f->setitem(value, item, ret)`

换句话说,所有dtype转换都由定义的dtype完成。如果代码“动态”决定如何转换value(以及所有先前分配的)代码,则它将变得更加复杂此函数中的大多数代码都处理分配data缓冲区。

我等下去np.array我敢肯定它要复杂得多。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Postgres:为什么某些函数调用需要()而其他函数不需要?

来自分类Dev

在C语言中,当使用malloc创建2D数组时,为什么在传递给函数时不需要指定2D数组大小?

来自分类Dev

为什么ng-href指令需要{{}}而其他指令则不需要?

来自分类Dev

为什么ng-href指令需要{{}}而其他指令则不需要?

来自分类Dev

为什么有些程序需要安装,而其他程序则不需要?

来自分类Dev

为什么 ViewController 类不需要遵守 NSObject 协议,而其他类则需要

来自分类Dev

为什么某些android事件会阻止传播,而其他则不需要?

来自分类Dev

为什么某些android事件停止传播,而其他则不需要?

来自分类Dev

为什么不需要在构造函数中指定变量?

来自分类Dev

为什么某些html元素需要Angular.JS指令,而其他则不需要?

来自分类Dev

为什么JavaScript在函数声明后不需要分号?

来自分类Dev

为什么不需要释放静态数组?

来自分类Dev

为什么putchar不需要标题?

来自分类Dev

为什么类需要默认构造函数,而结构却不需要?

来自分类Dev

为什么iter()需要lambda函数的&,而本例中的range却不需要

来自分类Dev

为什么对象不需要时Java中的数组需要具有预定义的长度?

来自分类Dev

为什么有些应用程序需要首先“安装”才能运行,而其他应用程序则不需要?

来自分类Dev

XML的XSL转换-显示不需要的其他文本

来自分类Dev

JSLint错误:“中断后不需要其他”

来自分类Dev

JLabel是否不需要其他线程即可刷新?

来自分类Dev

不需要基于其他字段的值的字段

来自分类Dev

sql语句不需要的其他记录

来自分类Dev

为什么我不需要在邮件中指定SMTP服务器?

来自分类Dev

为什么在Spring Boot项目中不需要为某些依赖项指定版本?

来自分类Dev

在EF Core中使用Include(或ThenInclude)时,为什么不需要指定类型?

来自分类Dev

为什么我不需要在邮件中指定SMTP服务器?

来自分类Dev

为什么gpg不需要我们指定用于加密和解密的密钥?

来自分类Dev

为什么for循环不需要显式指定循环变量的值集?

来自分类Dev

为什么有些 JavaScript 函数需要创建一个新变量,而有些则不需要?

Related 相关文章

  1. 1

    Postgres:为什么某些函数调用需要()而其他函数不需要?

  2. 2

    在C语言中,当使用malloc创建2D数组时,为什么在传递给函数时不需要指定2D数组大小?

  3. 3

    为什么ng-href指令需要{{}}而其他指令则不需要?

  4. 4

    为什么ng-href指令需要{{}}而其他指令则不需要?

  5. 5

    为什么有些程序需要安装,而其他程序则不需要?

  6. 6

    为什么 ViewController 类不需要遵守 NSObject 协议,而其他类则需要

  7. 7

    为什么某些android事件会阻止传播,而其他则不需要?

  8. 8

    为什么某些android事件停止传播,而其他则不需要?

  9. 9

    为什么不需要在构造函数中指定变量?

  10. 10

    为什么某些html元素需要Angular.JS指令,而其他则不需要?

  11. 11

    为什么JavaScript在函数声明后不需要分号?

  12. 12

    为什么不需要释放静态数组?

  13. 13

    为什么putchar不需要标题?

  14. 14

    为什么类需要默认构造函数,而结构却不需要?

  15. 15

    为什么iter()需要lambda函数的&,而本例中的range却不需要

  16. 16

    为什么对象不需要时Java中的数组需要具有预定义的长度?

  17. 17

    为什么有些应用程序需要首先“安装”才能运行,而其他应用程序则不需要?

  18. 18

    XML的XSL转换-显示不需要的其他文本

  19. 19

    JSLint错误:“中断后不需要其他”

  20. 20

    JLabel是否不需要其他线程即可刷新?

  21. 21

    不需要基于其他字段的值的字段

  22. 22

    sql语句不需要的其他记录

  23. 23

    为什么我不需要在邮件中指定SMTP服务器?

  24. 24

    为什么在Spring Boot项目中不需要为某些依赖项指定版本?

  25. 25

    在EF Core中使用Include(或ThenInclude)时,为什么不需要指定类型?

  26. 26

    为什么我不需要在邮件中指定SMTP服务器?

  27. 27

    为什么gpg不需要我们指定用于加密和解密的密钥?

  28. 28

    为什么for循环不需要显式指定循环变量的值集?

  29. 29

    为什么有些 JavaScript 函数需要创建一个新变量,而有些则不需要?

热门标签

归档