Numpy高级应用

数组重塑

reshape

无需复制任何数据,数组就能从一个形状转换成另一个形状。 ——向数组的实例方法reshape传入一个表示新形状的元组

ravel 散开 flatten 扁平化

注意: ravel不会产生源数据的副本,相反,flatten总是返回数据的副本。

数组的合并和拆分

np.concatenate() np.vstack() np.hstack()

In [2]: import numpy as np

In [3]: arr1 = np.array([[1,2,3],[4,5,6]])

In [4]: arr2 = np.array([[7,8,9],[10,11,12]])

In [5]: np.concatenate([arr1,arr2], axis=0)
Out[5]:
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])

In [6]: np.vstack((arr1,arr2))
Out[6]:
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])

In [7]: np.concatenate([arr1,arr2], axis=1)
Out[7]:
array([[ 1,  2,  3,  7,  8,  9],
       [ 4,  5,  6, 10, 11, 12]])

In [8]: np.hstack((arr1,arr2))
Out[8]:
array([[ 1,  2,  3,  7,  8,  9],
       [ 4,  5,  6, 10, 11, 12]])

split :沿指定轴在指定的位置拆分数组。

In [19]: from numpy.random import randn

In [20]: arr = randn(5,2)

In [21]: arr
Out[21]:
array([[-0.24213657,  0.7912939 ],
       [-1.93341047, -0.090163  ],
       [-1.44827594, -0.77660436],
       [-0.35056947,  0.96571127],
       [ 1.02953072,  1.4517834 ]])

In [22]: first, second, third = np.split(arr,[1,3])

In [23]: first
Out[23]: array([[-0.24213657,  0.7912939 ]])

In [24]: second
Out[24]:
array([[-1.93341047, -0.090163  ],
       [-1.44827594, -0.77660436]])

In [25]: third
Out[25]:
array([[-0.35056947,  0.96571127],
       [ 1.02953072,  1.4517834 ]])
函数 说明
concatenate 最一般化的连接,沿一条轴连接一组数组
vstack、row_stack 以面对行的方式对数组进行堆叠(沿轴0)
hstack 以面对列的方式对数组进行堆叠(沿轴1)
column_stack 类似于hstack,但是会先将一维数组转换为二维列向量
dstack 以面向深度的方式对数组进行堆叠(沿轴2)
split 沿指定轴在指定位置拆分数组
hsplit、vsplit、dsplit split的便捷化函数,分别沿轴0、1、2进行拆分

广播(broadcasting)

# 乘法运算中,标量值4被广播到了其他所有的元素上。
In [4]: arr = np.arange(5)

In [5]: arr
Out[5]: array([0, 1, 2, 3, 4])

In [6]: arr * 4
Out[6]: array([ 0,  4,  8, 12, 16])

# 通过减去列平均值的方式对数组的每一列进行距平化处理。
In [7]: arr = np.random.randn(4,3)

In [8]: arr
Out[8]:
array([[-0.02670178,  0.35390654,  2.55570361],
       [ 0.31655488,  0.84301258,  0.91673203],
       [-0.86669646,  0.50996979, -0.45762143],
       [-0.50018861, -0.12417934,  1.28628869]])

In [9]: arr.mean(0)
Out[9]: array([-0.26925799,  0.39567739,  1.07527573])

# 一维数组在轴0上的广播(列,按行进行)
In [10]: demeaned = arr - arr.mean(0)

In [11]: demeaned
Out[11]:
array([[ 0.24255621, -0.04177085,  1.48042789],
       [ 0.58581288,  0.44733519, -0.1585437 ],
       [-0.59743847,  0.11429239, -1.53289716],
       [-0.23093062, -0.51985673,  0.21101297]])

In [12]: demeaned.mean(0)
Out[12]: array([  0.00000000e+00,   2.77555756e-17,   1.11022302e-16])


In [17]: arr
Out[17]:
array([[-0.02670178,  0.35390654,  2.55570361],
       [ 0.31655488,  0.84301258,  0.91673203],
       [-0.86669646,  0.50996979, -0.45762143],
       [-0.50018861, -0.12417934,  1.28628869]])

In [18]: row_means = arr.mean(1)

In [19]: row_means
Out[19]: array([ 0.96096946,  0.69209983, -0.27144937,  0.22064025])

In [20]: row_means.reshape((4,1))
Out[20]:
array([[ 0.96096946],
       [ 0.69209983],
       [-0.27144937],
       [ 0.22064025]])

