pydata

Keep Looking, Don't Settle

Numpy Introduction 02

Summary: this is the introduction and summary of numpy array/matrix manipulation. Some are with very detailed explaination which I think is more detailed than the numpy document.

In [1]:
import numpy as np

1. 矩阵变形

function 描述
1. ravel 对矩阵的元素进行拉直
2. flat 对矩阵元素拉直,返回一个iterator
3. flatten 拉直矩阵

1.1. np.ravel

np.ravel(a = , order = )flatten非常类似,返回展开的一维数组,并且按需生成副本。返回的数组和输入数组拥有相同数据类型。order也和flatten的用法一样.

In [2]:
x = np.arange(24).reshape(2, 3, 4)
print np.ravel(x, order = "C")
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]

1. 2. np.ndarray.flatten

np.ndarray.flatten(order = )把一个矩阵(matrix,或者叫数组array)转为一个向量。order:是展开的顺序,'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'k' -- 元素在内存中的出现顺序。

In [3]:
x = np.arange(24).reshape(2, 3, 4)
print x.flatten(order = "C")
print x.flatten(order = "F")
print x.flatten(order = "A")
print x.flatten(order = "k")
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
[ 0 12  4 16  8 20  1 13  5 17  9 21  2 14  6 18 10 22  3 15  7 19 11 23]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]

1.3. np.flat

np.flat返回一个矩阵拉直以后的迭代器(iterator)

In [4]:
x = np.arange(1, 7).reshape(2, 3)
x.flat[:]
Out[4]:
array([1, 2, 3, 4, 5, 6])

2. 翻转操作

function 描述
1. transpose 矩阵转置,行变列,列变行
2. rollaxis 矩阵沿着给定的轴滚动,直到指定位置
3. swapaxes 交换轴

2.1. np.transpose or array.T

np.transpose or array.T用来对矩阵进行行和列的转置。

In [5]:
x = np.arange(1, 7).reshape(2, 3)

print "\n 原始矩阵为: \n"
print x

print "\n 转置后的矩阵为: \n"
print np.transpose(x)
 原始矩阵为: 

[[1 2 3]
 [4 5 6]]

 转置后的矩阵为: 

[[1 4]
 [2 5]
 [3 6]]

2.2. np.rollaxis

np.rollaxis(a, axis = , start = )有三个参数,第一个参数a是要进行运算的矩阵,第二个参数axis是要被移动的轴,第三个参数start是把第二个参数放到哪儿。根据函数的说明文档,是把第二个参数放到第三个参数之前。

比如说,假如矩阵a的维度为(2, 3, 4), np.rollaxis(a, 0, 3)是把第一个轴(0轴,因为index = 0)放到index = 3之前,也就是index = 2的位置,即把(2, 3, 4)2调到最后,所以输出矩阵就应该是(3, 4, 2)

相应的np.rollaxis(a, 0, 0)np.rollaxis(a, 0, 1)都是一样的结果,因为都是把0轴调到第一个位置,所以应该就是a本身.

np.rollaxis(a, 1, 3)就是把第二个轴(1轴)调到2轴(index = 3之前的轴,所以是index = 2轴,即第三轴).所以输出应该是(2, 4, 3)

In [6]:
x = np.arange(24).reshape(2, 3, 4)

print '把0轴放到0轴之前,所以还是原来的矩阵x: ' + str(np.rollaxis(x, 0, 0).shape)
print '把0轴放到1轴之前,还是0轴,所以还是原来的矩阵x: ' + str(np.rollaxis(x, 0, 1).shape)
print '把0轴放到2轴之前,所以2和3交换位置: ' + str(np.rollaxis(x, 0, 2).shape)
print '把0轴放到3轴之前,所以2到了最后: ' + str(np.rollaxis(x, 0, 3).shape)
print '把1轴放到3轴之前,所以3到了最后: ' + str(np.rollaxis(x, 1, 3).shape)
把0轴放到0轴之前,所以还是原来的矩阵x: (2L, 3L, 4L)
把0轴放到1轴之前,还是0轴,所以还是原来的矩阵x: (2L, 3L, 4L)
把0轴放到2轴之前,所以2和3交换位置: (3L, 2L, 4L)
把0轴放到3轴之前,所以2到了最后: (3L, 4L, 2L)
把1轴放到3轴之前,所以3到了最后: (2L, 4L, 3L)

