用numpy中的nditer遍历矩阵中的元素

问题由来:

遍历数组时,通常的做法是采用多层for循环嵌套,例如对于一个三维数组,则采用三个for循环进行遍历。但是,这种做法对于高维度矩阵执行力下降。

另外,还有种做法是先把多维度数组展平,操作完后再还原成原来的数组。

这里介绍另一种方法,即用numpy提供的nditer进行迭代。

步骤为:

1、初始化迭代器

it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])

以上x是要被遍历的矩阵,flags为指定是否为多维度迭代器,针对数组;op_flags为指定对迭代器进行读写操作。注意这里字符要用中括号括起来。

2、使用迭代器进行循环

while not it.finished:

        idx = it.multi_index

        ...

        it.iternext()

这里it.finished返回一个bool值,即当迭代至最后一个元素时为True,其他情况为false

it.multi_index 返回当前迭代的数组的索引  

it.iternext()为对索引进行更新,类似 idx +=1

以下为一个简单的例子

import numpy as np

if __name__ == '__main__':
    a = np.array([[[1, 2, 3], [4, 5, 6]]])

    it = np.nditer(a, flags=['multi_index'], op_flags=['readwrite'])

    while not it.finished:
        print(it.multi_index)
        it.iternext()

运行结果:

用以上遍历方法编写一个数值方法(中心差分法)求梯度的函数,并用该方法求解y = x^2 + y ^2 + z ^2 的最小值

import numpy as np


def grad_numerical(f, x):
    """
    用数值方法(中心差分法)计算函数f在x处的梯度
    :param f: 函数句柄
    :param x: 自变量
    :return: 梯度grad
    """
    # 创建数组迭代器
    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    x = np.array(x, dtype=np.float64)  # 把x转换成numpy数组的float64类型
    # 循环计算每个元素的梯度
    h = 1e-4  # x的微小变量
    grads = np.zeros_like(x)  # 梯度的形状和自变量的形状相同
    while not it.finished:
        idx = it.multi_index
        temp = x[idx]
        # 计算f(x + h)
        x[idx] = temp + h
        f_h1 = f(x[idx])
        # 计算f(x - h)
        x[idx] = temp - h
        f_h2 = f(x[idx])

        # 还原x[idx]
        x[idx] = temp

        # 中心差分法计算梯度 g = (f(x + h) - f(x - h))/2h
        grads[idx] = (f_h1 - f_h2) / (2.0 * h)

        # 迭代索引更新
        it.iternext()

    return grads

if __name__ == '__main__':
    # 用梯度下降法计算f = x^2 + y^2 + z^2 的最小值
    iter_num = 100  # 迭代次数
    lr = 0.1  # 学习率

    f = lambda x: np.sum(x ** 2)

    # 初始值
    x0 = np.array([1., -2., 3.])

    for i in range(iter_num):
        grad = grad_numerical(f, x0)
        x0 -= lr * grad

        if i % 10 == 0:  # 每10次返回一次迭代结果
            y = f(x0)
            print(f'第{i}次迭代函数值为{y}, 对应自变量为{x0}')

当然,也可用最前面提到的第二种方法,即将数据展平成1维后再reshape:

import numpy as np


def grad_numerical1(f, x):
    """
    用数值方法(中心差分法)计算函数f在x处的梯度
    :param f: 函数句柄
    :param x: 自变量
    :return: 梯度grad
    """

    x = np.array(x, dtype=np.float64)  # 把x转换成numpy数组的float64类型
    x_shape = x.shape
    x_len = x.size

    x_iter = x.reshape(-1)
    grads = np.zeros_like(x_iter)  # 初始化梯度
    # 循环计算每个元素的梯度
    h = 1e-4  # x的微小变量
    for idx in range(x_len):
        temp = x_iter[idx]
        # 计算f(x + h)
        x_iter[idx] = temp + h
        f_h1 = f(x_iter[idx])
        # 计算f(x - h)
        x_iter[idx] = temp - h
        f_h2 = f(x_iter[idx])

        # 还原x[idx]
        x_iter[idx] = temp

        # 中心差分法计算梯度g = (f(x + h) - f(x - h)) / 2h
        grads[idx] = (f_h1 - f_h2) / (2.0 * h)

    grads = grads.reshape(x_shape)
    return grads

if __name__ == '__main__':
    # 用梯度下降法计算f = x^2 + y^2 + z^2的最小值
    iter_num = 100  # 迭代次数
    lr = 0.1  # 学习率

    f = lambda x: np.sum(x ** 2)

    # 初始值
    x0 = np.array([1., -2., 3.])

    for i in range(iter_num):
        grad = grad_numerical(f, x0)
        x0 -= lr * grad

        if i % 10 == 0:  # 每10次返回一次迭代结果
            y = f(x0)
            print(f'第{i}次迭代函数值为{y}, 对应自变量为{x0}')

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值