4_1 Numpy基础:数组和矢量计算

2022-09-10 10:28:53

利用python进行数据分析

看这里

第四章 简介

NumPy之于数值计算特别重要的原因之一,是因为它可以高效处理大数组的数据。这是因为:

  • NumPy是在一个连续的内存块中存储数据,独立于其他Python内置对象。NumPy的C语言编写的算法库可以操作内存,而不必进行类型检查或其它前期工作。比起Python的内置序列,NumPy数组使用的内存更少。
  • NumPy可以在整个数组上执行复杂的计算,而不需要Python的for循环。
import numpyas np
my_arr = np.arange(1000000)
my_list =  list(range(1000000))
%timefor nin range(10):my_arr2 = my_arr *2
Wall time: 24.9 ms
my_arr2[:10]
array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])
%timefor min range(10): my_list2 = [x *2for xin my_list]
Wall time: 1.2 s
my_list2[:10]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
  • 通过上述实验对比可知,numpy在大型数组计算时会快很多

4.1ndarray:多维数组对象

import numpyas np# 产生2*3的数组
data = np.random.randn(2,3)
data
array([[ 1.46500606,  0.38171158,  0.20194511],
       [-1.21663118, -0.65103605,  2.03941173]])
#数组的每个元素乘以一个实数
data *10
array([[ 14.65006062,   3.81711579,   2.01945106],
       [-12.1663118 ,  -6.51036045,  20.39411734]])
data + data
array([[ 2.93001212,  0.76342316,  0.40389021],
       [-2.43326236, -1.30207209,  4.07882347]])
  • ndarray是一个通用的同构数据多维容器,即其所有元素必须是相同类型的。每个数组都有一个shape(一个表示各维度大小的元组)和一个dtype(一个用于说明数组数据类型的对象)
data.shape
(2, 3)
data.dtype
dtype('float64')
  • 创建数组:最简单的办法就是使用array函数。它接受一切序列型的对象(包括其他数组),然后产生一个新的含有传入数据的NumPy数组
data1 = [1,2,3,6.5,0]
arr1 = np.array(data1)
arr1
array([1. , 2. , 3. , 6.5, 0. ])
  • 嵌套序列:有一组等长的列表组成的列表
data2 = [[1,2,3],[4,5,6]]
arr2 = np.array(data2)
arr2
array([[1, 2, 3],
       [4, 5, 6]])
arr2.ndim#维度
2
arr2.shape
(2, 3)
arr2.dtype
dtype('int32')
  • zeros和ones分别可以创建指定长度或形状的全0或全1数组。empty可以创建一个没有任何具体值的数组。要用这些方法创建多维数组,只需传入一个表示形状的元组即可
np.zeros((2,3))
array([[0., 0., 0.],
       [0., 0., 0.]])
arr3 = np.ones((2,2,2))
arr3
array([[[1., 1.],
        [1., 1.]],

       [[1., 1.],
        [1., 1.]]])
arr3.ndim
3
arr3.shape
(2, 2, 2)
  • arange()是Python内置函数range()函数的数组版
np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

数组创建函数

  • 也可以在创建数组时指定数据类型
arr4 = np.array([1,2,3],dtype = np.float)
arr4
array([1., 2., 3.])
arr4.dtype
dtype('float64')
arr5 = np.array([1,2,3],dtype=np.int32)
arr5
array([1, 2, 3])
arr5.dtype
dtype('int32')
  • 可以使用astype(type)将一个类型的数组转换为指定类型
float_arr5 = arr5.astype(np.float64)
float_arr5.dtype
dtype('float64')
  • 上例中将整数转换为浮点数;如果将浮点数转换为整数,则小数部分将被截取删除
f_arr = np.array([1.22,33.211,20.01])
f_arr
array([ 1.22 , 33.211, 20.01 ])
f_arr.dtype
dtype('float64')
i_arr = f_arr.astype(np.int32)
i_arr
array([ 1, 33, 20])
i_arr.dtype
dtype('int32')
  • 如果某个数组元素全是数字字符串,也可以使用astype进行转换
