关于numpy:NumPy之ndarray多维数组操作

2次阅读

共计 5763 个字符,预计需要花费 15 分钟才能阅读完成。

简介

NumPy 一个十分重要的作用就是能够进行多维数组的操作,多维数组对象也叫做 ndarray。咱们能够在 ndarray 的根底上进行一系列简单的数学运算。

本文将会介绍一些根本常见的 ndarray 操作,大家能够在数据分析中应用。

创立 ndarray

创立 ndarray 有很多种办法,咱们能够应用 np.random 来随机生成数据:

import numpy as np
# Generate some random data
data = np.random.randn(2, 3)
data
array([[0.0929,  0.2817,  0.769],
       [1.2464,  1.0072, -1.2962]])

除了随机创立之外,还能够从 list 中创立:

data1 = [6, 7.5, 8, 0, 1]
arr1 = np.array(data1)
array([6. , 7.5, 8. , 0. , 1.])

从 list 中创立多维数组:

data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
arr2 = np.array(data2)
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])

应用 np.zeros 创立初始值为 0 的数组:

np.zeros(10)
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

创立 2 维数组:

np.zeros((3, 6))
array([[0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0.]])

应用 empty 创立 3 维数组:

np.empty((2, 3, 2))
array([[[0., 0.],
        [0., 0.],
        [0., 0.]],

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

留神,这里咱们看到 empty 创立的数组值为 0,其实并不是肯定的,empty 会从内存中随机筛选空间来返回,并不能保障这些空间中没有值。所以咱们在应用 empty 创立数组之后,在应用之前,还要记得初始化他们。

应用 arange 创立范畴类的数组:

np.arange(15)
array([0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])

指定数组中元素的 dtype:

arr1 = np.array([1, 2, 3], dtype=np.float64)
arr2 = np.array([1, 2, 3], dtype=np.int32)

ndarray 的属性

能够通过 data.shape 取得数组的形态。

data.shape
(2, 3)

通过 ndim 获取维数信息:

arr2.ndim
2

能够通过 data.dtype 取得具体的数据类型。

data.dtype
dtype('float64')

ndarray 中元素的类型转换

在创立好一个类型的 ndarray 之后,还能够对其进行转换:

arr = np.array([1, 2, 3, 4, 5])
arr.dtype
dtype('int64')

float_arr = arr.astype(np.float64)
float_arr.dtype
dtype('float64')

下面咱们应用 astype 将 int64 类型的 ndarray 转换成了 float64 类型的。

如果转换类型的范畴不匹配,则会主动进行截断操作:

arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
arr.astype(np.int32)

array([3, -1, -2,  0, 12, 10], dtype=int32)

留神,这里是把小数截断,并没有向上或者向下取整。

ndarray 的数学运算

数组能够和常量进行运算,也能够和数组进行运算:

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

arr * arr

array([[1.,  4.,  9.],
       [16., 25., 36.]])

arr + 10

array([[11., 12., 13.],
       [14., 15., 16.]])

arr - arr

array([[0., 0., 0.],
       [0., 0., 0.]])

1 / arr

array([[1.    , 0.5   , 0.3333],
       [0.25  , 0.2   , 0.1667]])

arr ** 0.5

array([[1.    , 1.4142, 1.7321],
       [2.    , 2.2361, 2.4495]])

数组之间还能够进行比拟,比拟的是数组中每个元素的大小:

arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])

arr2 > arr

array([[False,  True, False],
       [True, False,  True]])

index 和切片

根本应用

先看下 index 和切片的根本应用,index 基本上和一般数组的应用形式是一样的,用来拜访数组中某一个元素。

切片要留神的是切片后返回的数组中的元素是原数组中元素的援用,批改切片的数组会影响到原数组。

# 构建一维数组
arr = np.arange(10)

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

# index 拜访
arr[5]
5

# 切片拜访
arr[5:8]
array([5, 6, 7])

# 切片批改
arr[5:8] = 12
array([0,  1,  2,  3,  4, 12, 12, 12,  8,  9])

