【问题标题】:python: iterating through every item within parallel nested listspython:遍历并行嵌套列表中的每个项目
【发布时间】:2017-05-27 23:31:22
【问题描述】:

我有以下各种 numpy 数组的列表:

nparrays_list = [
    array([1, 2, 3, 4])
    array([5, 6, 7, 8]),
    array([9, 10, 11, 12])
]

我想在不影响列表形状的情况下遍历整个列表(即我不想展平列表)以获得以下numpy数组列表:

nparrays_list_Decimal = [
    array([Decimal('1'), Decimal('2'), Decimal('3'), Decimal('4')])
    array([Decimal('5'), Decimal('6'), Decimal('7'), Decimal('8')]),
    array([Decimal('9'), Decimal('10'), Decimal('11'), Decimal('12')])
]

这是我目前的代码:

import numpy as np

nparrays_list_Decimal = []
for nparray in nparrays_list:
    nparray_Decimal = np.array([D(str(item)) for item in nparray])
    nparrays_list_Decimal.append(nparray_Decimal)

我的问题是我正在处理大量数据,因此创建新列表并不理想(即浪费内存)。是否有一种简单的方法可以遍历原始列表中的每个项目,即使这些项目位于嵌套列表(或本例中为 numpy 数组)中?

【问题讨论】:

  • 你是如何定义D的?为什么nparrays_list 不是一个numpy 数组?
  • 我猜你至少可以通过传递"<U8" 格式和生成器来保存临时列表。这会将您的项目截断为 8 个字符。
  • D 代表十进制。让我编辑它以使其更清楚。它是nparrays_list,因为它是一个 numpy 数组列表。我也不需要容器成为 nparray
  • 当你似乎有整数时,为什么你需要Decimal类型?
  • @dawg 我在这个例子中使用了整数,但我的实际数据有小数。快速跟进问题:如果我只处理整数,我会失去精度/准确性吗?如果我对整数进行除法(我猜这些问题分别是“否”和“是”)呢?

标签: python arrays numpy iteration


【解决方案1】:

由于您将在 Numpy 数组中拥有不同的对象类型,因此您需要创建新数组(除非它们是 dtype=object 的数组)

这是一个演示,说明你不能在 Numpy 数组中混合类型:

>>> arr=np.array([1,2,3])
>>> arr
array([1, 2, 3])
>>> arr[1]="string"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for long() with base 10: 'string' 

Decimal 类型分配给整数数组不会将该元素更改为数组中的十进制类型; arr[1] 被转换为 Decimal,但随后又默默地转换回 int:

>>> arr
array([1, 2, 3])
>>> arr[1]=Decimal(arr[1])
>>> arr
array([1, 2, 3])
>>> type(arr[1])
<type 'numpy.int64'>

你可以这样做:

>>> nparrays_list_Decimal=[np.array([Decimal(e) for e in arr]) for arr in nparrays_list]
>>> nparrays_list_Decimal
[array([Decimal('1'), Decimal('2'), Decimal('3'), Decimal('4')], dtype=object), array([Decimal('5'), Decimal('6'), Decimal('7'), Decimal('8')], dtype=object), array([Decimal('9'), Decimal('10'), Decimal('11'), Decimal('12')], dtype=object)]

或者,只使用列表列表:

>>> LoL=[[Decimal(e) for e in arr] for arr in nparrays_list]
>>> LoL
[[Decimal('1'), Decimal('2'), Decimal('3'), Decimal('4')], [Decimal('5'), Decimal('6'), Decimal('7'), Decimal('8')], [Decimal('9'), Decimal('10'), Decimal('11'), Decimal('12')]]

如果 memory 是您关心的问题,(通常您不需要对适度的数组担心太多)您可以通过在转换子数组时删除子数组来进行更高效的转换:

from collections import deque 

nparrays_list=deque(LoA)   # the List of Arrays is garbage collected..
nparrays_list_Decimal=[]
while nparrays_list:
    # each sublist is garbage collected after being popped and iterated
    nparrays_list_Decimal.append(np.array([Decimal(e) for e in nparrays_list.popleft()]))

>>> nparrays_list_Decimal
[array([Decimal('1'), Decimal('2'), Decimal('3'), Decimal('4')], dtype=object), array([Decimal('5'), Decimal('6'), Decimal('7'), Decimal('8')], dtype=object), array([Decimal('9'), Decimal('10'), Decimal('11'), Decimal('12')], dtype=object)]

