NumPy 数组 - 改变所有入口
NumPy Array - changing all the entrances
我正在编写一个函数,该函数采用 NumPy 数组并进行规范化。我写了下面的内容:
def normalize_min_max(A, axis = None):
ptr = axis
minimum = np.amin(A, ptr)
maximum = np.amax(A, ptr)
for x in np.nditer(A):
x = (x - minimum)/(maximum - minimum)
return A
不幸的是它不起作用,因为返回的数组没有改变。我该如何修复它?
return [(x - minimum)/(maximum - minimum) for x in np.nditer(A)]
或者,对于就地数组规范化,请参阅 this answer。
为什么 for
循环?这是一个带有一些轴技巧的矢量化解决方案,以确保形状与输入轴对齐:
def normalize_min_max(A, axis=None):
A = np.asarray(A)
A_min = A.min(axis=axis)
A = (np.rollaxis(A, (0 if axis is None else axis)) - A_min) / (A.max(axis=axis) - A_min)
return np.rollaxis(A, (0 if axis is None else axis))
一些结果:
In[175]: a = np.arange(4*3, dtype='float32').reshape(4, 3)
In[176]: a
Out[176]:
array([[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.],
[ 9., 10., 11.]], dtype=float32)
In[177]: normalize_min_max(a, None)
Out[177]:
array([[ 0. , 0.09090909, 0.18181819],
[ 0.27272728, 0.36363637, 0.45454547],
[ 0.54545456, 0.63636363, 0.72727275],
[ 0.81818181, 0.90909094, 1. ]], dtype=float32)
In[178]: normalize_min_max(a, 0)
Out[178]:
array([[ 0. , 0. , 0. ],
[ 0.33333334, 0.33333334, 0.33333334],
[ 0.66666669, 0.66666669, 0.66666669],
[ 1. , 1. , 1. ]], dtype=float32)
In[179]: normalize_min_max(a, 1)
Out[179]:
array([[ 0. , 0.5, 1. ],
[ 0. , 0.5, 1. ],
[ 0. , 0.5, 1. ],
[ 0. , 0.5, 1. ]], dtype=float32)
在任何 Python 迭代中,
for x in np.nditer(A):
x = (x - minimum)/(maximum - minimum)
给迭代变量赋值会改变它的引用,并不会修改原来的list/array。
我试过了
for x in np.nditer(A):
x[:] = (x - minimum)/(maximum - minimum)
但出现错误
ValueError: assignment destination is read-only
我必须转到 nditer
文档,https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.nditer.html#arrays-nditer 了解如何将其更改为 read/write 变量
In [388]: def normalize_min_max(A, axis = None):
...: ptr = axis
...: minimum = np.amin(A, ptr)
...: maximum = np.amax(A, ptr)
...: for x in np.nditer(A, op_flags=['readwrite']):
...: x[...] = (x - minimum)/(maximum - minimum)
...: return A
...:
...:
In [389]: normalize_min_max(np.arange(10))
Out[389]: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
糟糕,原来的数组是整数
In [390]: normalize_min_max(np.arange(10.))
Out[390]:
array([ 0. , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
0.55555556, 0.66666667, 0.77777778, 0.88888889, 1. ])
但我不需要迭代来执行这种计算:
In [391]: def normalize_min_max1(A, axis = None):
...: ptr = axis
...: minimum = np.amin(A, ptr, keepdims=True)
...: maximum = np.amax(A, ptr, keepdims=True)
...: return (A-minimum)/(maximum-minimum)
In [392]: normalize_min_max1(np.arange(10.))
Out[392]:
array([ 0. , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
0.55555556, 0.66666667, 0.77777778, 0.88888889, 1. ])
nditer
在这种情况下确实有效,因为迭代变量是可修改的,而 for x in A: ...
则不能。但除此之外,它是一个复杂的迭代器,并且不提供任何速度优势。如 nditer
教程页面所示,它最适合作为在 cython
中使用 nditer
的垫脚石。
您的 nditer
代码也不适用于轴值。我的 keep_dims
参数有效:
In [396]: normalize_min_max1(np.arange(10.).reshape(5,2),0)
Out[396]:
array([[ 0. , 0. ],
[ 0.25, 0.25],
[ 0.5 , 0.5 ],
[ 0.75, 0.75],
[ 1. , 1. ]])
In [397]: normalize_min_max1(np.arange(10.).reshape(5,2),1)
Out[397]:
array([[ 0., 1.],
[ 0., 1.],
[ 0., 1.],
[ 0., 1.],
[ 0., 1.]])
In [398]: normalize_min_max1(np.arange(10.).reshape(5,2),None)
Out[398]:
array([[ 0. , 0.11111111],
[ 0.22222222, 0.33333333],
[ 0.44444444, 0.55555556],
[ 0.66666667, 0.77777778],
[ 0.88888889, 1. ]])
带有轴值的nditer
代码:
In [395]: normalize_min_max(np.arange(10.).reshape(5,2),0)
...
ValueError: could not broadcast input array from shape (2) into shape ()
nditer
变量是0d数组,允许修改。但这会使它与可能是数组的 min/max 值一起使用变得复杂。我们必须将这些数组包含在 nditer
设置中。所以这是可能的,但通常不值得额外的工作。
一种方法:原地修改而不创建新的Numpy数组
import numpy as np
def normalize_min_max(A, axis = None):
ptr = axis
minimum = np.amin(A, ptr)
maximum = np.amax(A, ptr)
A = (A - minimum)/(maximum - minimum)
return A
np_array = np.array([[1,2, 3,4],[2,3,4,5]]) # example input
print(normalize_min_max(np_array))
输出:
[[ 0. 0.25 0.5 0.75]
[ 0.25 0.5 0.75 1. ]]
**第二种方法(您的风格):创建与输入数组具有相同形状的新 Numpy 数组,并将标准化值存储在那里**
import numpy as np
def normalize_min_max(A, axis = None):
ptr = axis
norm_A = np.empty(A.shape)
minimum = np.amin(A, ptr)
maximum = np.amax(A, ptr)
delta = maximum - minimum
for indx, x in np.ndenumerate(A):
norm_A[indx] = (x - minimum)/delta
return norm_A
np_array = np.array([[1,2, 3,4], [2,3,4,5]])
print(normalize_min_max(np_array))
输出:
[[ 0. 0.25 0.5 0.75]
[ 0.25 0.5 0.75 1. ]]
注意:我假设您只对 Numpy 数组所有元素的 min/max 感兴趣,这就是为什么您的默认轴是 None。正如@hpaulj 对 nditer 所解释的那样,轴的其他值不适用于 None 以外的轴的 ndenumerate。如果你想使用其他轴,我建议使用上面的方法 1。
我正在编写一个函数,该函数采用 NumPy 数组并进行规范化。我写了下面的内容:
def normalize_min_max(A, axis = None):
ptr = axis
minimum = np.amin(A, ptr)
maximum = np.amax(A, ptr)
for x in np.nditer(A):
x = (x - minimum)/(maximum - minimum)
return A
不幸的是它不起作用,因为返回的数组没有改变。我该如何修复它?
return [(x - minimum)/(maximum - minimum) for x in np.nditer(A)]
或者,对于就地数组规范化,请参阅 this answer。
为什么 for
循环?这是一个带有一些轴技巧的矢量化解决方案,以确保形状与输入轴对齐:
def normalize_min_max(A, axis=None):
A = np.asarray(A)
A_min = A.min(axis=axis)
A = (np.rollaxis(A, (0 if axis is None else axis)) - A_min) / (A.max(axis=axis) - A_min)
return np.rollaxis(A, (0 if axis is None else axis))
一些结果:
In[175]: a = np.arange(4*3, dtype='float32').reshape(4, 3)
In[176]: a
Out[176]:
array([[ 0., 1., 2.],
[ 3., 4., 5.],
[ 6., 7., 8.],
[ 9., 10., 11.]], dtype=float32)
In[177]: normalize_min_max(a, None)
Out[177]:
array([[ 0. , 0.09090909, 0.18181819],
[ 0.27272728, 0.36363637, 0.45454547],
[ 0.54545456, 0.63636363, 0.72727275],
[ 0.81818181, 0.90909094, 1. ]], dtype=float32)
In[178]: normalize_min_max(a, 0)
Out[178]:
array([[ 0. , 0. , 0. ],
[ 0.33333334, 0.33333334, 0.33333334],
[ 0.66666669, 0.66666669, 0.66666669],
[ 1. , 1. , 1. ]], dtype=float32)
In[179]: normalize_min_max(a, 1)
Out[179]:
array([[ 0. , 0.5, 1. ],
[ 0. , 0.5, 1. ],
[ 0. , 0.5, 1. ],
[ 0. , 0.5, 1. ]], dtype=float32)
在任何 Python 迭代中,
for x in np.nditer(A):
x = (x - minimum)/(maximum - minimum)
给迭代变量赋值会改变它的引用,并不会修改原来的list/array。
我试过了
for x in np.nditer(A):
x[:] = (x - minimum)/(maximum - minimum)
但出现错误
ValueError: assignment destination is read-only
我必须转到 nditer
文档,https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.nditer.html#arrays-nditer 了解如何将其更改为 read/write 变量
In [388]: def normalize_min_max(A, axis = None):
...: ptr = axis
...: minimum = np.amin(A, ptr)
...: maximum = np.amax(A, ptr)
...: for x in np.nditer(A, op_flags=['readwrite']):
...: x[...] = (x - minimum)/(maximum - minimum)
...: return A
...:
...:
In [389]: normalize_min_max(np.arange(10))
Out[389]: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
糟糕,原来的数组是整数
In [390]: normalize_min_max(np.arange(10.))
Out[390]:
array([ 0. , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
0.55555556, 0.66666667, 0.77777778, 0.88888889, 1. ])
但我不需要迭代来执行这种计算:
In [391]: def normalize_min_max1(A, axis = None):
...: ptr = axis
...: minimum = np.amin(A, ptr, keepdims=True)
...: maximum = np.amax(A, ptr, keepdims=True)
...: return (A-minimum)/(maximum-minimum)
In [392]: normalize_min_max1(np.arange(10.))
Out[392]:
array([ 0. , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
0.55555556, 0.66666667, 0.77777778, 0.88888889, 1. ])
nditer
在这种情况下确实有效,因为迭代变量是可修改的,而 for x in A: ...
则不能。但除此之外,它是一个复杂的迭代器,并且不提供任何速度优势。如 nditer
教程页面所示,它最适合作为在 cython
中使用 nditer
的垫脚石。
您的 nditer
代码也不适用于轴值。我的 keep_dims
参数有效:
In [396]: normalize_min_max1(np.arange(10.).reshape(5,2),0)
Out[396]:
array([[ 0. , 0. ],
[ 0.25, 0.25],
[ 0.5 , 0.5 ],
[ 0.75, 0.75],
[ 1. , 1. ]])
In [397]: normalize_min_max1(np.arange(10.).reshape(5,2),1)
Out[397]:
array([[ 0., 1.],
[ 0., 1.],
[ 0., 1.],
[ 0., 1.],
[ 0., 1.]])
In [398]: normalize_min_max1(np.arange(10.).reshape(5,2),None)
Out[398]:
array([[ 0. , 0.11111111],
[ 0.22222222, 0.33333333],
[ 0.44444444, 0.55555556],
[ 0.66666667, 0.77777778],
[ 0.88888889, 1. ]])
带有轴值的nditer
代码:
In [395]: normalize_min_max(np.arange(10.).reshape(5,2),0)
...
ValueError: could not broadcast input array from shape (2) into shape ()
nditer
变量是0d数组,允许修改。但这会使它与可能是数组的 min/max 值一起使用变得复杂。我们必须将这些数组包含在 nditer
设置中。所以这是可能的,但通常不值得额外的工作。
一种方法:原地修改而不创建新的Numpy数组
import numpy as np
def normalize_min_max(A, axis = None):
ptr = axis
minimum = np.amin(A, ptr)
maximum = np.amax(A, ptr)
A = (A - minimum)/(maximum - minimum)
return A
np_array = np.array([[1,2, 3,4],[2,3,4,5]]) # example input
print(normalize_min_max(np_array))
输出:
[[ 0. 0.25 0.5 0.75]
[ 0.25 0.5 0.75 1. ]]
**第二种方法(您的风格):创建与输入数组具有相同形状的新 Numpy 数组,并将标准化值存储在那里**
import numpy as np
def normalize_min_max(A, axis = None):
ptr = axis
norm_A = np.empty(A.shape)
minimum = np.amin(A, ptr)
maximum = np.amax(A, ptr)
delta = maximum - minimum
for indx, x in np.ndenumerate(A):
norm_A[indx] = (x - minimum)/delta
return norm_A
np_array = np.array([[1,2, 3,4], [2,3,4,5]])
print(normalize_min_max(np_array))
输出:
[[ 0. 0.25 0.5 0.75]
[ 0.25 0.5 0.75 1. ]]
注意:我假设您只对 Numpy 数组所有元素的 min/max 感兴趣,这就是为什么您的默认轴是 None。正如@hpaulj 对 nditer 所解释的那样,轴的其他值不适用于 None 以外的轴的 ndenumerate。如果你想使用其他轴,我建议使用上面的方法 1。