numpy的使用

numpy的使用

  • 1数据的创建与类型
    • (1)np.array和np.arange
    • (2)numpy中常见的数据类型
    • (3)numpy中的bool型
    • (4)数据类型转换
    • (5)numpy中的小数
  • 2 数组的形状
    • (1) 查看数组的形状np.shape
    • (2)重塑数组的形状 np.reshape()
  • 3 数组的轴
  • 4 广播
    • (1)数组(矩阵)+数字
    • (2)不同维度的两个数组相加
  • 5 读数据
  • 6 数组的切片
    • (1)取行或列
    • (2)取元素
    • (3)切片引用
  • 7 数组值的修改
    • (1)赋值修改
    • (2)三元运算符
    • (3)范围裁剪numpy.clip
  • 8 关于numpy.nan和numpy.inf
  • 9 布尔索引
  • 10 常用统计函数
  • 11 数组的拼接
    • (1)一维数组的拼接
    • (1)二维数组的拼接
    • (3)高维数组的拼接
  • 12 数组的切割
    • (1)水平竖直分割
    • (2)按指定轴分割
    • (3)按深度分割
  • 13 行与行的交换、列与列的交换
  • 14 线性代数相关操作
    • (1)转置
    • (2)矩阵乘法
      • a 对应位置乘积
      • b 矩阵乘积
    • (3)求行列式
    • (4)求逆
    • (5)解线性方程组
    • (6)特征值和特征向量
  • 15 随机函数
    • (1)随机抽样
    • (2)打乱顺序
      • a 原地打乱 shuffle
      • b 非原地打乱 permutation
  • 16 其他常用方法
    • (1)获取最大值最小值的索引
    • (2)全零数组,全一数组,单位矩阵
    • (3)真值测试函数
  • 17 练习

1数据的创建与类型

(1)np.array和np.arange

import numpy as np
# 下面三种方式等效
t1 = np.array([1,2,3,4,5])
t2 = np.array(range(5))
t3 = np.arange(5)
print(t1)
print(type(t1))		# 数组的类型
print(t1.dtype)     # t1数组中,数据的类型

输出

[1 2 3 4 5]
<class 'numpy.ndarray'>
int32

数组的类型是ndarray,数组中数据的类型是int32。
arrange的用法和range一致,即参数是start,end,seg
但与range不同的是,arange还能生成小数

t4 = np.arange(10, 15, 0.5)
print(t4)

输出

[10.  10.5 11.  11.5 12.  12.5 13.  13.5 14.  14.5]

(2)numpy中常见的数据类型

numpy的使用_第1张图片
除了上面的类型,numpy还支持字符串类型,用 np.str_ 表示

可以在创建的时候,指定其类型

t5 = np.array(range(1,4),dtype="i1")
# 也可以写成t4 = np.array(range(1,4),dtype=int8)

  若在创建数组的时候没有指定数据类型,那么默认情况下,根据电脑的位数来确定是32位还是64位,如果电脑是64位,那么就是int64,如果是32位,那么就是int32。

(3)numpy中的bool型

将数值型转化为bool型时,只要不是0,那都是True

##numpy中的bool类型
t6 = np.array([1,1,0,1,0,0],dtype=bool)
print(t6)
print(t6.dtype)

输出

[ True  True False  True False False]
bool

(4)数据类型转换

使用np.astype进行转换

t7 = t6.astype("int8")
print(t7)
print(t7.dtype)

输出

[1 1 0 1 0 0]
int8

(5)numpy中的小数

# numpy中的小数
# 需要先导入random模块,import random
# random.random()表示生成一个0-1之间的随机数
t7 = np.array([random.random() for i in range(10)])
print(t7)
print(t7.dtype)

# 四舍五入
t8 = np.round(t7,2)	# 保留两位小数
print(t8)

输出

[0.86556796 0.43664234 0.75419431 0.09691071 0.95194878 0.3131914
 0.70976318 0.53698263 0.29735993 0.96115199]
float64
[0.87 0.44 0.75 0.1  0.95 0.31 0.71 0.54 0.3  0.96]

2 数组的形状

(1) 查看数组的形状np.shape

可以使用np.shape()来查看数组的形状(即几行几列)
numpy的使用_第2张图片
t1是一位数组,其形状为(12, ),这是一个元组,但只有含有一个值。

(2)重塑数组的形状 np.reshape()