# 在轴1上做减法(即各行减去平均值)
In [21]: demeaned = arr - row_means.reshape((4,1))

In [22]: demeaned.mean(1)
Out[22]:
array([  0.00000000e+00,   0.00000000e+00,   3.70074342e-17,
         0.00000000e+00])

广播的原则如果两个数组的后缘维度的轴长相符或其中一方的长度为1,则认为它们是广播兼容的。广播会在++缺失或长度为1++的维度上进行。

沿其他轴向广播

根据广播的原则,较小数组的“广播维”必须为1。


普遍的问题:需要专门为了广播添加一个长度为1的新轴。reshape插入轴需要构造一个表示新形状的元组。

因此,Numpy数组提供了一种通过索引机制插入轴的特殊语法:np.newaxis属性以及“全”切片。

In [22]: arr = np.zeros((4,4))

In [23]: arr
Out[23]:
array([[ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.]])

In [24]: arr_3d = arr[:,np.newaxis,:]

In [25]: arr_3d.shape
Out[25]: (4L, 1L, 4L)

In [26]: arr_3d
Out[26]:
array([[[ 0.,  0.,  0.,  0.]],

       [[ 0.,  0.,  0.,  0.]],

       [[ 0.,  0.,  0.,  0.]],

       [[ 0.,  0.,  0.,  0.]]])

例子:对三维数组对轴二进行距平化

In [1]: import numpy as np

In [2]: arr = np.random.randn(3,4,5)

In [3]: depth_means = arr.mean(2)

In [4]: depth_means
Out[4]:
array([[ 0.8264348 ,  0.42729857, -0.70614215,  0.41029565],
       [ 0.04613014, -0.29223305,  0.1984838 ,  0.30052865],
       [-0.44228584, -0.50591049,  0.25722958, -0.00410482]])

In [5]: demeaned = arr - depth_means[:,:,np.newaxis]

In [6]: demeaned.mean(2)
Out[6]:
array([[ -1.33226763e-16,   4.44089210e-17,  -2.22044605e-17,
         -2.22044605e-17],
       [  0.00000000e+00,   4.44089210e-17,  -4.44089210e-17,
         -2.22044605e-17],
       [  0.00000000e+00,   4.44089210e-17,  -2.22044605e-17,
         -8.88178420e-17]])

对指定轴进行距平化的一种通用又不牺牲性能的方法:

def demean_axis(arr, axis=0):
    means = arr.mean(axis)

    #下面的类似于N维的[:,:,np.newaxis]
    indexer = [slice(None)] * arr.ndim
    indexer[axis] = np.newaxis
    return arr - means(indexer)

通过广播设置数组的值

In [11]: arr = np.zeros((4,3))

In [12]: arr[:] = 5

In [13]: arr
Out[13]:
array([[ 5.,  5.,  5.],
       [ 5.,  5.,  5.],
       [ 5.,  5.,  5.],
       [ 5.,  5.,  5.]])

In [14]: col = np.array([1.28,-0.42,0.44,1.6])

In [15]: arr[:] = col[:,np.newaxis]

In [16]: arr
Out[16]:
array([[ 1.28,  1.28,  1.28],
       [-0.42, -0.42, -0.42],
       [ 0.44,  0.44,  0.44],
       [ 1.6 ,  1.6 ,  1.6 ]])

In [17]: arr[:2] = [[-1.37],[0.59]]

In [18]: arr
Out[18]:
array([[-1.37, -1.37, -1.37],
       [ 0.59,  0.59,  0.59],
       [ 0.44,  0.44,  0.44],
       [ 1.6 ,  1.6 ,  1.6 ]])

ufunc高级应用:执行矢量化的特殊方法

方法 说明
reduce(x) 通过连续执行原始运算的方式对值进行聚合
accumulate(x) 聚合值,保留所有局部聚合结果
reduceat(x,bins) “局部”约简(也就是groupby)。约减数据的各个切片以产生聚合型数组
outer(x,y) 对x,y的每对原始应用原始运算。结果数组的形状为x.shape + y.shape

例子:

arr = np.arange(10)
np.add.reduce(arr)  #45

np.add.accumulate(arr1, axis=1) # 产生一个跟原始数组大小相同的中间“累计”值数组

np.multiply.outer(arr2, np.arange(5)) #计算两个数组的叉积

np.add.reduceat(arr3, [0,5,8]) #计算局部约简,接受一组用于指示如何对值进行拆分和聚合的“边界”

结构化和记录式数组

结构化数组是一种特殊的ndarray。用于表示异质或表格型的数据。