s_arr = np.array(['1','2.22','3.01'])
s_arr.dtype
dtype('<U4')
s_arr.astype(np.float64)
array([1.  , 2.22, 3.01])

numpy 数组的运算

arr = np.array([[1,2,3.0],[4.,5.,6.]])
arr
array([[1., 2., 3.],
       [4., 5., 6.]])
arr **2
array([[ 1.,  4.,  9.],
       [16., 25., 36.]])
arr * arr
array([[ 1.,  4.,  9.],
       [16., 25., 36.]])
#数组与标量的算术运算会将标量值传播到各个元素#不同大小的数组之间的运算叫做广播(broadcasting)
arr /2
array([[0.5, 1. , 1.5],
       [2. , 2.5, 3. ]])
arr //2
array([[0., 1., 1.],
       [2., 2., 3.]])
arr -1
array([[0., 1., 2.],
       [3., 4., 5.]])
# shape相同的数组比较会产生一个布尔数组
arr2 = np.array([[4,1,1],[7,5,5]])
arr > arr2
array([[False,  True,  True],
       [False, False,  True]])

基本的索引和切片

arr = np.arange(10)
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr[5]
5
arr[:6]
array([0, 1, 2, 3, 4, 5])
arr[2:5] =10
arr
array([ 0,  1, 10, 10, 10,  5,  6,  7,  8,  9])
  • 数组切片跟列表最重要的区别在于,数组切片是原始数组的视图。这意味着数据不会被复制,视图上的任何修改都会直接反映到源数组上。
arr_slice = arr[2:5]
arr_slice
array([10, 10, 10])
#当修改arr_slice时,arr数组也会被修改
arr_slice[1] =100
arr_slice
array([ 10, 100,  10])
arr
array([  0,   1,  10, 100,  10,   5,   6,   7,   8,   9])
  • 如果想要得到数组的一个副本,而不是原数组的一个视图,可以使用copy()方法
arr_copy = arr[:3].copy()
arr_copy
array([ 0,  1, 10])
arr_copy[0] =100
arr_copy
array([100,   1,  10])
arr
array([  0,   1,  10, 100,  10,   5,   6,   7,   8,   9])
arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
arr2d[1]
array([4, 5, 6])
arr2d[1,1]
5
arr2d[1][1]
5
arr2d.ndim
2
# 三维数组
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]]])
arr3d.shape
(2, 2, 3)
arr3d[0]
array([[1, 2, 3],
       [4, 5, 6]])