numpy的使用_第3张图片
  t3是三维数组,的形状为(2, 3, 4),应该从后往前读,最后一维是4,说明最里面的中括号里有四个数,然后是3,说明次里面的中括号有三个对象,最前面是2,说明最大的中括号里面有两个对象。
  对于多维数组,其元素地址的变化规律如下:下标从最后一个维度开始变化,然后倒数第二个,一直到最前面的。
  也可以这样认为,2表示有2块,(3, 4)表示每块都有一个(3, 4)的矩阵。
  需要注意的是,一维数组是(3, ),只有一对中括号,而不是(3, 1)和(1, 3),后两者是二维的,有两对中括号。
numpy的使用_第4张图片
np.flatten将矩阵打平成数组
numpy的使用_第5张图片
np.flatten是从里往外,依次打开中括号
numpy的使用_第6张图片

3 数组的轴

  在numpy中可以理解为方向,使用0,1,2…数字表示,对于一个一维数组,只有一个0轴,对于2维数组(shape(2,2)),有0轴和1轴,对于三维数组(shape(2,2, 3)),有0,1,2轴。
  np.arange(0,10).reshape((2,5)),reshpe的参数中2表示0轴长度(包含数据的条数)为2,1轴长度为5,2X5一共10个数据。
numpy的使用_第7张图片
  在带有axis参数的二维数组上使用np.sum()等聚合函数时,它会将二维数组折叠为一维数组,其折叠的方向由axis参数确定。
  如

t1 = np.arange(12,24).reshape((3,4))
print(t1)
print(50 * '-')

t2 = np.sum(t1, axis=0)
print(t2)

输出

[[12 13 14 15]
 [16 17 18 19]
 [20 21 22 23]]
--------------------------------------------------
[48 51 54 57]

  对于三维数组也是类似,假如t3是三维数组,其shape是(2,3,4),那么第0轴的长度是2,如果按照第0轴的方向折叠,折叠后的shape为(3,4),如下:
numpy的使用_第8张图片

4 广播

不同维度的矩阵或数据进行计算,即为广播。

(1)数组(矩阵)+数字

相当于二维数组的每个元素都加了这个数字

In [6]: t2
Out[6]:
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11]])

In [7]: t2 + 10
Out[7]:
array([[10, 11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20, 21]])

(2)不同维度的两个数组相加

先看下面的实例:

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

In [12]: t8
Out[12]:
array([[10, 11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20, 21]])

In [13]: t9
Out[13]:
array([[10, 11],
       [12, 13],
       [14, 15],
       [16, 17],
       [18, 19],
       [20, 21]])

In [14]: t7 + t8
Out[14]:
array([[10, 12, 14, 16, 18, 20],
       [16, 18, 20, 22, 24, 26]])

t7能和t8相加

In [15]: t7 + t9
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-15-e3cd48b39d92> in <module>
----> 1 t7 + t9

ValueError: operands could not be broadcast together with shapes (6,) (6,2)

t7+t9就会报错

(6,1)的数组能和(6,2)的相加吗?

numpy的使用_第9张图片
根据上面的规律,可以提炼出广播的规律:
在这里插入图片描述
  注意什么是后缘维度,所谓的后缘维度就是从后面开始算起,从前面开始算起的(前缘维度)有若干维度相同的,不能进行广播,如
numpy的使用_第10张图片
其他基本运算,包括地板除,与加法相同
二维或者更高维度的数组和一维数据进行运算,那么一维数组,其长度就是后缘维度
numpy的使用_第11张图片

5 读数据

  由于csv便于展示,读取和写入,所以很多地方也是用csv的格式存储和传输中小型的数据,为了方便教学,我们会经常操作csv格式的文件,但是操作数据库中的数据也是很容易的实现的

np.loadtxt(fname,dtype=np.float,delimiter=None,skiprows=0,usecols=None,unpack=False)

numpy的使用_第12张图片
其中 unpack 若为True,则相当于将原来的数据进行了转置
在这里插入图片描述
练习:
  现有英国和美国各自在youtube的1000多个视频的“点击,喜欢,不喜欢,评论”数量([“views”,“likes”,“dislikes”,“comment_total”])的csv文件,使用刚刚介绍的方法读取数据:

import numpy as np

us_file_path = "./youtube_video_data/US_video_data_numbers.csv"
uk_file_path = "./youtube_video_data/GB_video_data_numbers.csv"

# 读取第1列和第3列
t1 = np.loadtxt(us_file_path,delimiter=",",dtype="int",usecols=(1, 3))

# 不指定读取哪一列,默认读取全部,让每一列代表一个记录
t2 = np.loadtxt(us_file_path,delimiter=",",dtype="int",unpack=True)