2.3. np.swapaxes

np.swapaxes比较直观,就是把两个轴对换一下

In [7]:
x = np.arange(24).reshape(2, 3, 4)
print np.swapaxes(x, 1, 2).shape
(2L, 4L, 3L)

3. 元素重排

function 描述
1. flip fliplr flipud 对矩阵进行翻转
2. roll 对矩阵的元素进行滚动位移
3. rot90 旋转矩阵

3.1. np.flip np.fliplr np.flipud

np.flip(array, axis), np.fliplr(array), np.flipud(array)均是对矩阵进行翻转操作。

np.flip(array, axis = 0) == np.flipud(array) == array[::-1,...]

np.flip(array, axis = 1) == np.fliplr(array) == array[:,::-1]

In [8]:
x = np.arange(8).reshape((2, 2, 2))

print "原始矩阵为: \n"
print x

print "\n 1. 进行axis=0上的翻转:x[0, :, :]和x[1, :, :]调换位置: \n"
print np.flipud(x) 

print np.all(np.flipud(x) == x[::-1,...])

print "\n 2. 进行axis=1上的翻转: x[:, 0, :]和x[:, 1, :]调换位置: \n"
print np.fliplr(x)
print np.all(np.fliplr(x) == x[:,::-1])
原始矩阵为: 

[[[0 1]
  [2 3]]

 [[4 5]
  [6 7]]]

 1. 进行axis=0上的翻转:x[0, :, :]和x[1, :, :]调换位置: 

[[[4 5]
  [6 7]]

 [[0 1]
  [2 3]]]
True

 2. 进行axis=1上的翻转: x[:, 0, :]和x[:, 1, :]调换位置: 

[[[2 3]
  [0 1]]

 [[6 7]
  [4 5]]]
True

3.2. np.roll

np.roll(array, shift, axis)滚动移位: 移动矩阵元素的位置,或者行/列整体移动

In [9]:
x = np.arange(16).reshape(4, 4)

print "\n 1. 没有axis则进行元素移位,把最后2个元素移到第一个第二个位置 \n"
print np.roll(x, 2)

print "\n 2. axis = 0, 把最后两行整体移到第一行第二行"
print np.roll(x, 2, axis = 0)

print "\n 3. axis = 1, 把最后1列整体移到第一列"
print np.roll(x, 1, axis = 1)
 1. 没有axis则进行元素移位,把最后2个元素移到第一个第二个位置 

[[14 15  0  1]
 [ 2  3  4  5]
 [ 6  7  8  9]
 [10 11 12 13]]

 2. axis = 0, 把最后两行整体移到第一行第二行
[[ 8  9 10 11]
 [12 13 14 15]
 [ 0  1  2  3]
 [ 4  5  6  7]]

 3. axis = 1, 把最后1列整体移到第一列
[[ 3  0  1  2]
 [ 7  4  5  6]
 [11  8  9 10]
 [15 12 13 14]]

3.3. np.rot90

np.rot90(array, k)对矩阵整体进行k次的90度转置.

In [10]:
x = np.arange(6).reshape(2, 3)

print "\n 1. 旋转90度 \n"
print np.rot90(x, 1)

print "\n 2. 再旋转90度 \n"
print np.rot90(x, 2)


print "\n 3. 旋转4个90度,变成了自己 \n"
print np.rot90(x, 4)
 1. 旋转90度 

[[2 5]
 [1 4]
 [0 3]]

 2. 再旋转90度 

[[5 4 3]
 [2 1 0]]

 3. 旋转4个90度,变成了自己 

[[0 1 2]
 [3 4 5]]

4. 修改维度

