摘要
- 什么是numpy
- numpy基础
- numpy常用方法
- numpy常用统计方法
为什么要学习numpy:1. 快速;2. 方便;3. 科学计算的基础库
numpy是一个在Python中做科学计算的基础库,重在数值计算
,也是大部分PYTHON科学计算库的基础库,多用于在大型、多维数组上执行数值运算
1. 使用numpy生成数组,得到ndarray
NumPy的核心特征之一就是N维数组对象ndarry
。ndarry是Python中一个快速、灵活的大型数据集容器。数组允许使用类似于标量的操作语法在整块数据上进行数学计算。
一个ndarry是一个通用的多维同类数据容器,也就是说它包含的每一个元素均为相同类型。每一个数组都有一个shape
属性,用来表征数组每一维度的数量; 每一个数组都有一个dtype
属性,用来描述数组的数据特征。
- 创建ndarray的3种方法
import numpy as np
#方法1
t1=np.array([1,2,3]) #传入列表
print(t1)
print(type(t1))
#[1 2 3]
# <class 'numpy.ndarray'>
#方法2
t2=np.array(range(10)) #传入range生成的可迭代对象
print(t2)
print(type(t2))
# [0 1 2 3 4 5 6 7 8 9]
# <class 'numpy.ndarray'>
#方法3 和2原理一样
t3=np.arange(4,10,2) ##np.arange()等同于np.array(range())
print(t3)
print(type(t3))
# [4 6 8]
# <class 'numpy.ndarray'>
- 数组类型(dtype)的操作
print(t3.dtype)
#int64
t4=t3.astype(np.int8) #修改数组的数据类型
print(t4.dtype)
#int8
t5=np.array(range(1,4),dtype='float') #指定创建数组的数据类型
print(t5)
print(t5.dtype)
# [1. 2. 3.]
# float64
import random
t6=np.array([random.random() for i in range(10)]) #random.random()用于生成一个0到1的随机符点数: 0 <= n < 1.0
print(t6)
print(t6.dtype)
# [0.2530124 0.19825549 0.61507 0.36285379 0.9481657 0.67246082
# 0.80597906 0.24741171 0.73392225 0.97530711]
# float64
t7=np.round(t5,2) #修改浮点型的小数位数
print(t)
print(t7.dtype)
# [0.58 0.27 0.22 0.2 0.23 0.94 0.64 0.77 0.81 0.54]
# float64
python中常见的更多数据类型
- 数组的形状
import numpy as np
t1=np.arange(12)
print(t1)
print(t1.shape)
# [ 0 1 2 3 4 5 6 7 8 9 10 11]
# (12,)
t2=np.array([[1,2,3],[4,5,6]])
print(t2)
print(t2.shape)
# [[1 2 3]
# [4 5 6]]
# (2, 3)
t3=np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
print(t3)
print(t3.shape)
# [[[ 1 2 3]
# [ 4 5 6]]
# [[ 7 8 9]
# [10 11 12]]]
# (2, 2, 3)
修改数组的形状
⚠️ reshape方法是有返回值return的,其本身没有发生变化
t1.reshape((3,4)) #传入元组
print(t1.reshape((3,4)))
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(t1)
print(t1.shape)
# [ 0 1 2 3 4 5 6 7 8 9 10 11]
# (12,)
#需要用新的变量来接收
t4=t1.reshape((3,4))
print(t4)
print(t4.shape)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# (3, 4)
t5=np.arange(24).reshape((2,3,4))
print(t5)
print(t5.shape)
# [[[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
#
# [[12 13 14 15]
# [16 17 18 19]
# [20 21 22 23]]]
# (2, 3, 4)
t6=np.arange(4) #注意t6 t7和t8的区别
print(t6)
print(t6.shape)
# [0 1 2 3]
# (4,)
t7=t6.reshape((4,1))
print(t7)
print(t7.shape)
# [[0]
# [1]
# [2]
# [3]]
# (4, 1)
t8=t6.reshape((1,4))
print(t8)
print(t8.shape)
# [[0 1 2 3]]
# (1, 4)
t9=t4.reshape((t4.shape[0]*t4.shape[1],)) #在不知道有多少个值存在的情况下二维转一维。shape[0]是行数,shape[1]是列数。
print(t9)
print(t9.shape)
# [ 0 1 2 3 4 5 6 7 8 9 10 11]
# (12,)
t10=t4.flatten() #flatten可以直接二维转一维
print(t10)
print(t10.shape)
# [ 0 1 2 3 4 5 6 7 8 9 10 11]
# (12,)
2. 数组的计算
数组和数的计算:
numpy具有广播机制,在运算过程中,加减乘除的值被光波到所有元素上面
import numpy as np
t1=np.arange(12)
print(t1)
# [ 0 1 2 3 4 5 6 7 8 9 10 11]
print(t1+1)
# [ 1 2 3 4 5 6 7 8 9 10 11 12]
print(t1*3)
# [ 0 3 6 9 12 15 18 21 24 27 30 33]
维度相同的数组和数组的计算:
t2=t1+10
print(t2)
# [10 11 12 13 14 15 16 17 18 19 20 21]
t3=t1*t2
print(t3)
# [ 0 11 24 39 56 75 96 119 144 171 200 231]
维度不同的数组和数组的计算:
⚠️广播原则:
如果两个数组的后缘维度(trailing dimension,即从末尾开始算起的维度)的轴长度相符或者其中一方的长度为1,则认为它们是广播兼容的。广播会在缺失和(或)长度为1的维度上进行。
维度可以理解为shape所对应的数字个数
t4=np.arange(4).reshape(4,1)
print(t4)
# [[0]
# [1]
# [2]
# [3]]
t5=np.arange(24).reshape((2,4,3))
print(t5)
# [[[ 0 1 2]
# [ 3 4 5]
# [ 6 7 8]
# [ 9 10 11]]
#
# [[12 13 14]
# [15 16 17]
# [18 19 20]
# [21 22 23]]]
t6=t5-t4
print(t6)
# [[[ 0 1 2]
# [ 2 3 4]
# [ 4 5 6]
# [ 6 7 8]]
#
# [[12 13 14]
# [14 15 16]
# [16 17 18]
# [18 19 20]]]
轴的概念:
在numpy中可以理解为方向,使用0,1,2...数字表示,对于一个一维数组,只有一个0轴,对于2维数组(shape(2,2)),有0轴和1轴,对于三维数组(shape(2,2, 3)),有0,1,2轴
有了轴的概念之后,我们计算会更加方便,比如计算一个2维数组的平均值,必须指定是计算哪个方向上面的数字的平均值
回顾np.arange(0,10).reshape((2,5)),reshpe中2表示0轴长度(包含数据的条数)为2,1轴长度为5,2X5一共10个数据
二维数组axis=0表示作用于行,axis=1表示作用于列
x.shape[0]是取行 (方括号里的内容),x.shape[1]是取列 (方括号间对应部分的内容) 。
3. numpy读取本地数据和切片索引操作
pandas比numpy读取数据功能更强大,所以numpy读取数据功能只需简单了解即可
- 读取:
语法:
np.loadtxt(frame,dtype=np.float,delimiter=None,skiprows=0,usecols=None,unpack=False)
(loadtxt并不是说只能从txt读取文件,而是读取文本文件)
参数 | 解释 |
---|---|
frame |
文件、字符串或产生器(文件路径),可以是.gz或bz2压缩文件 |
dtype |
数据类型,csv的字符串以什么数据类型读入数组中。默认是np.float,默认情况下对于较大的数据会将其变为科学计数的方式 |
delimiter |
分隔字符串,默认是任何空格。读取csv是设置为"," |
skiprows | 跳过前x行,一般跳过第一行表头 |
usecols | 读取指定的列,索引,元组类型 |
unpack | 默认为False。如果为True,读入属性将分别写入不同的数组变量,False读入数据只写入一个数组变量。(即:转置) |
import numpy as np
us_file_path='../youtube_video_data/US_video_data_numbers.csv'
#如果不设置delimiter会报错,如果不设置dtype出来的数字是科学计数法的形式
t1=np.loadtxt(us_file_path,delimiter=",",dtype='int')
t2=np.loadtxt(us_file_path,delimiter=",",dtype='int',unpack=True) #unpack=True,发生了行和列的转置
print(t1)
print('*'*100)
print(t2)
# [[4394029 320053 5931 46245]
# [7860119 185853 26679 0]
# [5845909 576597 39774 170708]
# ...
# [ 142463 4231 148 279]
# [2162240 41032 1384 4737]
# [ 515000 34727 195 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]]
练习题:
英国和美国各自youtube1000的数据结合之前的matplotlib绘制出各自的评论数量的直方图
希望了解英国的youtube中视频的评论数和喜欢数的关系,应该如何绘制改图
import numpy as np
from matplotlib import pyplot as plt
#第1题
us_file_path='../youtube_video_data的副本/US_video_data_numbers.csv'
t_us=np.loadtxt(us_file_path,delimiter=",",dtype='int')
# 选取评论的数据
t_us_comments=t_us[:,-1] #-1是取最后一行
t_us_comments=t_us_comments[t_us_comments<=5000] #有极值,所以只取小于5000的值
#绘制直方图
print(t_us_comments.max(),t_us_comments.min())
#582505 0
d=100
bin_nums=(t_us_comments.max()-t_us_comments.min())//d
#绘图
plt.figure(figsize=(20,8),dpi=300)
plt.hist(t_us_comments,bin_nums)
plt.show()
#第2题
uk_file_path='../youtube_video_data的副本/GB_video_data_numbers.csv'
t_uk=np.loadtxt(uk_file_path,delimiter=",",dtype='int')
#选择喜欢数比50万小的数据
t_uk=t_uk[t_uk[:,1]<=500000]
t_uk_comments=t_uk[:,-1]
t_uk_likes=t_uk[:,1]
plt.figure(figsize=(20,8),dpi=300)
plt.scatter(t_uk_likes,t_uk_comments)
plt.show()
- 二维数组转置的三种方式:
transpose
,T
和swapaxes
转置是一种变换,对于numpy中的数组来说,就是在对角线方向交换数据,目的也是为了更方便的去处理数据
import numpy as np
t1=np.arange(24).reshape((4,6))
print(t1)
# [[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# [12 13 14 15 16 17]
# [18 19 20 21 22 23]]
print(t1.transpose())
# [[ 0 6 12 18]
# [ 1 7 13 19]
# [ 2 8 14 20]
# [ 3 9 15 21]
# [ 4 10 16 22]
# [ 5 11 17 23]]
print(t1.T)
# [[ 0 6 12 18]
# [ 1 7 13 19]
# [ 2 8 14 20]
# [ 3 9 15 21]
# [ 4 10 16 22]
# [ 5 11 17 23]]
print(t1.swapaxes(1,0))
# [[ 0 6 12 18]
# [ 1 7 13 19]
# [ 2 8 14 20]
# [ 3 9 15 21]
# [ 4 10 16 22]
# [ 5 11 17 23]]
- ⚠️numpy索引和切片
import numpy as np
us_file_path='../youtube_video_data的副本/US_video_data_numbers.csv'
t1=np.loadtxt(us_file_path,delimiter=",",dtype='int')
print(t1)
#取单行
print(t1[2])#取第三行
print(t1[2,:]) #和上一行作用相同。逗号前表示行,逗号后表示列。冒号表示所有列都要
#取连续的多行
print(t1[2:]) #取3到最后一行
print(t1[2:,:])
#取不连续的多行
print(t1[[2,8,10]]) #取3,9,11行
print(t1[[2,8,10],:])
#取单列
print(t1[:,0]) #第一列
#取连续的多列
print(t1[:,2:]) #取3到最后一列
#取不连续的多列
print(t1[:,[2,8,10]]) #取3,9,11列
#取多行多列 (取行和列交叉点的位置)
print(t1[2,3]) #取3行4列
print(t1[2:5,1:4]) #取3到5行,2到4列
#取多个不相邻的点(前面方括号里的行和后面方括号里的列一一对应)
print(t1[[0,2,2],[0,1,3]]) #取坐标为(0,0)(2,1)(2,3)的这三个点
- numpy中数值的修改(赋值)
- 修改单个值的话,直接用索引找到那个值再用=赋值即可
- 批量修改--采用布尔索引
import numpy as np
t=np.arange(24).reshape(4,6)
print(t)
#把t中小于0的数字替换为3
print(t<10)
#[[ True True True True True True]
# [ True True True True False False]
# [False False False False False False]
# [False False False False False False]]
t[t<10]=3
print(t)
# [[ 3 3 3 3 3 3]
# [ 3 3 3 3 10 11]
# [12 13 14 15 16 17]
# [18 19 20 21 22 23]]
- 批量修改--python中的三元运算符 np.where(判断式,T时返回的值,F时返回的值)
import numpy as np
t=np.arange(24).reshape(4,6)
print(t)
#将小于等于3的替换成100,否则替换成300
t1=np.where(t<=3,100,300) #np.where没有返回值,需要用变量接收
print(t1)
# [[100 100 100 100 300 300]
# [300 300 300 300 300 300]
# [300 300 300 300 300 300]
# [300 300 300 300 300 300]]
- clip(裁剪)操作
可用于去除极值
import numpy as np
t=np.arange(24).reshape(4,6)
print(t)
#将小于等于10的替换成10,大于10的替换成18
t1=t.clip(10,18)
print(t1)
# [[10 10 10 10 10 10]
# [10 10 10 10 10 11]
# [12 13 14 15 16 17]
# [18 18 18 18 18 18]]
4. numpy中的nan和常用方法以及inf
nan(NAN,Nan):not a number表示不是一个数字
当我们读取本地的文件为float的时候,如果有缺失,就会出现nan
当做了一个不合适的计算的时候(比如无穷大(inf)减去无穷大)也会出现nan
inf(-inf,inf):infinity,inf表示正无穷,-inf表示负无穷
什么时候回出现inf包括(-inf,+inf)
比如一个数字除以0,(python中直接会报错,numpy中是一个inf或者-inf)
- nan的注意点:
- nan和inf都是浮点型⚠️
import numpy as np
a=np.nan
print(type(a))
# <class 'float'>
b=np.inf
print(type(b))
# <class 'float'>
- 两个nan是不相等的
import numpy as np
print(np.nan==np.nan)
# False
print(np.nan!=np.nan)
#True
- 可以使用np.isnan()来判断一个数字是不是nan
import numpy as np
t1=np.arange(15,dtype=float).reshape(3,5)
t1[2,2]=np.nan
print(t1)
# [[ 0. 1. 2. 3. 4.]
# [ 5. 6. 7. 8. 9.]
# [10. 11. nan 13. 14.]]
print(np.isnan(t1))
# [[False False False False False]
# [False False False False False]
# [False False True False False]]
- 利用2和3的特点,使用 np.count_nonzero来统计数组中nan的个数
import numpy as np
t1=np.arange(15,dtype=float).reshape(3,5)
t1[2,2]=np.nan
print(t1)
# [[ 0. 1. 2. 3. 4.]
# [ 5. 6. 7. 8. 9.]
# [10. 11. nan 13. 14.]]
print(np.count_nonzero(t1!=t1)) #只有nan才不等于它本身
#1
print(np.count_nonzero(np.isnan(t1)))
#1
- nan和任何值计算都是nan
import numpy as np
t1=np.arange(15,dtype=float).reshape(3,5)
t1[2,2]=np.nan
print(np.sum(t1))
# nan
print(t1)
# [[ 0. 1. 2. 3. 4.]
# [ 5. 6. 7. 8. 9.]
# [10. 11. nan 13. 14.]]
print(np.sum(t1,axis=0))
#[15. 18. nan 24. 27.]
- numpy中常用统计函数
思考:在一组数据中单纯的把nan替换为0会带来什么样的影响?
全部替换为0后,替换之前的平均值如果大于0,替换之后的均值肯定会变小,所以更一般的方式是把缺失的数值替换为均值(中值)或者是直接删除有缺失值的一行
将nan替换成列的均值:
import numpy as np
t1=np.arange(12,dtype=float).reshape(3,4)
t1[1,2:]=np.nan
print(t1)
# [[ 0. 1. 2. 3.]
# [ 4. 5. nan nan]
# [ 8. 9. 10. 11.]]
# [12. 15. nan 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)
if nan_num !=0:
temp_not_nan_col=temp_col[temp_col==temp_col] #当前这一列不为n的array
temp_col[np.isnan(temp_col)]=temp_not_nan_col.mean() #选中当前为nan的位置,把值赋值为不为nan的均值
pass
return t1
t2=fill_ndarray(t1)
print(t2)
# [[ 0. 1. 2. 3.]
# [ 4. 5. 6. 7.]
# [ 8. 9. 10. 11.]]
pandas有更容易的方法处理缺失值
5. 数组的拼接和行列交换
- 竖直拼接和水平拼接:
import numpy as np
t1=np.arange(12).reshape(2,6)
print(t1)
# [[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]]
t2=np.arange(12,24).reshape(2,6)
print(t2)
# [[12 13 14 15 16 17]
# [18 19 20 21 22 23]]
t3=np.vstack((t1,t2)) #竖直拼接vertically
print(t3)
# [[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# [12 13 14 15 16 17]
# [18 19 20 21 22 23]]
t4=np.hstack((t1,t2)) #水平拼接horizontally
print(t4)
# [[ 0 1 2 3 4 5 12 13 14 15 16 17]
# [ 6 7 8 9 10 11 18 19 20 21 22 23]]
竖直切割和水平切割是竖直拼接和水平拼接的逆操作
- 行列交换
数组水平或者竖直拼接之前应该注意:
竖直拼接的时候:每一列代表的意义相同!!!否则牛头不对马嘴。如果每一列的意义不同,这个时候应该交换某一组的数的列,让其和另外一类相同。水平拼接时也是一样
import numpy as np
t1=np.arange(12,24).reshape(3,4)
print(t1)
# [[12 13 14 15]
# [16 17 18 19]
# [20 21 22 23]]
t1[[1,2],:]=t1[[2,1],:] #行交换(第2行和第3行交换)
print(t1)
# [[12 13 14 15]
# [20 21 22 23]
# [16 17 18 19]]
t1[:,[0,2]]=t1[:,[2,0]] #列交换(第1行和第3行交换)
print(t1)
# [[14 13 12 15]
# [22 21 20 23]
# [18 17 16 19]]
练习:把之前案例中两个国家的数据方法一起来研究分析,同时保留国家的信息(每条数据的国家来源)。
import numpy as np
#加载国家数据
us_file_path='../youtube_video_data的副本/US_video_data_numbers.csv'
us_data=np.loadtxt(us_file_path,delimiter=",",dtype='int')
uk_file_path='../youtube_video_data的副本/GB_video_data_numbers.csv'
uk_data=np.loadtxt(uk_file_path,delimiter=",",dtype='int')
#添加 国家信息(用0和1来代表)
zero_data=np.zeros((us_data.shape[0],1)).astype(int)
ones_data=np.ones((uk_data.shape[0],1)).astype(int)
us_data=np.hstack((us_data,zero_data))
uk_data=np.hstack((uk_data,ones_data))
#拼接两组数据
final_data=np.vstack((us_data,uk_data))
print(final_data)
# [[4394029 320053 5931 46245 0]
# [7860119 185853 26679 0 0]
# [5845909 576597 39774 170708 0]
# ...
# [ 109222 4840 35 212 1]
# [ 626223 22962 532 1559 1]
# [ 99228 1699 23 135 1]]
- numpy更多好用的方法
1.获取最大值最小值的位置
np.argmax(t,axis=0)
np.argmin(t,axis=1)
2.创建一个全0的数组: np.zeros((3,4))
3.创建一个全1的数组:np.ones((3,4))
4.创建一个对角线为1的正方形数组(方阵):np.eye(3)
5.numpy生成随机数
- numpy的注意点copy和view
a=b 完全不复制,a和b相互影响
a = b[:],视图的操作,一种切片,会创建新的对象a,但是a的数据完全由b保管,他们两个的数据变化是一致的,
a = b.copy(),复制,a和b互不影响
6. 小结
- 如何选择一行或者多行的数据(列)?
- 如何给选取的行或者列赋值?
- 如何把大于10的值替换为10?
- np.where如何使用?
- np.clip如何使用?
- 如何转置(交换轴)?
- 读取和保存数据为csv
- np.nan和np.inf是什么
- 常用的统计函数你记得几个?
- 标准差反映出数据的什么信息?
参考:https://www.runoob.com/numpy/numpy-array-from-existing-data.html