【问题标题】:Running a for loop through 2 arrays of different lengths and index manipulation通过 2 个不同长度的数组和索引操作运行 for 循环
【发布时间】:2017-12-06 03:37:17
【问题描述】:

我需要通过 2 个不同长度的数组运行 for 循环。一个数组是 8760 x 1,另一个是 10 x 1。如果短数组中的值等于长数组中的值的索引,我不想更改任何内容。如果长数组中的值的索引不等于短数组中的值,我想将其设置为零。我知道我的代码是错误的,但这是一个开始。我无法附加更长的数组,但它现在可能是随机值。

I = np.array([4993, 4994, 4995, 5016, 5017, 5018, 5019, 5042, 5043, 5066])

import numpy as np

A = np.loadtxt('A.txt')
I = np.loadtxt('I.txt')

for i in A:
    for j in I:
        if A[j] != I[j]:
            i = 0

【问题讨论】:

  • 查看np.in1d 以获得更简单的方法或查看np.searchsorted 以获得不那么简单但有效的方法。
  • @Divakar FYI 现在还有 np.isin :)
  • @AndrasDeak 嗯,新东西,令人兴奋!
  • 我几乎想添加一个答案,但是从您的代码示例中可以清楚地看出那里存在非常基本的问题。如果您还没有阅读 Python 教程,您可能会从中受益。
  • np.in1d 似乎不允许我在查看文档后根据索引将值更改为零

标签: python arrays numpy for-loop indexing


【解决方案1】:

主要原则

当您需要for 循环遍历数组的索引时,请使用“计数”循环——遍历一组整数的循环。使用for index in range(len(your list)

您的具体问题

鉴于您的I,我认为您要求将A 的所有值设置为0(例如分配A[5] = 0),例如A[4993] 将保持不变,等等索引在I

good_elements_indices = I
all_elements = A
for all_elements_index in range(len(all_elements)):
    if all_elements_index not in good_elements_index:
        A[all_elements_index] = 0

其他 cmets

  • Python 样式使用小写的变量名,单词之间有下划线,没有缩写。因此我重命名了IA。见PEP 8: Python Style Guide
  • in 运算符是 Python 的核心。因为您已经在导入 numpy 并且您的 good_elements_index 又名 I 已经是 numpy.array 对象,所以按照 mrcl 的建议使用 numpy.isin 函数更快但不太通用。
  • 您的问题涉及“通过 2 个数组运行 for 循环”。这表明不是一个 for 循环,而是两个嵌套的 for 循环,如您的问题代码所示。 in 运算符实际上像 for 循环一样遍历列表,测试是否存在于集合中。

【讨论】:

    【解决方案2】:

    numpy 的一般概念是 “无循环” 我想展示一下它是如何实现的 可以在没有任何(显式)的情况下执行 OP 提出的任务 循环。

    我们将使用numpy 的扩展寻址功能 让它以自己的速度处理数据操作细节。

    举个例子,我需要一些data 和一个列表,或者 向量,这里命名为persisting,对应于这些索引的索引 要求在修改后的 data 数组中保留的值 我们的程序结束。

    import numpy as np
    data = np.arange(10)
    persisting = [4,8,1,0]
    

    鉴于这些预备,我们可以计算出一个held 数组,它包含 我们想要持久化的所有data 元素,indexing the data array using the persisting array

    held = data[persisting]
    

    data 数组可以使用全速填充零 数组法 .fill() 最终保存在held 中的元素可以恢复到它们的 原来的地方,再次使用扩展寻址,这次在左边 的任务。

    data.fill(0)
    data[persisting] = held
    print(data) #>>> [0 1 0 0 4 0 0 0 8 0]
    

    上面概述的过程可能会也可能不会比其他程序更快 方法取决于您正在操作的数组的 len() 以及分别有多少是零填充而不是 保持之前的值。如果您的问题是生产问题 考虑对您使用过的各种方法进行基准测试 建议。

    基准测试

    我已经对接受的答案和我的方法中提出的方法进行了计时。以下是记录我的过程的 IPython 会话记录。

    打印的结果是数据数组的长度、索引数组的长度、用于执行这两个函数中的每一个的时间(以秒为单位)(平均超过 7 次重复)。

    In [38]: import numpy as np
    
    In [39]: def accepted(A, I):
        ...:     good_elements_indices = I
        ...:     all_elements = A
        ...:     for all_elements_index in range(len(all_elements)):
        ...:         if all_elements_index not in good_elements_indices:
        ...:             A[all_elements_index] = 0.0
        ...:             
    
    In [40]: def alternate(a, i):
        ...:     held = a[i]
        ...:     a.fill(0.0)
        ...:     a[i] = held
        ...:     
    
    In [41]: for length in (100, 10000, 1000000):
        ...:     a = np.arange(length)
        ...:     for remain in (10, 100, 10000, length//2):
        ...:         if remain < length:
        ...:             i = np.random.choice(length, remain)
        ...:             acc_t = %timeit -q -o  accepted(a, i)
        ...:             alt_t = %timeit -q -o alternate(a, i)
        ...:             print('%10d, %10d: %e, %e;'%(
        ...:                    length, remain, acc_t.average, alt_t.average))
        ...:                    
           100,         10: 1.506336e-04, 1.126085e-06;
           100,         50: 1.663167e-04, 1.385859e-06;
         10000,         10: 1.539412e-02, 5.308621e-06;
         10000,        100: 2.198021e-02, 6.056105e-06;
         10000,       5000: 2.995333e-01, 3.775863e-05;
       1000000,         10: 1.524685e+00, 1.596268e-03;
       1000000,        100: 2.187460e+00, 1.599069e-03;
       1000000,      10000: 7.067548e+01, 1.770094e-03;
    ^C---------------------------------------------------------------------------
    KeyboardInterrupt                         Traceback (most recent call last)
    

    请注意,我不得不中断计时过程,因为%timeit 计算了七次重复的平均值,这意味着最后一行需要超过 8 分钟才能完成...

    我不得不说可以很容易地加快接受的答案,但我认为必须处理循环和测试它会更慢。

    【讨论】:

      猜你喜欢
      • 2018-04-10
      • 2019-08-04
      • 2020-11-20
      • 2021-09-20
      • 2012-01-09
      • 1970-01-01
      • 2018-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多