【问题标题】:Changing individual elements of numpy array based on its value根据其值更改 numpy 数组的各个元素
【发布时间】:2019-07-21 03:57:03
【问题描述】:

我正在尝试遍历 numpy 数组的每个元素并以半随机方式更改其值。这样做的原因是,我将该方法应用于不同的数组:我希望它们被更改,但我不希望它们以相同的方式更改。

这是我目前尝试过的:

with np.nditer(smatrix, op_flags=['readwrite']) as it:
    for element in it:
        if element < 0:
            element = element - uniform(0.1,0.2)
        if 0 <= element < 0.05:
            element = uniform(0.15,0.3)
        elif 0.05 <= element < 1:
            element = 0
        elif 1 == element:
            element = 1

另一种可能性:

for element in np.nditer(smatrix, op_flags=['readwrite']):
    if element < 0:
        element = element - uniform(0.1,0.2)
    if 0 <= element < 0.05:
        element = uniform(0.15,0.3)
    elif 0.05 <= element < 1:
        element = 0
    elif 1 == element:
        element = 1

但是,结果数组看起来与初始数组完全相同...

我对编程比较陌生,并且在这个问题上停留了很长一段时间。如果有人能给我一个关于如何解决它的提示,最好是一个简短的解释,那就太棒了。谢谢!!

【问题讨论】:

    标签: python arrays numpy iteration numpy-ndarray


    【解决方案1】:

    如果您想对numpy.array 的每个单元格应用转换,那么numpy.vectorize 是正确的工具。 首先你需要一个函数,它将使用单个单元格的内容作为输入,它本身将被提供给 vectorizereturn 所需的值,请参见代码:

    import numpy as np
    import random
    def f(x):
        if x < 0:
            return x-random.uniform(0.1,0.2)
        if 0 <= x < 0.05:
            return random.uniform(0.15,0.3)
        if 0.05 <= x < 1:
            return 0.0
        if x == 1:
            return 1.0
        return x
    vf = np.vectorize(f)
    
    data = np.array([-4.3,0.03,0.9,1.0,1.9])
    altered_data = vf(data)
    

    输出(对你来说可能有点不同,因为它是部分随机的):

    [-4.48922564  0.19609667  0.          1.          1.9       ]
    

    如您所见,它对所有值都按预期工作。请注意,我添加了“对元素不做任何事情”行为 (return x) 作为安全措施,以防元素大于 1

    有关numpy.vectorize 的更多信息,请阅读documentation

    编辑:修复了评论中报告的问题,问题是 f 有时是 returned int 有时是 float,而它应该始终是 return float

    【讨论】:

    • 我用不同的二维数组尝试了你的解决方案,如果第一个值 = 1 则发现问题示例:data = np.array([[0.02,0,0.1,1],[1,0.05 ,0,0.01]]) [[0.17426108 0.25596603 0. 1. ] [1. 0. 0.29732222 0.23448857]] 数据 = np.array([[1,0,0.1,1],[1,0.05,0,0.01]]) [[1 0 0 1] [1 0 0 0]]跨度>
    • vectorize 执行试算以确定返回 dtype。要跳过该定义 otypes 参数。如果您必须在多维数组上使用标量函数,vectorize 会很方便,但它很慢 - 比更显式的 Python 迭代要慢。
    【解决方案2】:

    我认为nditer 需要更强有力的免责声明。对于初学者来说,这不是一个好的迭代工具。正确使用很棘手,而且不是特别快。这个 Python 版本确实是在编译代码中使用它的垫脚石,如 nditer 主页面末尾的 cython 示例所示:

    https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html

    有更快的方法来进行这种数组计算,但我会尝试解释为什么你的nditer 不起作用。

    问题在于基本的 Python 迭代。在循环中:

    alist = [0,0,0]
    for element in alist:
        element = 1
    

    alist 未修改。 element=1 只是重新分配 element 变量,但不修改迭代变量本身。相反,如果可能的话,你已经改变了 element 本身。

    对于nditer,迭代变量本身就是ndarray,并且是可变的:

    In [69]: smatrix = np.zeros((2,2),int)                                          
    In [70]: with np.nditer(smatrix, op_flags=['readwrite']) as it: 
        ...:     for element in it: 
        ...:         print(element, type(element)) 
        ...:         element[...] = 1 
        ...:                                                                        
    0 <class 'numpy.ndarray'>
    0 <class 'numpy.ndarray'>
    0 <class 'numpy.ndarray'>
    0 <class 'numpy.ndarray'>
    In [71]: smatrix                                                                
    Out[71]: 
    array([[1, 1],
           [1, 1]])
    

    如果不清楚,请仔细查看https://docs.scipy.org/doc/numpy/reference/generated/numpy.nditer.html 中的示例。注意使用out 参数和x[:] = [-1, -2, -3] 之类的表达式。

    如果关于变异变量的讨论令人困惑,这很好地表明 nditer 在这一点上是一个过于先进的工具。

    【讨论】:

      猜你喜欢
      • 2020-12-05
      • 2011-08-22
      • 1970-01-01
      • 2013-01-10
      • 2017-11-02
      • 2021-10-25
      • 2022-01-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多