function 描述
1. broadcast 产生模仿广播的对象
2. broadcast_to 将数组广播到新形状
3. expand_dims 扩展数组的形状
4. squeeze 从数组的形状中删除单维条目

4.1. np.broadcast

np.broadcast()模仿广播机制。 它返回一个broadcast对象,该对象封装了将一个数组广播到另一个数组的结果。

In [11]:
x = np.array([[1], [2], [3]])  # shape = (3, 1)
y = np.array([4, 5, 6])        # shape = (, 3)

# 对 y 广播 x
b = np.broadcast(x,y) 

print b.shape

for (i, j) in b:
    print i, j
(3L, 3L)
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
In [12]:
b = np.broadcast(x,y) 
c = np.empty(b.shape)
c.flat = [i * j for (i, j) in b]
print c
[[  4.   5.   6.]
 [  8.  10.  12.]
 [ 12.  15.  18.]]
In [13]:
print x * y
[[ 4  5  6]
 [ 8 10 12]
 [12 15 18]]

4.2. np.broadcast_to

np.broadcast_to将原始数组广播到给定的新的shape.下面的例子中把shape为(2, 4)的矩阵在0轴上广播了三次.

In [14]:
x = np.arange(8).reshape(2, 4)
print np.broadcast_to(x, (3, 2, 4))
[[[0 1 2 3]
  [4 5 6 7]]

 [[0 1 2 3]
  [4 5 6 7]]

 [[0 1 2 3]
  [4 5 6 7]]]

4.3. np.expand_dims

np.expand_dims(arr, axis) 在原始矩阵上增加一个维度,所以在那个维度上的dim=1,相当于把原来的矩阵整体打包放到新的维度里面了。

In [15]:
x = np.arange(4).reshape(2, 2)

print "原始矩阵的shape: " + str(x.shape) + '\n'

print "在index=0的方向增加一个维度: " + str(np.expand_dims(x, axis = 0).shape) + '\n'

print "np.expand_dims(x, axis = 1) 在index=1增加一个维度,所以现在维度为(2, 1, 2) \n"

np.expand_dims(x, axis = 1)
原始矩阵的shape: (2L, 2L)

在index=0的方向增加一个维度: (1L, 2L, 2L)

np.expand_dims(x, axis = 1) 在index=1增加一个维度,所以现在维度为(2, 1, 2) 

Out[15]:
array([[[0, 1]],

       [[2, 3]]])

4.4. np.squeeze

np.squeeze(arr, axis) 把矩阵dim=1的那个维度或者那些维度去掉

In [16]:
print "\n 1. 输入矩阵维度为(1, 2, 2),squeeze后维度为(2, 2) \n"
x = np.arange(4).reshape(1, 2, 2)
print x.shape
print np.squeeze(x).shape

print "\n 2. 输入矩阵维度为(1, 1, 4),squeeze后维度为(4, ) \n"
x = np.arange(4).reshape(1, 1, 4)
print x.shape
print np.squeeze(x).shape
 1. 输入矩阵维度为(1, 2, 2),squeeze后维度为(2, 2) 

(1L, 2L, 2L)
(2L, 2L)

 2. 输入矩阵维度为(1, 1, 4),squeeze后维度为(4, ) 

(1L, 1L, 4L)
(4L,)

5. 矩阵连接

function 描述
1. concatenate 沿着现存的轴连接数据序列
2. stack 沿着新轴连接数组序列
3. hstack 水平堆叠序列中的数组(列方向)
4. vstack 竖直堆叠序列中的数组(行方向)
5. np.c_[] 水平堆叠序列中的数组(列方向)
6. np.r_[] 竖直堆叠序列中的数组(行方向)

5.1. np.concatenate

np.concatenate((a1, a2, ...), axis) 沿着指定的轴把各个数组连接起来

In [17]:
x = np.arange(12).reshape(3, 4)
y = np.arange(12).reshape(3, 4)
print np.concatenate((x, y), axis = 0).shape
print np.concatenate((x, y), axis = 1).shape
(6L, 4L)
(3L, 8L)