定义结构化dtype, 典型方法是元组列表,各个元组的格式为(field_name, field_data_type)。

In [1]: import numpy as np

In [2]: dtype = [('x', np.float64), ('y', np.int32)]

In [3]: sarr = np.array([(1.5,6),(np.pi,-2)],dtype=dtype)

In [4]: sarr
Out[4]:
array([(1.5, 6), (3.141592653589793, -2)],
      dtype=[('x', '), ('y', ')])

In [5]: sarr[0]
Out[5]: (1.5, 6)

In [6]: sarr[0]['y']
Out[6]: 6

In [7]: sarr['x']
Out[7]: array([ 1.5       ,  3.14159265])

嵌套dtype和多维字段

In [13]: dtype = [('x', [('a', 'f8'), ('b', 'f4')]), ('y', np.int32)]

In [14]: arr = np.array([((1,2),5), ((3,4),6)])

In [15]: arr = np.array([((1,2),5), ((3,4),6)], dtype=dtype)

In [16]: arr['x']
Out[16]:
array([(1.0, 2.0), (3.0, 4.0)],
      dtype=[('a', '), ('b', ')])

In [17]: arr['y']
Out[17]: array([5, 6], dtype=int32)

In [18]: arr['x']['a']
Out[18]: array([ 1.,  3.])

结构化数组操作:numpy.lib.recfunctions

一般都需要创建一个新数组以便对dtype进行修改。

排序

跟Python内置的列表一样,ndarray的sort实例方法也是就地排序。
但是,numpy.sort会为原数组创建一个已排序副本。

两个排序方法(np.sort(arr) and arr.sort())都可以接受一个axis参数,以便沿指定轴向对各块数据进行单独排序。

间接排序

arr.argsort() and numpy.lexsort(): 索引值说明了数据在新顺序下的位置。

注: Series和DataFrame的sort_index以及Series的order方法就是通过这些函数的变体实现的。

其他排序算法

mergesort是稳定排序,会保持定价元素的相对位置。

numpy.searchsorted 在有序数组中查找元素

返回插入位置,保持数组有序。

In [21]: arr = np.array([0,1,4,7,9,24,64])

In [22]: arr.searchsorted(8)
Out[22]: 4

In [23]: arr.searchsorted([0,8,11,16])
Out[23]: array([0, 4, 5, 5])

用边界数组拆分数据数组

In [24]: from pandas import Series

In [25]: data  = np.floor(np.random.uniform(0,10000,size=50))

In [26]: bins = np.array([0,100,1000,5000,10000])

In [27]: data
Out[27]:
array([ 8795.,  3572.,  8139.,  8369.,  6866.,  4000.,  4320.,   185.,
        7171.,  7183.,  7554.,  2747.,  8301.,   508.,  6789.,  5572.,
        4647.,  1800.,  6617.,  7725.,  8510.,  6242.,  3087.,  9541.,
        4456.,  9974.,  7493.,  4238.,  6600.,  2291.,  5139.,  5193.,
        5226.,  6799.,  1689.,  3912.,  5704.,  7168.,  8418.,  9963.,
        2454.,  7647.,   718.,  5830.,  6241.,  6469.,  3005.,  7537.,
        6170.,  4417.])

In [28]: lables = bins.searchsorted(data)

In [29]: lables
Out[29]:
array([4, 3, 4, 4, 4, 3, 3, 2, 4, 4, 4, 3, 4, 2, 4, 4, 3, 3, 4, 4, 4, 4, 3,
       4, 3, 4, 4, 3, 4, 3, 4, 4, 4, 4, 3, 3, 4, 4, 4, 4, 3, 4, 2, 4, 4, 4,
       3, 4, 4, 3])

In [30]: np.digitize(data, bins)
Out[30]:
array([4, 3, 4, 4, 4, 3, 3, 2, 4, 4, 4, 3, 4, 2, 4, 4, 3, 3, 4, 4, 4, 4, 3,
       4, 3, 4, 4, 3, 4, 3, 4, 4, 4, 4, 3, 3, 4, 4, 4, 4, 3, 4, 2, 4, 4, 4,
       3, 4, 4, 3])

In [31]: Series(data).groupby(lables).mean()
Out[31]:
2     470.333333
3    3375.666667
4    7217.031250
dtype: float64

性能建议

  • 将Python循环和条件逻辑转换为数组运算布尔数组运算
  • 尽量使用广播
  • 避免复制数据,尽量使用数组视图(切片

参考《Python for Data Analysis》

你可能感兴趣的:(numpy,数据分析)