NumPy阵列 - 改变所有入口

时间:2017-10-22 21:16:43

标签: arrays python-3.x numpy normalization

我正在编写一个函数,它接受一个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

不幸的是它不起作用,因为返回的数组没有改变。我该如何修理?

4 个答案:

答案 0 :(得分:2)

在任何Python迭代中,

for x in np.nditer(A):
    x = (x - minimum)/(maximum - minimum)

为迭代变量赋值会更改其引用,并且不会修改原始列表/数组。

我试过

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以了解如何将其更改为读/写变量

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教程页面所示,它在nditer中使用cython作为踏脚石非常有用。

您的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数组,允许对其进行修改。但这使得它与最小/最大值(可能是数组)一起使用变得复杂。我们必须在nditer设置中包含这些数组。所以它是可能的,但通常不值得额外的工作。

答案 1 :(得分:1)

xx=function(arg){
  var=quo(arg)
  #print(var)
  df1=df %>%
    select(trust09, !!!quos(arg)) %>%
    group_by(trust09) %>%
    filter_(.dots=paste0(arg,'==','4|',arg,'== 5'))%>%
    summarise(length(!!var))
  return(df1)
}



xx('q16a')

<quosure: frame>
~arg
# A tibble: 2 x 2
  trust09 `length(arg)`
    <chr>         <int>
1     5A3             1
2     TAN             1

或者,对于就地数组规范化,请参阅this answer

答案 2 :(得分:1)

为什么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)

答案 3 :(得分:1)

一种方法:就地修改而不创建新的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数组的所有元素的最小值/最大值感兴趣,这就是你的默认轴为None的原因。如@hpaulj为nditer所解释的那样,轴的其他值不会使用除非以外的轴的ndenumerate。如果你想使用其他轴,我建议使用上面的方法1。