5.2. np.stack

np.stack(arrays, axis) 沿着新轴连接数组,产生多一个轴的数组

下面输入的两个数组shape相同,shape为(3, 4)

np.stack((x, y), axis = 0)沿着axis=0连接两个矩阵,所以产生的新矩阵在axis = 0上维度为2;新的矩阵shape为(2L, 3L, 4L)

np.stack((x, y), axis = 1)沿着axis=1连接两个矩阵,所以产生的新矩阵在axis = 1上维度为2;新的矩阵shape为(3L, 2L, 4L)

In [18]:
x = np.arange(12).reshape(3, 4)
y = np.arange(12).reshape(3, 4)
print np.stack((x, y), axis = 0).shape
print np.stack((x, y), axis = 1).shape
(2L, 3L, 4L)
(3L, 2L, 4L)

5.3. np.vstack

np.vstack((a1, a2, ...))用来竖直连接输入的数组,跟np.r_[]很像。也可以用np.concatenate((a1, a2, ...), axis = 0)来得到。

In [19]:
print np.vstack((x, y))
print "\n this is the same as np.r_[x, y]: \n"
print np.r_[x, y]
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

 this is the same as np.r_[x, y]: 

[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

5.4. np.hstack

np.hstack((a1, a2, ...))用来水平连接输入的数组,跟np.c_[]很像。也可以用np.concatenate((a1, a2, ...), axis = 1)来得到。

In [20]:
print np.hstack((x, y))
print "\n this is the same as np.c_[x, y]: \n"
print np.c_[x, y]
[[ 0  1  2  3  0  1  2  3]
 [ 4  5  6  7  4  5  6  7]
 [ 8  9 10 11  8  9 10 11]]

 this is the same as np.c_[x, y]: 

[[ 0  1  2  3  0  1  2  3]
 [ 4  5  6  7  4  5  6  7]
 [ 8  9 10 11  8  9 10 11]]

5.5. np.r_np.c_

np.r_[]沿着0轴来连接矩阵;

np.c_[]沿着1轴来连接矩阵

In [21]:
np.r_[x.flatten(), [99, 999]]
Out[21]:
array([  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  99, 999])
In [22]:
print x.flatten().shape
np.c_[x.flatten(), np.repeat(99, 12)]
(12L,)
Out[22]:
array([[ 0, 99],
       [ 1, 99],
       [ 2, 99],
       [ 3, 99],
       [ 4, 99],
       [ 5, 99],
       [ 6, 99],
       [ 7, 99],
       [ 8, 99],
       [ 9, 99],
       [10, 99],
       [11, 99]])

6. 矩阵分割

function 描述
1. split 将一个数组分割为多个子数组
2. hsplit 将一个数组水平分割为多个子数组(按列)
3. vsplit 将一个数组竖直分割为多个子数组(按行)

6.1. np.split

np.split(ary, indices_or_sections, axis)沿特定的轴将数组分割为子数组

In [23]:
x = np.arange(12).reshape(3, 4)

res = np.split(x, 2, axis = 1)

print res
[array([[0, 1],
       [4, 5],
       [8, 9]]), array([[ 2,  3],
       [ 6,  7],
       [10, 11]])]

6.2. np.hsplit

np.hsplit = np.split( , , axis = 1). np.hsplit(array, k)k必须能被array.shape[1]整除

In [24]:
np.hsplit(x, 2)
Out[24]:
[array([[0, 1],
        [4, 5],
        [8, 9]]), array([[ 2,  3],
        [ 6,  7],
        [10, 11]])]

6.3. np.hsplit

np.hsplit = np.split( , , axis = 0)

In [25]:
np.vsplit(x, 3)
Out[25]:
[array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]]), array([[ 8,  9, 10, 11]])]

7. 添加/删除元素

function 描述
1. resize 返回指定形状的新数组
2. append 将值添加到数组末尾
3. insert 沿指定轴将值插入到指定下标之前
4. delete 返回删掉某个轴的子数组的新数组
5. unique 寻找数组内的唯一元素