print(t1)
print(50*'*')
print(t2)

输出

[[320053  46245]
 [185853      0]
 [576597 170708]
 ...
 [  4231    279]
 [ 41032   4737]
 [ 34727   4722]]
**************************************************
[[4394029 7860119 5845909 ...  142463 2162240  515000]
 [ 320053  185853  576597 ...    4231   41032   34727]
 [   5931   26679   39774 ...     148    1384     195]
 [  46245       0  170708 ...     279    4737    4722]]

6 数组的切片

(1)取行或列

In [17]: t1
Out[17]:
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])

In [18]: t1[2]  # 取行
Out[18]: array([10, 11, 12, 13, 14])

In [19]: t1[-1] # 取最后一行
Out[19]: array([15, 16, 17, 18, 19])

取连续多行,像列表切片一样,startseg

In [21]: t1[1:3] # 取连续多行
Out[21]:
array([[ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])

取不连续的多行

In [23]: t1[[1,3]]  # 取第1行和第3行
Out[23]:
array([[ 5,  6,  7,  8,  9],
       [15, 16, 17, 18, 19]])

  对列的操作和行类似,但是在取列的时候,行的位置处要有冒号(:),否则报错
  取列的时候,返回值是一维数组,一维数组是以行的形式展示的。

In [27]: t1
Out[27]:
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])

In [28]: t1[:,2] # 取列的时候,行的位置冒号(:)不能省略
Out[28]: array([ 2,  7, 12, 17])

In [29]: t1[:,::2]
Out[29]:
array([[ 0,  2,  4],
       [ 5,  7,  9],
       [10, 12, 14],
       [15, 17, 19]])

(2)取元素

  取某个具体元素上的值,返回的将不再是数组,而是一个numpy.int或numpy.float的数据

In [31]: t1[2,3]
Out[31]: 13

In [32]: type(t1[2,3])
Out[32]: numpy.int32

取多个不相邻的元素,例如要取(0,0),(2,1),(2,3)这三个位置上的值
返回值将是包含上述三个位置值的一位数组

In [34]: t1
Out[34]:
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])

In [35]: t1[[0,2,2],[0,1,3]]	# 第一个方括号里确定行数,第二个方括号确定列数
Out[35]: array([ 0, 11, 13])

取多行多列交叉的值

In [36]: t1[2:5,1:4]
Out[36]:
array([[11, 12, 13],
       [16, 17, 18]])

(3)切片引用

观察下面四个例子
numpy的使用_第13张图片
a2[1] = 100不会对a1造成影响,因为a2 = a1[2:]传递的是若干个元素的地址
  b2[1] = 100之所以会对b1造成影响,因为b2 = b1[1]是浅拷贝,只拷贝引用,不拷贝对象
  c2[1] = 100会对c1造成影响,因为 c2 = c1[2:] 传递的是切片的引用,是把切片作为一个整体,而非“若干元素的”引用,这个和列表有明显的区别
  d2[1] = 100也会对d1造成影响,因为d2 = d1[1]同样传递的是切片的引用

  • 回忆“若干个元素的引用”与“整个列表的引用的区别”
    numpy的使用_第14张图片
    a3 = a1,是把列表的地址赋给a3,列表是一个整体,传递的是列表的地址
    a2 = a1[2:],是把a1的第2个以后的所有元素的地址赋给a2,传递的是若干个元素的地址

7 数组值的修改

(1)赋值修改

同前面的切片一样,再在右边加上一个赋值号,通过赋值号进行修改
numpy的使用_第15张图片
对数组切片的复制,如果类型不一致,则强制转化为数组的数据类型
numpy的使用_第16张图片

比如我们想要把t中小于10的数字替换为3,该如何实现?
numpy的使用_第17张图片

(2)三元运算符

numpy的使用_第18张图片

(3)范围裁剪numpy.clip

如果我们想把 t 中小于10的数字替换为10,把大于18的替换为18,应该怎么做?
numpy的使用_第19张图片

8 关于numpy.nan和numpy.inf

nan(NAN,Nan):not a number表示不是一个数字

什么时候numpy中会出现nan:
  当我们读取本地的文件为float的时候,如果有缺失,就会出现nan
  当做了一个不合适的计算的时候(比如无穷大(inf)减去无穷大)

inf(-inf,inf):infinity,inf表示正无穷,-inf表示负无穷

什么时候回出现inf包括(-inf,+inf)
  比如一个数字除以0,(python中直接会报错,numpy中是一个inf或者-inf)