【讨论】:

  • 列表理解就足够了。谢谢。根据您的帖子和 hpaulj 的帖子,听起来内存根本不是限制因素。
【解决方案2】:

可能是这样的

import numpy as np

nparrays_list_Decimal = [list(map(float, lst)) for lst in nparrays_list]

编辑:

From the Python Documentation on Decimals

要使用小数试试这个

from decimal import *
nparrays_list_Decimal = [list(map(Decimal, lst)) for lst in nparrays_list]

【讨论】:

  • 如何使用它将数字转换为 Decimal 对象(我需要更高的精度)?浮点数太不准确
【解决方案3】:
nparrays_list = [
    array([1, 2, 3, 4])
    array([5, 6, 7, 8]),
    array([9, 10, 11, 12])
]

不用担心制作新列表。列表只包含指向内存中其他地方的对象的指针。在这种情况下,列表只占用 3 个整数的内存。组件确实会占用内存 - 它们是具有 4 个元素数据缓冲区的数组。

nparrays_list_Decimal = [
    array([Decimal('1'), Decimal('2'), Decimal('3'), Decimal('4')]),
    array([Decimal('5'), Decimal('6'), Decimal('7'), Decimal('8')]),
    array([Decimal('9'), Decimal('10'), Decimal('11'), Decimal('12')])
]

是另一个小列表,有 3 个指针。您可以将这些指针放回原来的nparray_list,但为什么呢?只是为了节省 3 个整数的空间?

但重要的是,新数组在内存方面与原始数组不兼容:

array([Decimal('1'), Decimal('2'), Decimal('3'), Decimal('4')])

是一个对象 dtype 数组。这就像一个列表,带有指向内存中其他位置的 Decimal(n') 对象的指针。那必须是一个新数组;它不能替换原始array([1,2,3,4]) 中的np.int32 项。

你为什么不直接离开

nparrays_list = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12]
]

到:

nparrays_list_Decimal = [
    [Decimal('1'), Decimal('2'), Decimal('3'), Decimal('4')],
    [Decimal('5'), Decimal('6'), Decimal('7'), Decimal('8')],
    [Decimal('9'), Decimal('10'), Decimal('11'), Decimal('12')]
]

换句话说,坚持使用列表。 Decimal 对象的数组是否比相同对象的列表更有用?

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

因为Decimal 定义了许多数学运算,所以可以对Decimal 对象数组执行一些数组数学运算:

In [482]: arr = np.array([Decimal(i) for i in range(1,4)])
In [483]: arr
Out[483]: array([Decimal('1'), Decimal('2'), Decimal('3')], dtype=object)
In [484]: arr + 1
Out[484]: array([Decimal('2'), Decimal('3'), Decimal('4')], dtype=object)
In [485]: 1 / arr
Out[485]: 
array([Decimal('1'), Decimal('0.5'),
       Decimal('0.3333333333333333333333333333')], dtype=object)

Speedwise 最后一条语句与以下基本相同:

np.array([1/i for i in arr])

会比1/np.arange(1,4)慢。

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

您可以通过以下方式制作 Decimal 数组来稍微提高速度:

In [503]: np.frompyfunc(Decimal,1,1)(np.arange(3))
Out[503]: array([Decimal('0'), Decimal('1'), Decimal('2')], dtype=object)
In [504]: np.frompyfunc(Decimal,1,1)(np.arange(12).reshape(3,4))
Out[504]: 
array([[Decimal('0'), Decimal('1'), Decimal('2'), Decimal('3')],
       [Decimal('4'), Decimal('5'), Decimal('6'), Decimal('7')],
       [Decimal('8'), Decimal('9'), Decimal('10'), Decimal('11')]], dtype=object)

在其他测试中,我发现frompyfunc 与更显式的迭代表达式相比,速度有所提高(例如 2 倍)。它还具有无缝处理多维数组的优势。它返回一个object 数组。有时这是个问题;在这里就好了。