arr3d[0,1]
array([4, 5, 6])
arr3d[0,1,2]
6
# 标量值可以直接赋值给数组得某个元素,具有广播
arr3d[0] =0
arr3d
array([[[ 0,  0,  0],
        [ 0,  0,  0]],

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

切片索引

arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
arr2d
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
arr2d[:2]
array([[1, 2, 3],
       [4, 5, 6]])
arr2d[:2,:2]
array([[1, 2],
       [4, 5]])
arr2d[1,:2]
array([4, 5])
  • 对切片表达式的赋值也会扩散到整个选区
arr2d[:2,:2] =1
arr2d
array([[1, 1, 3],
       [1, 1, 6],
       [7, 8, 9]])

布尔型索引

names = np.array(['Bob','Joe','Will','Bob','will','Joe','Joe'])
data = np.random.randn(7,4)
names
array(['Bob', 'Joe', 'Will', 'Bob', 'will', 'Joe', 'Joe'], dtype='<U4')
data
array([[-0.22069039, -0.3274228 , -1.16742577, -0.73831674],
       [-0.17419963, -1.86709013,  1.07920976, -1.10985636],
       [ 1.55001149, -2.08476377, -1.14224182, -1.15043735],
       [ 0.98140083,  0.96417792,  3.68246684, -1.21193783],
       [-0.49201841,  0.93379201, -2.06124303,  1.73694261],
       [ 0.76176287,  0.59960082, -0.72839576, -1.22476123],
       [ 0.03756529,  2.76069372,  1.33604503, -1.47566927]])
names =='Bob'
array([ True, False, False,  True, False, False, False])
data[names =='Bob']
array([[-0.22069039, -0.3274228 , -1.16742577, -0.73831674],
       [ 0.98140083,  0.96417792,  3.68246684, -1.21193783]])
data[names =='Bob',2:]
array([[-1.16742577, -0.73831674],
       [ 3.68246684, -1.21193783]])
data[names =='Bob',2]#索引列
array([-1.16742577,  3.68246684])
  • 如果要获取除了‘Bob’以外的值,既可以使用 != ,也可以使用~取反
names !='Bob'
array([False,  True,  True, False,  True,  True,  True])
data[~(names =='Bob')]
array([[-0.17419963, -1.86709013,  1.07920976, -1.10985636],
       [ 1.55001149, -2.08476377, -1.14224182, -1.15043735],
       [-0.49201841,  0.93379201, -2.06124303,  1.73694261],
       [ 0.76176287,  0.59960082, -0.72839576, -1.22476123],
       [ 0.03756529,  2.76069372,  1.33604503, -1.47566927]])
  • 也可以使用& 、 | 、等不二算术运算
mask = (names =='Bob') |(names =='Will')
mask
array([ True, False,  True,  True, False, False, False])
data[mask]
array([[-0.22069039, -0.3274228 , -1.16742577, -0.73831674],
       [ 1.55001149, -2.08476377, -1.14224182, -1.15043735],
       [ 0.98140083,  0.96417792,  3.68246684, -1.21193783]])

通过布尔型索引选取数组元素,都将创建数组的副本。而数字切片索引将获得数组的视图

# 将data中小于零的元素设置为0
data[data <0] =0
data
array([[0.        , 0.        , 0.        , 0.        ],
       [0.        , 0.        , 1.07920976, 0.        ],
       [1.55001149, 0.        , 0.        , 0.        ],
       [0.98140083, 0.96417792, 3.68246684, 0.        ],
       [0.        , 0.93379201, 0.        , 1.73694261],
       [0.76176287, 0.59960082, 0.        , 0.        ],
       [0.03756529, 2.76069372, 1.33604503, 0.        ]])
# 通过一维布尔数组设置整行或列的值
data[names !='Joe'] =7
data
array([[7.        , 7.        , 7.        , 7.        ],
       [0.        , 0.        , 1.07920976, 0.        ],
       [7.        , 7.        , 7.        , 7.        ],
       [7.        , 7.        , 7.        , 7.        ],
       [7.        , 7.        , 7.        , 7.        ],
       [0.76176287, 0.59960082, 0.        , 0.        ],
       [0.03756529, 2.76069372, 1.33604503, 0.        ]])

花式索引

  • 花式索引(Fancy indexing)是一个NumPy术语,它指的是利用整数数组进行索引。
arr = np.empty((8,4))for iin 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[[-1,-3,-5]]
array([[7., 7., 7., 7.],
       [5., 5., 5., 5.],
       [3., 3., 3., 3.]])
  • 一次传入多个索引数组会有一点特别。它返回的是一个一维数组,其中的元素对应各个索引元组:
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]])
#最终选出的是元素(1,0)、(5,3)、(7,1)和(2,2)。无论数组是多少维的,花式索引总是一维的。
arr[[1,5,7,2],[0,3,1,2]]
array([ 4, 23, 29, 10])
arr[[1,5,7,2]]
array([[ 4,  5,  6,  7],
       [20, 21, 22, 23],
       [28, 29, 30, 31],
       [ 8,  9, 10, 11]])
arr[[1,5,7,2]][:,[0,3,1,2]]
array([[ 4,  7,  5,  6],
       [20, 23, 21, 22],
       [28, 31, 29, 30],
       [ 8, 11,  9, 10]])
  • 花式索引跟切片不一样,它总是将数据复制到新数组中。
  • 作者:湾区小学生
  • 原文链接:https://blog.csdn.net/FANGLICHAOLIUJIE/article/details/82584779
    更新时间:2022-09-10 10:28:53