那么如何指定一个nan或者inf呢?
注意他们的type类型
numpy的使用_第20张图片
  可以给某个元素直接赋numpy.nan或numpy.inf,但是必须先把原来的数据类型改成浮点型,否则会报错或者出现一些奇怪的数字。
numpy的使用_第21张图片
numpy的使用_第22张图片
两个np.nan是不相同的
numpy的使用_第23张图片
np.isnan(t) 返回一个和t形状相同的数组,数据类型为bool型
np.count_nonzero(t) 返回一个数组t中0(或者False)的个数

  那么问题来了,在一组数据中单纯的把nan替换为0,合适么?会带来什么样的影响?
  比如,全部替换为0后,替换之前的平均值如果大于0,替换之后的均值肯定会变小,所以更一般的方式是把缺失的数值替换为均值(中值)或者是直接删除有缺失值的一行

9 布尔索引

numpy的使用_第24张图片

10 常用统计函数

求和:t.sum(axis=None)
均值:t.mean(a,axis=None) 受离群点的影响较大
中值:np.median(t,axis=None)
最大值:t.max(axis=None)
最小值:t.min(axis=None)
极值:np.ptp(t,axis=None) 即最大值和最小值只差
标准差:t.std(axis=None)
  若未指定axis,默认返回多维数组的全部的统计结果,如果指定axis则返回一个当前轴上的结果

练习,将t1中的np.nan,替换成整个数组剩余元素的平均值。
其中t1为

t1 = np.arange(12).reshape(3,4).astype("float")
t1[2,:] = np.nan

相关代码

import numpy as np

t1 = np.arange(12).reshape(3,4).astype("float")
t1[2,:] = np.nan


def fill_ndarray(t1):
    for i in range(t1.shape[1]):
        temp_col = t1[:,i]	# 当前的一列
        nan_num = np.count_nonzero(temp_col!=temp_col)
        # 因为temp_col != temp_col返回的是一个bool型的矩阵,
        # 而np.nan!=np.nan的结果为True,np.count_nonzero统计的是矩阵中非零的个数
        # 因此可以统计其中True的个数,此即为temp_col中np.nan的个数

        if nan_num != 0:
            temp_not_nan_col = temp_col[temp_col == temp_col]
            # 如果temp_col中,某个位置的元素不是nan,那么这个位置上的结果则为True

            temp_col[np.isnan(temp_col)] = temp_not_nan_col.mean()
            # 在nan的位置上,赋上整个矩阵的均值

    # 由于切片赋值是浅拷贝,因此temp_col发生变化,t1也会发生变化
    return t1


if __name__ == '__main__':  # 直接敲入main,然后回车就行
    print(t1)
    t1 = fill_ndarray(t1)

    print(50*'-')
    print(t1)

11 数组的拼接

(1)一维数组的拼接

类似于列表的拼接,可以使用 np.append 方法
numpy的使用_第25张图片

(1)二维数组的拼接

numpy的使用_第26张图片
hstack也能用于一维数组的拼接
注意,上面两个方法中,参数都是元组。

(3)高维数组的拼接

定义两个三维数组
numpy的使用_第27张图片
numpy的使用_第28张图片
numpy的使用_第29张图片
上面的三张图片可以看到,concatenate 可以实现在指定轴上的拼接,axis=0,则表示在0轴,即拼接的时候,只打开一个方括号,axis=1,则打开两个方括号,axis=2,则打开三个方括号,即 concatenate 不仅可以拼接高维数组,也能拼接低维数组。

12 数组的切割

(1)水平竖直分割

竖直分割
numpy的使用_第30张图片
可以看到,hsplit返回的是由分割结果得到的列表。
上面的hsplit第二个参数是 3,表示均匀分割成三份,每份的列数一样

如果不想均匀分怎么办?可以用一个元组代替,元组中的数字表示划线位置
numpy的使用_第31张图片
水平分割 vsplit 的用法与 hsplit 一致。

(2)按指定轴分割

同前面np.contenate类似,在第几个轴上分割,axis就设置为几
numpy的使用_第32张图片
numpy的使用_第33张图片
如果不想均分,也可以用元组的方法,指定划线位置
numpy的使用_第34张图片

(3)按深度分割

把最深的索引一致的元素拿出来构成新的数组
numpy的使用_第35张图片
上图红色框中,a[0, 0, 0],a[0, 1, 0],a[1, 0, 0],a[1, 1, 0]这四个数的最后一个索引都是0,将它们取出,组成一个数组,维度数与前面保持一致,都保持三维。
b中的另外两个元素,与b[0]一致。

13 行与行的交换、列与列的交换