In [509]: timeit np.frompyfunc(Decimal,1,1)(np.arange(2000))
1000 loops, best of 3: 752 µs per loop
In [510]: timeit np.array([Decimal(str(i)) for i in np.arange(2000)])
100 loops, best of 3: 17.1 ms per loop
In [515]: timeit np.array([Decimal(i) for i in range(2000)])
100 loops, best of 3: 7.39 ms per loop
In [525]: timeit np.array([Decimal(i.item()) for i in np.arange(2000)])
100 loops, best of 3: 11.3 ms per loop

我想知道你为什么使用str(i)。但是后来我发现Decimal只能拿几个np.dtypes(不是np.int32)。我的猜测是 frompyfunc 使用 item() 或等价物来生成 Python 标量:

In [523]: np.frompyfunc(Decimal,1,1)(np.arange(2))
Out[523]: array([Decimal('0'), Decimal('1')], dtype=object)
In [524]: np.array([Decimal(i.item()) for i in np.arange(2)])
Out[524]: array([Decimal('0'), Decimal('1')], dtype=object)

frompyfunc 必须执行与 i.item() 等效的操作才能从 np.int32 对象生成 Python 标量。

【讨论】:

  • 我需要 np.array 容器,因为我正在执行 numpy 模块更容易进行的数学运算
  • 是的,我添加了一些使用对象数组的示例。无论如何,我认为您无法提高速度或内存使用率。无论容器结构如何,您都将拥有 1000 个 Decimal 对象和 1000 个指向这些对象的指针。
  • 我添加了一个使用frompyfunc的演示,以方便Decimal数组的创建。
  • 听起来记忆对我来说不是什么大问题,我可以采取简单的方法。谢谢!
【解决方案4】:

要遍历每个项目,您可以像这样进行嵌套 for 循环。

nparrays_list = [
        array([1, 2, 3, 4]),
        array([5, 6, 7, 8]),
        array([9, 10, 11, 12])   
    ]

for arr in nparrays_list:
  for i, item in enumerate(arr):
    arr[i] = Decimal(str(item))

【讨论】:

  • 当我在最后一行尝试item = Decimal(str(item)) 时,没有任何反应。如何使用它将所有值转换为 Decimal 对象?
  • @jcmetz21 更新了我的答案
  • 这不会将元素转换为Decimal 对象。请参阅 hpaulj 的帖子或我的帖子。
【解决方案5】:

我没有numpy,但以下可能会给你一些解决问题的方向:

Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 08:06:12) [MSC v.1900 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import array
>>> array_list = [
    array.array('q', [1, 2, 3, 4]),
    array.array('q', [5, 6, 7, 8]),
    array.array('q', [9, 10, 11, 12])
    ]
>>> def iterate(iterable):
    for index_a, value_a in enumerate(iterable):
        try:
            for index_b, value_b in iterate(value_a):
                yield [index_a] + index_b, value_b
        except TypeError:
            yield [index_a], value_a


>>> for index, value in iterate(array_list):
    print(value, 'is at', index)


1 is at [0, 0]
2 is at [0, 1]
3 is at [0, 2]
4 is at [0, 3]
5 is at [1, 0]
6 is at [1, 1]
7 is at [1, 2]
8 is at [1, 3]
9 is at [2, 0]
10 is at [2, 1]
11 is at [2, 2]
12 is at [2, 3]
>>> 

为了完成您的问题的解决方案,可以支持自动转换或类型转换:

>>> def iterate(iterable, cast):
    for index_a, value_a in enumerate(iterable):
        try:
            for index_b, value_b in iterate(value_a, cast):
                yield [index_a] + index_b, value_b
        except TypeError:
            yield [index_a], cast(value_a)


>>> import decimal
>>> for index, value in iterate(array_list, decimal.Decimal):
    print(repr(value), 'came from', index)


Decimal('1') came from [0, 0]
Decimal('2') came from [0, 1]
Decimal('3') came from [0, 2]
Decimal('4') came from [0, 3]
Decimal('5') came from [1, 0]
Decimal('6') came from [1, 1]
Decimal('7') came from [1, 2]
Decimal('8') came from [1, 3]
Decimal('9') came from [2, 0]
Decimal('10') came from [2, 1]
Decimal('11') came from [2, 2]
Decimal('12') came from [2, 3]
>>> 

【讨论】:

  • 我一定要考虑创建这些可迭代函数。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-19
  • 1970-01-01
相关资源
最近更新 更多