# 切片能够批改原数组的值
arr_slice = arr[5:8]
arr_slice[1] = 12345
arr

array([    0,     1,     2,     3,     4,    12, 12345,    12,     8,
           9])

# 构建二维数组
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[2]

array([7, 8, 9])

# index 二维数组
arr2d[0][2]
3

# index 二维数组
arr2d[0, 2]
3

# 构建三维数组
arr3d = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
arr3d

array([[[1,  2,  3],
        [4,  5,  6]],

       [[7,  8,  9],
        [10, 11, 12]]])

# index 三维数组
arr3d[0]

array([[1, 2, 3],
       [4, 5, 6]])

# copy 是硬拷贝,和原数组的值互相不影响
old_values = arr3d[0].copy()
arr3d[0] = 42

arr3d

array([[[42, 42, 42],
        [42, 42, 42]],

       [[7,  8,  9],
        [10, 11, 12]]])

arr3d[0] = old_values
arr3d

array([[[1,  2,  3],
        [4,  5,  6]],

       [[7,  8,  9],
        [10, 11, 12]]])

# index 三维数组
arr3d[1, 0]

array([7, 8, 9])

x = arr3d[1]
x

array([[7,  8,  9],
       [10, 11, 12]])

x[0]

array([7, 8, 9])

index with slice

slice 还能够作为 index 应用,作为 index 应用示意的就是一个 index 范畴值。

作为 index 示意的 slice 能够有多种形式。

有头有尾的,示意 index 从 1 开始到 6 - 1 完结:

arr[1:6]
array([1,  2,  3,  4, 64])

无头有尾的,示意 index 从 0 开始,到尾 - 1 完结:

arr2d[:2]
array([[1, 2, 3],
       [4, 5, 6]])

有头无尾的,示意从头开始,到所有的数据完结:

arr2d[:2, 1:]
array([[2, 3],
       [5, 6]])
arr2d[1, :2]
array([4, 5])

boolean index

index 还能够应用 boolean 值,示意是否抉择这一个 index 的数据。

咱们先看下怎么构建一个 boolean 类型的数组:

names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
names == 'Bob'

array([True, False, False,  True, False, False, False])

下面咱们通过比拟的形式返回了一个只蕴含 True 和 False 的数组。

这个数组能够作为 index 值来拜访数组:

#  构建一个 7 * 4 的数组
data = np.random.randn(7, 4)

array([[0.275 ,  0.2289,  1.3529,  0.8864],
       [-2.0016, -0.3718,  1.669 , -0.4386],
       [-0.5397,  0.477 ,  3.2489, -1.0212],
       [-0.5771,  0.1241,  0.3026,  0.5238],
       [0.0009,  1.3438, -0.7135, -0.8312],
       [-2.3702, -1.8608, -0.8608,  0.5601],
       [-1.2659,  0.1198, -1.0635,  0.3329]])

# 通过 boolean 数组来拜访:data[names == 'Bob']
array([[0.275 ,  0.2289,  1.3529,  0.8864],
       [-0.5771,  0.1241,  0.3026,  0.5238]])

在索引行的时候,还能够索引列:

data[names == 'Bob', 3]
array([0.8864, 0.5238])

能够用 ~ 符号来取反:

data[~(names == 'Bob')]
array([[-2.0016, -0.3718,  1.669 , -0.4386],
       [-0.5397,  0.477 ,  3.2489, -1.0212],
       [0.0009,  1.3438, -0.7135, -0.8312],
       [-2.3702, -1.8608, -0.8608,  0.5601],
       [-1.2659,  0.1198, -1.0635,  0.3329]])

咱们能够通过布尔型数组设置值,在理论的我的项目中十分有用:

data[data < 0] = 0
array([[0.275 , 0.2289, 1.3529, 0.8864],
       [0.    , 0.    , 1.669 , 0.],
       [0.    , 0.477 , 3.2489, 0.],
       [0.    , 0.1241, 0.3026, 0.5238],
       [0.0009, 1.3438, 0.    , 0.],
       [0.    , 0.    , 0.    , 0.5601],
       [0.    , 0.1198, 0.    , 0.3329]])