7.1. np.resize

np.resize(array, shape)返回指定大小的新数组矩阵。如果新的矩阵的shape比原来的矩阵大,那么其会自动重复原始矩阵的元素

In [26]:
x = np.arange(12).reshape(3, 4)

print "1. 从(3, 4)resize为(2, 6),这个等价于 `x.reshape(2, 6)`. (3, 4)和(2, 6)的元素个数相等: \n"
print np.resize(x, (2, 6))  

print "\n "
print "2. 从(3, 4)resize为(3, 6), 元素变多,所以原始矩阵的前六个元素被重复使用了: \n"
print np.resize(x, (3, 6))
1. 从(3, 4)resize为(2, 6),这个等价于 `x.reshape(2, 6)`. (3, 4)和(2, 6)的元素个数相等: 

[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]]

 
2. 从(3, 4)resize为(3, 6), 元素变多,所以原始矩阵的前六个元素被重复使用了: 

[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [ 0  1  2  3  4  5]]

7.2. np.append

np.append(array, values, axis)向数组添加元素。如果不带axis参数,那么arrayvalues会先被拉平成向量然后再append。

In [27]:
x = np.arange(8).reshape(2, 4)

print "\n 1. 没有axis参数,被拉直成向量 \n"
print np.append(x, [1, 2, 3, 4])

print "\n 2. 沿着0轴append新的值 \n"
print np.append(x, [[1, 2, 3, 4]], axis = 0)

print "\n 3. 沿着1轴append新的值 \n"
print np.append(x, [[1], [2]], axis = 1)
 1. 没有axis参数,被拉直成向量 

[0 1 2 3 4 5 6 7 1 2 3 4]

 2. 沿着0轴append新的值 

[[0 1 2 3]
 [4 5 6 7]
 [1 2 3 4]]

 3. 沿着1轴append新的值 

[[0 1 2 3 1]
 [4 5 6 7 2]]

. np.insert

np.insert(array, obj, values, axis)在给定的索引(obj)之前,沿着给定的轴(axis)在输入的数组(arr)中插入值(values). 如同np.append,如果没有axis,那么输入的数组会被展开。

In [28]:
x = np.arange(12).reshape(3, 4)

print "\n 1. np.insert(x, 3, [99, 999]): \
\n在index=3之前插入[99, 999], 因为没有axis,所以被展开成向量 \n"
print np.insert(x, 3, [99, 999])

print "\n 2. np.insert(x, 2, [[99, 999, 9999, 99999]], axis = 0): \
\n axis=0,插入新的一行,注意插入的行向量shape是(1, 4) \n"
print np.insert(x, 2, [[99, 999, 9999, 99999]], axis = 0)

print "\n 3. np.insert(x, 3, [99, 999, 9999], axis = 1): \
\n axis=1, 插入新的一列,注意插入的列向量shape是(3, ) \n"
print np.insert(x, 3, [99, 999, 9999], axis = 1)

print "\n 4. np.insert(x, 3, [[99], [999], [9999]], axis = 1): \
\n 如果插入一个shape为(3, 1)的向量,会自动把插入的向量补齐为(3, 3) \n"
print np.insert(x, 3, [[99], [999], [9999]], axis = 1)

print "\n 5. np.insert(x, 3, [9999], axis = 1): \n直接插入一个值的向量,自动补齐 \n"
print np.insert(x, 3, [9999], axis = 1)
 1. np.insert(x, 3, [99, 999]): 
在index=3之前插入[99, 999], 因为没有axis,所以被展开成向量 

[  0   1   2  99 999   3   4   5   6   7   8   9  10  11]

 2. np.insert(x, 2, [[99, 999, 9999, 99999]], axis = 0): 
 axis=0,插入新的一行,注意插入的行向量shape是(1, 4) 

