美文网首页程序员
《利用pyhton进行数据分析》笔记-Numpy(二)

《利用pyhton进行数据分析》笔记-Numpy(二)

作者: 董小贱 | 来源:发表于2018-08-12 23:49 被阅读152次

1.数组的索引和切片(可类比于list的索引和切片,注意区别)

数组选取数据子集或单个元素的方式有很多。一维数组跟list很相似,多维数组的花样更多, 下面来看。

1. 1基本的索引和切片

先来看一下例子,体会一下一维数组与list的区别:

import numpy as np
temp_array = np.arange(15)  # array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])
temp_list = list(range(15)) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

# 索引比较
temp_array[10]  #返回值: 10 
temp_list[10]   #返回值: 10 

# 切片比较
temp_array[1:5]  #返回值 array([1, 2, 3, 4])
temp_list[1:5]  #返回值 [1, 2, 3, 4]

# 对单个值赋值比较
temp_list[1] = 6
temp_list # 返回值  [0, 6, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
temp_array[1] = 6
temp_array # 返回值  array([ 0,  6,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])

# 对切片赋值比较
temp_array[1:5] = 6
temp_array  # 返回值   array([ 0,  6,  6,  6,  6,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])
# temp_list[1:5] = 6 # 报错  TypeError: can only assign an iterable

# 切片之后索引赋值比较
#先来看list
temp_list2 = temp_list[1:5] 
temp_list2 #  [6, 2, 3, 4]
temp_list2[2] = 1234
temp_list #返回值: [0, 6, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
temp_list2 # 返回值 [6, 2, 1234, 4]
temp_list[3] = 12341234  #对原始list修改
 temp_list2 # 返回值:[6, 2, 1234, 4]

#再来看array
temp_array2 = temp_array[2:8]
temp_array2 # array([6, 6, 6, 5, 6, 7])
temp_array2[2] = 1234
temp_array2 #返回值:array([   6,    6, 1234,    5,    6,    7])
temp_array # 返回值 array([   0,    6,    6,    6, 1234,    5,    6,    7,    8,    9,   10,11,   12,   13,   14])
temp_array[5] = 123123 # 对原始数组的修改
temp_array2 # 返回值: array([     6,      6,   1234, 123123,      6,      7])

通过看上边的例子, 不难发现ndarray和list的索引、切片、对单个值赋值基本都一样, 区别在于对切片直接赋值、切片单个值的赋值,list的切片赋值直接报错,数组的切片修改,该值会自动广播到整个选区的元素。
ndarray切片是原始数组的视图(可以理解为地址指向,类比于浅拷贝.),视图上的任何修改都会直接反应到原数组上,源数据的修改也会影响视图。Numpy的这种做法其实不难理解,Numpy是用来处理大数据的,如果将其中的数据多次复制的话那得是多大的内存和性能的消耗。
当然,如果想要的得到的数组的切片是一个副本而不是视图的话,需要进行复制操作,即 temp_array[1:5].copy(),如果非必须,还是不要辣么做了!

来看一下多维数组的例子(拿二维为例):

# 二维:
temp_array5 = np.eye(4)
temp_array5
#返回值: array([[1., 0., 0., 0.],
#        [0., 1., 0., 0.],
#        [0., 0., 1., 0.],
#        [0., 0., 0., 1.]])

temp_array5[2]# 返回值:array([0., 0., 1., 0.])
temp_array5[2][2] # 返回值 1.0

temp_array5[:3] # [:3]的切片
# 返回值: array([[1., 0., 0., 0.],
#        [0., 1., 0., 0.],
#        [0., 0., 1., 0.]])

temp_array5[:3:2] # 类比于list,这就是[:3]的切片, 步长为2
# 返回值: array([[1., 0., 0., 0.],
#        [0., 0., 1., 0.]])

temp_array5[:3] = 42 # 视图赋值
temp_array5
#返回值:  array([[42., 42., 42., 42.],
#        [42., 42., 42., 42.],
#        [42., 42., 42., 42.],
#        [ 0.,  0.,  0.,  1.]])

temp_array5[1,2] = 88  #与 temp_array5[1][2] 一样 
temp_array5
# 返回值:array([[42., 42., 42., 42.],
#            [42., 42., 88., 42.],
#            [42., 42., 42., 42.],
#              [ 0.,  0.,  0.,  1.]])
1.2切片索引

低维度的切片索引其实在1.1已经用到过了, 现在咱们直接用多维的来为例:

temp_list = [[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]
temp_array = np.array(temp_list)
temp_array.shape # 返回值:  (2, 2, 3)

temp_array[1, :1] # 返回值 array([[7, 8, 9]])

temp_array[:2, :1] # array([[[1, 2, 3]],[[7, 8, 9]]])
# 注:相当于temp_array[0][:1]与temp_array[1][:1] 的结合,不是相加,相加会广播到元素级。

# 这里需要注意
temp_array[1,0,1] # 返回值 8

# temp_array[1,0,1]的元素和 temp_array[1,1,1]的元素组成的列表
temp_array[1,:,1] #array([ 8, 11])

# 请参考上一种请情况
temp_array[:,:,1] 
# 返回值:array([[ 2,  5],
#            [ 8, 11]])
temp_array[:,:,1]  = 110
temp_array
# array([[[  1, 110,   3],
#         [  4, 110,   6]],
#        [[  7, 110,   9],
#         [ 10, 110,  12]]])

# 注:只写一个冒号, 表示选取的对应的整个维度。
1.3 布尔型索引

值的注意的是布尔型索引返回的值是副本而不是视图,不是视图!!!

#数据准备
temp_array1 = np.array('a b c d e f'.split(' '))
temp_array1 #array(['a', 'b', 'c', 'd', 'e', 'f'], dtype='<U1')
temp_array2 = np.random.randn(6,3)
temp_array2
# array([[-1.75405219, -0.33932199,  0.16753136],
#        [-0.40832969,  0.28943606, -0.29946825],
#        [-1.15116563, -1.93324644,  0.04890539],
#        [-2.55618941, -0.55516265,  0.13617437],
#        [ 2.11503851,  1.84211619,  0.35172968],
#        [ 0.75279809,  0.63056373, -1.1371636 ]])

# 单独的判断可以广播到元素级,这不是中点, 布尔切片才是重点
temp_array1 == 'a' # 返回值 array([ True, False, False, False, False, False])
temp_array2>0
# array([[ True,  True,  True],
#        [False,  True, False],
#        [False, False,  True],
#        [False, False,  True],
#        [ True,  True,  True],
#        [ True,  True, False]])

temp_array2[temp_array1 == 'a'] #返回值:array([[-1.75405219, -0.33932199,  0.16753136]])


temp_array3 = temp_array2[temp_array1 == 'a']
temp_array2[0] = 5
temp_array3 #返回值:array([[-1.75405219, -0.33932199,  0.16753136]])
temp_array2
# array([[ 5.        ,  5.        ,  5.        ],
#        [-0.40832969,  0.28943606, -0.29946825],
#        [-1.15116563, -1.93324644,  0.04890539],
#        [-2.55618941, -0.55516265,  0.13617437],
#        [ 2.11503851,  1.84211619,  0.35172968],
#        [ 0.75279809,  0.63056373, -1.1371636 ]])

# 注: 这里返回的并不是视图, 而是副本,是副本不是视图 不是视图。


# 可以写为并列形式
temp_array2[(temp_array1 == 'a') | (temp_array1 == 'b')]
# 注:and 和or在布尔型数组中无效

# 返回值:array([[ 5.        ,  5.        ,  5.        ],
#        [-0.40832969,  0.28943606, -0.29946825]])

# 当然还有这种形式
temp_array2[(temp_array1 == 'a'),:2] # array([[5., 5.]])
1.4 花式索引

花式索引是Numpy术语,指的是利用整数数组进行索引。返回的并不是视图, 也是副本。

temp_array = np.eye(6)
temp_array[[1,2]]
# 返回值: array([[0., 1., 0., 0., 0., 0.],
#                [0., 0., 1., 0., 0., 0.]])

temp_array[[1,-2]]
# array([[0., 1., 0., 0., 0., 0.],
#        [0., 0., 0., 0., 1., 0.]])


temp_array[[1,-2],[1,2]] # 返回值 array([1., 0.]), 我擦, 这种看不出来啊, 咱们换一种

temp_array = np.arange(24).reshape((6,4))
temp_array
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [ 8,  9, 10, 11],
#        [12, 13, 14, 15],
#        [16, 17, 18, 19],
#        [20, 21, 22, 23]])

temp_array[[1,2,3]]
# array([[ 4,  5,  6,  7],
#        [ 8,  9, 10, 11],
#        [12, 13, 14, 15]])

temp_array[[1,2,3],[2,3,1]] #最终选取的元素是(1,2),(2,3), (3,1)返回值: array([ 6, 11, 13])

temp_array[[1,2,3]][:,[2,3,1]] # 这个是选取的方形区域, 注意以上两种的写法区别
# 返回值 array([[ 6,  7,  5],
#        [10, 11,  9],
#        [14, 15, 13]])

#注:花式索引返回的是副本, 而不是视图。

2.数组的转置和轴的对换

转置是重塑的一种特殊形式,它返回的是源数据的视图, 转置最少要两维。

#两维数组
temp_array = np.arange(9).reshape((3,3))
# 两维数组的转置, 这两种方式等价 
temp_array.transpose(1,0) 
# 返回值:array([[0, 3, 6],
#        [1, 4, 7],
#        [2, 5, 8]])

temp_array.T
# 返回值:array([[0, 3, 6],
#        [1, 4, 7],
#        [2, 5, 8]])


# 更高维度的数组转置
temp_array2 = np.arange(27).reshape((3,3,3))
temp_array2
# 返回值:array([[[ 0,  1,  2],
#         [ 3,  4,  5],
#         [ 6,  7,  8]],

#        [[ 9, 10, 11],
#         [12, 13, 14],
#         [15, 16, 17]],

#        [[18, 19, 20],
#         [21, 22, 23],
#         [24, 25, 26]]])


temp_array2.transpose((1,0,2))
# 返回值:array([[[ 0,  1,  2],
#         [ 9, 10, 11],
#         [18, 19, 20]],

#        [[ 3,  4,  5],
#         [12, 13, 14],
#         [21, 22, 23]],

#        [[ 6,  7,  8],
#         [15, 16, 17],
#         [24, 25, 26]]])

temp_array2.transpose((1,2,0))

# 返回值:array([[[ 0,  9, 18],
#         [ 1, 10, 19],
#         [ 2, 11, 20]],

#        [[ 3, 12, 21],
#         [ 4, 13, 22],
#         [ 5, 14, 23]],

#        [[ 6, 15, 24],
#         [ 7, 16, 25],
#         [ 8, 17, 26]]])

temp_array2.T # 等价于 temp_array2.transpose((2,1,0))

#返回值: array([[[ 0,  9, 18],
#         [ 3, 12, 21],
#         [ 6, 15, 24]],

#        [[ 1, 10, 19],
#         [ 4, 13, 22],
#         [ 7, 16, 25]],

#        [[ 2, 11, 20],
#         [ 5, 14, 23],
#         [ 8, 17, 26]]])

是不是看的恍恍惚惚,迷迷瞪瞪.... 哈哈,我当时看的时候也是如此,那下边再来看一个例子(拿三维来讲):

temp_array = np.arange(24).reshape((2,3,4))
temp_array # 原始数组
# 返回值:array([[[ 0,  1,  2,  3],
#         [ 4,  5,  6,  7],
#         [ 8,  9, 10, 11]],

#        [[12, 13, 14, 15],
#         [16, 17, 18, 19],
#         [20, 21, 22, 23]]])


temp_array.transpose(1,0,2).shape # 返回值:(3, 2, 4)
temp_array.transpose(1,0,2)
# 返回值:array([[[ 0,  1,  2,  3],
#         [12, 13, 14, 15]],

#        [[ 4,  5,  6,  7],
#         [16, 17, 18, 19]],

#        [[ 8,  9, 10, 11],
#         [20, 21, 22, 23]]])



temp_array.transpose(1,2,0) # 其形状为(3,4,2)

# 返回值:array([[[ 0, 12],
#         [ 1, 13],
#         [ 2, 14],
#         [ 3, 15]],

#        [[ 4, 16],
#         [ 5, 17],
#         [ 6, 18],
#         [ 7, 19]],

#        [[ 8, 20],
#         [ 9, 21],
#         [10, 22],
#         [11, 23]]])

temp_array.transpose(2,1,0)# 其形状为(4,3,2)
#返回值: array([[[ 0, 12],
#         [ 4, 16],
#         [ 8, 20]],

#        [[ 1, 13],
#         [ 5, 17],
#         [ 9, 21]],

#        [[ 2, 14],
#         [ 6, 18],
#         [10, 22]],

#        [[ 3, 15],
#         [ 7, 19],
#         [11, 23]]])

从例子可以看出,数组的转置是按照轴来转换的,轴的编号即对应维度的下标,比如原始数据temp_array的形状(2,3,4),则0轴对应的维度是2,即第一层中括号里的数据,1号周对应的维度是3,即第二层括号里的数据,3轴对应的维度是4,即第三层里的数据,即元素。那么轴的转换,比如原始数据(0,1,2),转换为(1,0,2),也就是1号轴沿着0轴拼数据, 然后组成形状为 (3,2,4)的数据, 咱们依次看图:

原始数据 1号轴与0号轴转置

注:temp_array.transpose(1,2,0)的数据可在temp_array.transpose(1,0,2)的基础上求得在此不再展示。

2号轴与0号轴转置

总注:本次笔记的内容就到这里了,这次的重点是数组的索引、切片和转置,转置比较难理解, 我也是花了点功夫才理解其中的过程。后边的通用函数以及利用数组进行数据处理的内容不再做笔记,这两节主要讲的是矢量化的一些内容,一些方法用的时候直接查文档就ok了,太零碎,记不住,请读者老爷们见谅!最后需要提醒的是:注意区分视图和副本的情况! 注意区分视图和副本的情况!!注意区分视图和副本的情况!!!

本人水平有限, 如有错误欢迎提出指正!如有参考, 请注明出处!!原创不易,禁止抄袭,遇抄必肛!!!

相关文章

网友评论

    本文标题:《利用pyhton进行数据分析》笔记-Numpy(二)

    本文链接:https://www.haomeiwen.com/subject/xissbftx.html