data[names != 'Joe'] = 7
array([[7.    , 7.    , 7.    , 7.],
       [0.    , 0.    , 1.669 , 0.],
       [7.    , 7.    , 7.    , 7.],
       [7.    , 7.    , 7.    , 7.],
       [7.    , 7.    , 7.    , 7.],
       [0.    , 0.    , 0.    , 0.5601],
       [0.    , 0.1198, 0.    , 0.3329]])

Fancy indexing

Fancy indexing 也叫做花式索引,它是指应用一个整数数组来进行索引。

举个例子,咱们先创立一个 8 * 4 的数组:

arr = np.empty((8, 4))
for i in range(8):
    arr[i] = i
arr
array([[0., 0., 0., 0.],
       [1., 1., 1., 1.],
       [2., 2., 2., 2.],
       [3., 3., 3., 3.],
       [4., 4., 4., 4.],
       [5., 5., 5., 5.],
       [6., 6., 6., 6.],
       [7., 7., 7., 7.]])

而后应用一个整数数组来索引,那么将会以指定的程序来抉择行:

arr[[4, 3, 0, 6]]
array([[4., 4., 4., 4.],
       [3., 3., 3., 3.],
       [0., 0., 0., 0.],
       [6., 6., 6., 6.]])

还能够应用负值来索引:

arr[[-3, -5, -7]]
array([[5., 5., 5., 5.],
       [3., 3., 3., 3.],
       [1., 1., 1., 1.]])

花式索引还能够组合来应用:

arr = np.arange(32).reshape((8, 4))
arr
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, 27],
       [28, 29, 30, 31]])

下面咱们构建了一个 8 * 4 的数组。

arr[[1, 5, 7, 2], [0, 3, 1, 2]]
array([4, 23, 29, 10])

而后取他们的第 2 列的第一个值,第 6 列的第三个值等等。最初失去一个 1 维的数组。

数组变换

咱们能够在不同维度的数组之间进行变换,还能够转换数组的轴。

reshape 办法能够将数组转换成为任意的形态:

arr = np.arange(15).reshape((3, 5))
arr
array([[0,  1,  2,  3,  4],
       [5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])

数组还提供了一个 T 命令,能够将数组的轴进行对调:

arr.T
array([[0,  5, 10],
       [1,  6, 11],
       [2,  7, 12],
       [3,  8, 13],
       [4,  9, 14]])

对于高维数组,能够应用 transpose 来进行轴的转置:

arr = np.arange(16).reshape((2, 2, 4))
arr
array([[[0,  1,  2,  3],
        [4,  5,  6,  7]],

       [[8,  9, 10, 11],
        [12, 13, 14, 15]]])
        
arr.transpose((1, 0, 2))
array([[[0,  1,  2,  3],
        [8,  9, 10, 11]],

       [[4,  5,  6,  7],
        [12, 13, 14, 15]]])

下面的 transpose((1, 0, 2)) 怎么了解呢?

其含意是将 x,y 轴对调,z 轴放弃不变。

下面咱们通过应用 reshape((2, 2, 4)) 办法创立了一个 3 维,也就是 3 个轴的数组。其 shape 是 2 2 4。

先看下对应关系:

(0,0)-》[0, 1, 2, 3]

(0,1)-》[4, 5, 6, 7]

(1,0)-》[8, 9, 10, 11]

(1,1)-》[12, 13, 14, 15]

转换之后:

(0,0)-》[0, 1, 2, 3]

(0,1)-》[8, 9, 10, 11]

(1,0)-》[4, 5, 6, 7]

(1,1)-》[12, 13, 14, 15]

于是失去了咱们下面的的后果。

多维数组的轴转换可能比较复杂,大家多多了解。

还能够应用 swapaxes 来替换两个轴,下面的例子能够重写为:

arr.swapaxes(0,1)

本文已收录于 http://www.flydean.com/09-python-numpy-ndarray/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

正文完
 0