numpy的使用_第36张图片

14 线性代数相关操作

下面的操作适合二维数组

(1)转置

最简单的是t.T,常用的还有t.transpose()

In [40]: t
Out[40]:
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

In [41]: t.T
Out[41]:
array([[0, 5],
       [1, 6],
       [2, 7],
       [3, 8],
       [4, 9]])

In [42]: t.transpose()
Out[42]:
array([[0, 5],
       [1, 6],
       [2, 7],
       [3, 8],
       [4, 9]])

transpose还可以实现对多个维度的转置
numpy的使用_第37张图片
numpy的使用_第38张图片

可以看到,np.transpose(a, (1, 2, 0))其实就是进行了下面的操作

b[k, i, j] = a[i, j, k]

(2)矩阵乘法

a 对应位置乘积

既可以用 * 号,也可以用 np.multiply
numpy的使用_第39张图片

b 矩阵乘积

使用 np.dot 实现
numpy的使用_第40张图片

(3)求行列式

np.linalg.det()
numpy的使用_第41张图片

(4)求逆

np.linalg.inv 对矩阵求逆

A = np.array([[0,1,2],
              [1,0,3],
              [4,-3,8]])

print("A = ")
print(A)
print()

inverse = np.linalg.inv(A)
print("A的逆矩阵:")
print(inverse)
print()

输出

A = 
[[ 0  1  2]
 [ 1  0  3]
 [ 4 -3  8]]

A的逆矩阵:
[[-4.5  7.  -1.5]
 [-2.   4.  -1. ]
 [ 1.5 -2.   0.5]]

(5)解线性方程组

np.linalog.solve
numpy的使用_第42张图片
这里要注意b的维度,深度学习中,即便是向量,也是将其当成二维数组来,这样可以避免一些未知的错误。

当然,b如果为一维的,也能得到结果
numpy的使用_第43张图片

(6)特征值和特征向量

numpy的使用_第44张图片
numpy的使用_第45张图片

15 随机函数

(1)随机抽样

np.random.
numpy的使用_第46张图片
如果指定np.seed(1),那么程序每次运行的时候,生成的随机数都是相同的,如果未指定,则不同

以 np.random.rand 为例介绍 random 模块的使用
numpy的使用_第47张图片

(2)打乱顺序

a 原地打乱 shuffle

现场修改序列,改变自身内容。(类似洗牌,打乱顺序)numpy的使用_第48张图片

shuffle 只能对第一个索引(即axis=0)进行操作
numpy的使用_第49张图片

b 非原地打乱 permutation

permutation(x)

x若为数组,那么就返回打乱后的结果,但 x 不变
numpy的使用_第50张图片
x若为一个整数,那么就生成一个 0-x 序列,并打乱
在这里插入图片描述

random模块的其他常用函数,可以见这篇博客(其实帖子也没必要看,上面介绍的抽样和打乱的几个方法,已经完全够用了):
https://www.cnblogs.com/zuoshoushizi/p/8727773.html

16 其他常用方法

(1)获取最大值最小值的索引

  np.argmax(t,axis=0) (对0轴数据进行折叠)
  np.argmin(t,axis=1) (对1轴数据进行折叠)

(2)全零数组,全一数组,单位矩阵

  创建一个全0的数组: np.zeros((3,4))
  创建一个全1的数组:np.ones((3,4))
  创建一个对角线为1的正方形数组(方阵):np.eye(3)

(3)真值测试函数

  np.all 如果全为True,则返回True,否则返回 False
  np.any 只要存在一个True,就返回True,如果一个都没有,那就返回False

17 练习

  现有英国用户在youtube的1000多个视频的“点击,喜欢,不喜欢,评论”数量([“views”,“likes”,“dislikes”,“comment_total”])的csv文件,绘制评论数和喜欢数的散点图

import numpy as np
from matplotlib import pyplot as plt

uk_file_path = "./youtube_video_data/GB_video_data_numbers.csv"

t_uk = np.loadtxt(uk_file_path,delimiter=",",dtype="int")

t_uk = t_uk[t_uk[:,-1]<50000]   # 通过bool索引来筛选,将评论大于5万的去掉
# 之所以要筛选5万以下的,是因为评论数超过5万视频,太少了
# print(t_uk)

plt.figure(figsize=(10,6), dpi=80)
plt.scatter(t_uk[:,1],t_uk[:,-1])
# 第一列是喜欢数,最后一列是评论数
plt.show()

输出
numpy的使用_第51张图片

你可能感兴趣的:(数据科学库,numpy)