[[    0     1     2     3]
 [    4     5     6     7]
 [   99   999  9999 99999]
 [    8     9    10    11]]

 3. np.insert(x, 3, [99, 999, 9999], axis = 1): 
 axis=1, 插入新的一列,注意插入的列向量shape是(3, ) 

[[   0    1    2   99    3]
 [   4    5    6  999    7]
 [   8    9   10 9999   11]]

 4. np.insert(x, 3, [[99], [999], [9999]], axis = 1): 
 如果插入一个shape为(3, 1)的向量,会自动把插入的向量补齐为(3, 3) 

[[   0    1    2   99  999 9999    3]
 [   4    5    6   99  999 9999    7]
 [   8    9   10   99  999 9999   11]]

 5. np.insert(x, 3, [9999], axis = 1): 
直接插入一个值的向量,自动补齐 

[[   0    1    2 9999    3]
 [   4    5    6 9999    7]
 [   8    9   10 9999   11]]

numpy.delete

numpy.delete(array, obj, axis)返回从输入数组中沿着指定的轴删除去子数组以后的新数组。

In [29]:
x = np.arange(12).reshape(3, 4)

print "\n 1. np.delete(x, 3): 删除index=3的值(值为3), 因为没有axis,所以被展开成向量 \n"
print np.delete(x, 3)

print "\n 2. np.delete(x, 2, axis = 1): 删除index=2(value = 2)的列向量(axis = 1) \n"
print np.delete(x, 2, axis = 1)

print "\n 3. np.delete(x, np.s_[::2]): 展开成向量,然后每隔1个删除一个值 \n"
print np.delete(x, np.s_[::2])
 1. np.delete(x, 3): 删除index=3的值(值为3), 因为没有axis,所以被展开成向量 

[ 0  1  2  4  5  6  7  8  9 10 11]

 2. np.delete(x, 2, axis = 1): 删除index=2(value = 2)的列向量(axis = 1) 

[[ 0  1  3]
 [ 4  5  7]
 [ 8  9 11]]

 3. np.delete(x, np.s_[::2]): 展开成向量,然后每隔1个删除一个值 

[ 1  3  5  7  9 11]

numpy.unique

numpy.unique(array, return_index, return_inverse, return_counts)的输入为一个矩阵,return_index = True返回原始输入数组产生去重数组的下标;return_inverse = True返回去重数组在原始数组的下标,返回值跟原始输入数组shape相同,可以用来重构原始数组;return_counts = True返回去重数组在原始数组中出现的频率

In [30]:
np.random.seed(0)
x = np.random.poisson(lam = 3, size = 10)
print x

print "\n 1. 返回唯一值 \n"
print np.unique(x)

print "\n 2. 返回唯一值,和原始数组产生唯一值向量的下标\n"
print np.unique(x, return_index = True)

print "\n 3. 返回唯一值,和原始数组的下标,可以用来重构原始数组 \n"
print np.unique(x, return_inverse = True)

print "\n 4. 返回唯一值,和原始数组的下标,可以用来重构原始数组,重构: \n"
u, v = np.unique(x, return_inverse = True)
print u[v]

print "\n 5. 返回唯一值的频率 \n"
print np.unique(x, return_counts = True)
[5 6 2 0 7 3 3 1 6 1]

 1. 返回唯一值 

[0 1 2 3 5 6 7]

 2. 返回唯一值,和原始数组产生唯一值向量的下标

(array([0, 1, 2, 3, 5, 6, 7]), array([3, 7, 2, 5, 0, 1, 4], dtype=int64))

 3. 返回唯一值,和原始数组的下标,可以用来重构原始数组 

(array([0, 1, 2, 3, 5, 6, 7]), array([4, 5, 2, 0, 6, 3, 3, 1, 5, 1], dtype=int64))

 4. 返回唯一值,和原始数组的下标,可以用来重构原始数组,重构: 

[5 6 2 0 7 3 3 1 6 1]

 5. 返回唯一值的频率 

(array([0, 1, 2, 3, 5, 6, 7]), array([1, 2, 1, 2, 1, 2, 1], dtype=int64))