学习视频是B站的,【不愧是清华大佬!把Python数据分析讲得如此简单明了!从入门到精通保姆级】,经常被下架,所以没添加链接
一、jupyter notebook安装与使用
参考链接1:Jupyter NoteBook下载、安装、numpy安装、pandas安装、代码补全
参考链接2:jupyter notebook的基本使用
参考链接3:Jupyter Notebook介绍、安装及使用教程
按h会弹出各种快捷键,或者点右上角的帮助
注意:Ananconda和Jupyter NoteBook不能同时有好像,在安装配置好Ananconda后,黑窗口会自动关闭Jupyter NoteBook进程
二、Numpy
高效的用于处理数值型运算的包。
1. Numpy数组和Python列表性能对比
jupyter notebook代码运行原理:把所有运行了的变量存储在内存中,作为全局变量使用,如果后面cell中的代码修改了之前的cell中的值,可能会得不到预期结果,甚至报错,解决方案是点击工具栏里面的 >> 两个箭头按钮,让它从第一个cell运行一下。
2.Numpy库数组创建方式
# 创建数组的几种方式
import numpy as np
# 1.使用np.array来创建
# 此处a是数组,打印时没有逗号,而上面一个是列表,打印时有逗号
a = np.array([1,2,3,4])
print(a)
print(type(a))
# 2.使用np.arange创建数组
b = np.arange(10)# 产生0-9之间的数
print(b)
b
print(type(b))
c = np.arange(0,5,2) # 0-4之间的数,步长为2
c
print(c)
print(type(c))
# 3.使用 np.random.random来创建一个N行N列的数组,其中里面的值是0-1之间的随机数
d1 = np.random.random((2,2)) # 生成2行2列的随机数的数组
print("d1 = ")
print(d1)
# 4.np.random.randint来创建一个N行N列的数组,其中值的范围可以通过前面2个参数来指定
d2 = np.random.randint(0,10,size=(3,3)) # 元素是从0-10之间随机的3行3列的数组
print("d2 = ")
print(d2)
# 特殊函数
# 5.np.zeros生成一个所有元素都是0是N行N列数组
a1 = np.zeros((2,2))
print("a1 = ")
print(a1)
# 6.np.ones生成一个所有元素都是1的N行N列数组
a2 = np.ones((3,2))
print("a2 = ")
print(a2)
# 7.np.full((2,2),8)生成一个所有元素都是8的2行2列数组
a3 = np.full((2,2),8)
print("a3 = ")
print(a3)
# 8.np.eye(3) 生成一个3X3的对角矩阵
a4 = np.eye(3)
print("a4 = ")
print(a4)
运行结果:
[1 2 3 4]
<class 'numpy.ndarray'>
[0 1 2 3 4 5 6 7 8 9]
<class 'numpy.ndarray'>
[0 2 4]
<class 'numpy.ndarray'>
d1 =
[[0.48480631 0.31354445]
[0.23397893 0.63337708]]
d2 =
[[4 2 2]
[8 4 3]
[5 8 1]]
a1 =
[[0. 0.]
[0. 0.]]
a2 =
[[1. 1.]
[1. 1.]
[1. 1.]]
a3 =
[[8 8]
[8 8]]
a4 =
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
3. 数组数据类型
import numpy as np
a = np.arange(10)
print(a)
print(a.dtype)
# b = np.array([1,2,3,4,5],dtype=np.int8)
# 或者
b = np.array([1,2,3,4,5],dtype='i')
print(b)
print(b.dtype)
c = np.array([1,2,3,4,5],dtype=np.float16)
print(c)
print(c.dtype)
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
d = np.array([Person('小明',18),Person('李华',20)])
print(d)
print(d.dtype)
# bytes编码后的字符串数据类型
f = np.array(['a','b'],dtype = 'S')
print(f)
print(f.dtype)
# Unicode编码的字符串数据类型
e = np.array(['a','c'],dtype = 'U')
print(e)
print(e.dtype)
# astype不会修改数组本身,而是会将修改后的结果返回
uf =f.astype('U') # 修改为Unicode编码格式
print(uf)
print(uf.dtype)
print(f.dtype)
输出:
[0 1 2 3 4 5 6 7 8 9]
int32
[1 2 3 4 5]
int32
[1. 2. 3. 4. 5.]
float16
[<__main__.Person object at 0x000001D2CF9EA970>
<__main__.Person object at 0x000001D2CFA09160>]
object
[b'a' b'b']
|S1
['a' 'c']
<U1
['a' 'b']
<U1
|S1
总结:
4. 多维数组
import numpy as np
# 一维数组 -- 可以包含很多个数据
a1 = np.array([1,2,3])
print(a1)
print(a1.ndim) # 查看数组维度
# 二维数组 -- 一个二维数组是一个元素,可以包含很多个一维数组
a2 = np.array([[1,2,3],[4,5,6]])
print("============")
print(a2)
print(a2.ndim)
# 三维数组 -- 一个三维数组可以包含很多个二维数组,也就是可以包含很多个元素
a3 = np.array([
[
[1,2,3],
[4,5,6]
],
[
[7,8,9],
[10,11,12]
]
])
print("============")
print(a3)
print(a3.ndim)
a4 = np.array([
[
[1,2,3],
[4,5,6]
],
[
[7,8,9],
[10,11,12]
],
[
[13,14,15],
[16,17,18]
],
[
[13,14,15],
[16,17,18]
]
])
print("============")
print(a4)
print(a4.ndim)
# 数组的shape,【输出的结果中有几个数据就是几维度,而不是明确写出来是几个维度】
# 通过ndarray.shape可以看到数组的形状(几行几列),shape是一个元组,里面有几个元素代表是几维数组
print("============")
print(a1.shape) # 输出(3,)含义:有3个数据,一维数组
print(a2.shape) # 输出(2, 3)含义:2行3列,二维数组,
print(a3.shape) # 输出(2, 2, 3)含义:有2个元素,每个元素是2行3列,三维数组
# help(np.shape)
# 通过 ndarray.reshape 来重新修改数组的维数,
# 修改后的元素个数必须和原来的个数一致,本质不会修改原来数组的形状
# a3是3维,两个元素,每个元素都是2行3列的二维数组,一共2*2*3 = 12个数据
# 现将其变为一个2行6列的二维数组a5
a5 = a3.reshape((2,6))
print("============")
print(a5)
print(a5.shape)
print(a5.ndim)
# 注意:转换为一维数组时写不写前面的1???如果写了就是二维数组,不是一维数组
a6 = a3.reshape((1,12)) # 这仍然是一个二维数组
print("============")
print(a6)
print(a6.shape)
print(a6.ndim)
# 数组一维化 -- 方法1
a7 = a3.reshape((12,)) # 这是一个一维数组,只写一个数据就行了
print("============")
print(a7)
print(a7.shape)
print(a7.ndim)
# 数组一维化 -- 方法2
a8 = a3.flatten()
print("============")
print(a8)
print(a8.shape)
print(a8.ndim)
# ndarray.size获取数组中总的元素的个数
count = a3.size
print("============")
print(count)
# ndarray.itemsize数组中每个元素占的大小,单位是字节
itemsize = a3.itemsize
print("============")
print(itemsize)
print(a3.dtype)
# 计算a3所占字节数
print(a3.itemsize*a3.size)
输出:
[1 2 3]
1
============
[[1 2 3]
[4 5 6]]
2
============
[[[ 1 2 3]
[ 4 5 6]]
[[ 7 8 9]
[10 11 12]]]
3
============
[[[ 1 2 3]
[ 4 5 6]]
[[ 7 8 9]
[10 11 12]]
[[13 14 15]
[16 17 18]]
[[13 14 15]
[16 17 18]]]
3
============
(3,)
(2, 3)
(2, 2, 3)
============
[[ 1 2 3 4 5 6]
[ 7 8 9 10 11 12]]
(2, 6)
2
============
[[ 1 2 3 4 5 6 7 8 9 10 11 12]]
(1, 12)
2
============
[ 1 2 3 4 5 6 7 8 9 10 11 12]
(12,)
1
============
[ 1 2 3 4 5 6 7 8 9 10 11 12]
(12,)
1
============
12
============
4
int32
48
5. 数组索引和切片
(1)索引和切片
import numpy as np
# 1. 一维数组的索引和切片
a1 = np.arange(10)
print(a1)
# 1.1 进行索引操作,下标从0开始
print("a1[4] = ",a1[4])
# 1.2 进行切片操作,此处让其输出 4 5
print("a1[4:6] = ",a1[4:6])
# 1.3 使用步长切片操作
print("a1[::2] = ",a1[::2])
# 1.4 使用负数来作为索引
print("a1[-4] = ",a1[-4])
# 2. 多维数组
# 也是通过中括号来索引和切片,在中括号中,使用逗号进行分割,逗号前面是行,后面是列
# 如果多维数组中只有一个值,那么这个值就是行
print("=======================")
a2 = np.random.randint(0,10,size=(4,6)) # 产生4行6列的0-9之间的随机整数
print("a2 = ")
print(a2)
print("a2第0行数组:",a2[0])
print("a2第0行0列数数据:",a2[0,0])
print("a2第1、2行数组:",a2[1:3])
# 或者
a2[1:3]
print("a2第0、2、3行数组:")
print(a2[[0,2,3]])
print("获取a2中的两个元素:a2[1,2]和a2[4,5] = ",a2[[1,2],[4,5]])
print("获取a2中最中间4个数据:")
print(a2[1:3,2:4])
print("获取第一列数据:")
print(a2[:,1]) # 前面表示获取所有行,然后再获取每行的第1列
输出:
[0 1 2 3 4 5 6 7 8 9]
a1[4] = 4
a1[4:6] = [4 5]
a1[::2] = [0 2 4 6 8]
a1[-4] = 6
=======================
a2 =
[[4 5 7 0 5 0]
[8 2 9 8 4 8]
[5 0 8 3 3 6]
[2 8 7 6 7 1]]
a2第0行数组: [4 5 7 0 5 0]
a2第0行0列数数据: 4
a2第1、2行数组: [[8 2 9 8 4 8]
[5 0 8 3 3 6]]
a2第0、2、3行数组:
[[4 5 7 0 5 0]
[5 0 8 3 3 6]
[2 8 7 6 7 1]]
获取a2中的两个元素:a2[1,2]和a2[4,5] = [4 6]
获取a2中最中间4个数据:
[[9 8]
[8 3]]
获取第一列数据:
[5 2 0 8]
(2)布尔索引
# 布尔索引
import numpy as np
a3 = np.arange(24).reshape((4,6))
print(a3)
a3 < 10 # 返回一个与a3相同形状的布尔数组
a3[a3 < 10] #提取a3中小于10的元素,也可以说是提取布尔数组中值为True的位置所代表的数据
a3[(a3>5) & (a3<10)] # 返回5<a3<10的数据
输出:
[[ 0 1 2 3 4 5]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]
[18 19 20 21 22 23]]
array([6, 7, 8, 9])
(3)数组值的替换
# 数组值的替换
import numpy as np
a4 = np.random.randint(0,10,size=(3,5)) # 3行5列的0-9之间的二维数组
print("修改之前的数组:")
print(a4) # 不建议直接写a4输出,因为可能会造成覆盖
# a4第一行数据全部修改为0
a4[1] = 0
print("修改之后的数组:")
print(a4)
# a4第一行数据修改为特定的值,而不是统一修改为一样的数值
a4[1] = np.array([1,2,3,4,5])
print("修改之后的数组:")
print(a4)
# 将a4中所有小于3的数据都替换为1 -- 条件索引
a4[a4 < 3] = 1
print("修改之后的数组:")
print(a4)
# where函数
# 获取a4中元素小于5的位置
result1 = np.where(a4<5)
print(result1)
# 将小于5的替换为0,大于5的替换为1
result2 = np.where(a4<5,0,1)
print(result2)
输出:
修改之前的数组:
[[2 4 9 4 5]
[3 4 8 5 4]
[8 3 7 1 7]]
修改之后的数组:
[[2 4 9 4 5]
[0 0 0 0 0]
[8 3 7 1 7]]
修改之后的数组:
[[2 4 9 4 5]
[1 2 3 4 5]
[8 3 7 1 7]]
修改之后的数组:
[[1 4 9 4 5]
[1 1 3 4 5]
[8 3 7 1 7]]
(array([0, 0, 0, 1, 1, 1, 1, 2, 2], dtype=int64), array([0, 1, 3, 0, 1, 2, 3, 1, 3], dtype=int64))
[[0 0 1 0 1]
[0 0 0 0 1]
[1 0 1 0 1]]
6. 数组广播机制
import numpy as np
a1 = np.random.randint(0,5,size=(3,5))
print("a1 =")
print(a1)
# 数组中所有元素同时发生相同的变化
print("="*30)
print("a1*2 = ")
print(a1*2)
# 每一个数据对应相加
print("="*30)
a2 = np.random.randint(0,5,size=(3,5))
print("a2 =")
print(a2)
print("a1 + a2 = ")
print(a1+a2)
# 行数相同,列数不同,只能与只有一列的数组做相加操作
print("="*30)
a3 = np.random.randint(0,5,size=(3,4))
# print(a3 + a1) # 报错
a4 = np.random.randint(0,5,size=(3,1))
print("a4 = ")
print(a4)
# a1的每一列都与a4的这唯一一列数据对应相加
print("a1 + a4 = ")
print(a1 + a4)
# 行数不同,列数相同,只能与只有一行的数组进行相加操作
print("="*30)
a5 = np.random.randint(0,5,size=(1,5))
print("a5 = ")
print(a5)
# a1的每一行都与a5的这唯一一行数据对应相加
print("a1 + a5 = ")
print(a1 + a5)
# 三维数组和二维数组进行相加
print("="*30)
a6 = np.random.randint(0,5,size=(3,8,2)) # 3大块,每块有一个8行2列的二维数组
a7 = np.random.randint(0,5,size=(8,2)) # 只有一个8行2列的二维数组,相当于三维数组只有一大块
print("a6 = ")
print(a6)
print("a7 = ")
print(a7)
print("a6 + a7 = ")
print(a6+a7)
输出:
a1 =
[[3 0 4 2 2]
[1 0 3 1 2]
[2 2 1 3 3]]
==============================
a1*2 =
[[6 0 8 4 4]
[2 0 6 2 4]
[4 4 2 6 6]]
==============================
a2 =
[[1 4 1 2 3]
[0 3 0 0 4]
[0 3 0 2 0]]
a1 + a2 =
[[4 4 5 4 5]
[1 3 3 1 6]
[2 5 1 5 3]]
==============================
a4 =
[[3]
[3]
[1]]
a1 + a4 =
[[6 3 7 5 5]
[4 3 6 4 5]
[3 3 2 4 4]]
==============================
a5 =
[[1 0 1 0 1]]
a1 + a5 =
[[4 0 5 2 3]
[2 0 4 1 3]
[3 2 2 3 4]]
==============================
a6 =
[[[2 0]
[3 3]
[0 2]
[1 0]
[2 3]
[2 2]
[3 4]
[3 0]]
[[2 3]
[0 2]
[0 3]
[2 2]
[3 2]
[0 2]
[3 2]
[2 3]]
[[1 1]
[4 2]
[2 1]
[3 1]
[2 0]
[1 1]
[2 1]
[3 1]]]
a7 =
[[1 3]
[4 4]
[4 0]
[4 0]
[0 0]
[0 0]
[0 3]
[2 4]]
a6 + a7 =
[[[3 3]
[7 7]
[4 2]
[5 0]
[2 3]
[2 2]
[3 7]
[5 4]]
[[3 6]
[4 6]
[4 3]
[6 2]
[3 2]
[0 2]
[3 5]
[4 7]]
[[2 4]
[8 6]
[6 1]
[7 1]
[2 0]
[1 1]
[2 4]
[5 5]]]
7. 数组形状操作
import numpy as np
a1 = np.random.randint(0,10,size=(3,4))
print("修改前 a1 = ")
print(a1)
# reshape和resize
# reshape 不改变原数组
print("a1.reshape((2,6)) = ")
print(a1.reshape((2,6)))
print("reshape修改后 a1 = ")
print(a1)
# resize 会直接修改数组本身
print("a1.resize((4,3)) = ")
print(a1.resize((4,3)))
print("resize修改后 a1 = ")
print(a1)
# flatten和ravel均不会改变原数组
print("="*30)
a2 = np.random.randint(0,10,size=(3,4))
print("a2 = ")
print(a2)
print("a2.flatten() = ")
a3 = a2.flatten()
print(a3)
print("flatten修改后 a2 = ")
print(a2)
print("a2.ravel() = ")
a4 = a2.ravel()
print(a4)
print("ravel修改后 a2 = ")
print(a2)
# 但是flatten返回的是拷贝,后续修改不会改变原数组,
# ravel返回的是引用,后续修改会改变原数组
a3[0] = 100
print("flatten后续修改后 a2 = ")
print(a2)
a4[1] = 500
print("ravel后续修改后 a2 = ")
print(a2)
输出:
修改前 a1 =
[[4 8 2 5]
[0 2 4 2]
[6 5 3 6]]
a1.reshape((2,6)) =
[[4 8 2 5 0 2]
[4 2 6 5 3 6]]
reshape修改后 a1 =
[[4 8 2 5]
[0 2 4 2]
[6 5 3 6]]
a1.resize((4,3)) =
None
resize修改后 a1 =
[[4 8 2]
[5 0 2]
[4 2 6]
[5 3 6]]
==============================
a2 =
[[1 3 8 0]
[0 2 9 9]
[3 5 5 1]]
a2.flatten() =
[1 3 8 0 0 2 9 9 3 5 5 1]
flatten修改后 a2 =
[[1 3 8 0]
[0 2 9 9]
[3 5 5 1]]
a2.ravel() =
[1 3 8 0 0 2 9 9 3 5 5 1]
ravel修改后 a2 =
[[1 3 8 0]
[0 2 9 9]
[3 5 5 1]]
flatten后续修改后 a2 =
[[1 3 8 0]
[0 2 9 9]
[3 5 5 1]]
ravel后续修改后 a2 =
[[ 1 500 8 0]
[ 0 2 9 9]
[ 3 5 5 1]]
8. 数组的叠加
import numpy as np
vstack1 = np.random.randint(0,10,size=(3,4))
print("修改前 vstack1 = ")
print(vstack1)
vstack2 = np.random.randint(0,10,size=(2,4))
print("修改前 vstack2 = ")
print(vstack2)
# vstack :将数组按垂直方向进行叠加,数组的列数必须相同才能叠加。
# 数组变长了
vstack3 = np.vstack([vstack1,vstack2])
print("vstack3 = ")
print(vstack3)
# 或者用concatenate([],axis),axis=0代表的是往垂直(行)方向叠加
vstack4 = np.concatenate([vstack1,vstack2],axis=0)
print("vstack4 = ")
print(vstack4)
print("="*30)
h1 = np.random.randint(0,10,size=(3,4))
print("修改前 h1 = ")
print(h1)
h2 = np.random.randint(0,10,size=(3,1))
print("修改前 h2 = ")
print(h2)
# hstack :将数组按水平方向进行叠加。数组的行必须相同才能叠加。
# 数组变宽了
h3 = np.hstack([h1,h2])
print("h3 = ")
print(h3)
# 或者用concatenate([],axis),axis=1代表的是往水平(列)方向叠加
h4 = np.concatenate([h1,h2],axis=1)
print("h4 = ")
print(h4)
# 或者用concatenate([],axis),axis=None ,那么会将两个数组组合成一个一维数组。
h5 = np.concatenate([h1,h2],axis=None)
print("h5 = ")
print(h5)
输出:
修改前 vstack1 =
[[4 0 9 1]
[1 2 9 6]
[5 3 6 1]]
修改前 vstack2 =
[[4 4 7 3]
[8 2 9 9]]
vstack3 =
[[4 0 9 1]
[1 2 9 6]
[5 3 6 1]
[4 4 7 3]
[8 2 9 9]]
vstack4 =
[[4 0 9 1]
[1 2 9 6]
[5 3 6 1]
[4 4 7 3]
[8 2 9 9]]
==============================
修改前 h1 =
[[4 5 5 8]
[0 0 6 7]
[6 2 2 8]]
修改前 h2 =
[[8]
[9]
[0]]
h3 =
[[4 5 5 8 8]
[0 0 6 7 9]
[6 2 2 8 0]]
h4 =
[[4 5 5 8 8]
[0 0 6 7 9]
[6 2 2 8 0]]
h5 =
[4 5 5 8 0 0 6 7 6 2 2 8 8 9 0]
9. 数组切割
import numpy as np
# hsplit :按照水平方向进行切割。用于指定分割成几列
hs1 = np.random.randint(0,10,size=(3,4))
print("hs1 = ")
print(hs1)
hs2 = np.hsplit(hs1,2) # 平均分成2列
print("沿水平方向平均切割成2块后 hs2 = ")
print(hs2)
hs3 = np.hsplit(hs1,(1,2)) # 在第0列、1列后面切割成3列,后面给一个元组
print("沿水平方向切割成3块后 hs3 = ")
print(hs3)
print("="*30)
# vsplit :按照垂直方向进行切割。用于指定分割成几行
vs1 = np.random.randint(0,10,size=(4,5))
print("vs1 = ")
print(vs1)
vs2 = np.vsplit(vs1,4) # n平均分成4行
print("平均分成4行后 vs2 = ")
print(vs2)
vs3 = np.vsplit(vs1,(1,3)) # 从下标为第0行、第2行后面进行切割成3大行
print("分成3大块后 vs3 = ")
print(vs3)
#split/array_split(array,indicate_or_seciont,axis) :
#用于指定切割方式,在切割的时候需
#要指定是按照行还是按照列, axis=1 代表按照列, axis=0 代表按照行。
vs4 = np.split(vs1,4,axis=0) # 平均切成4行
print("平均分成4行后 vs4 = ")
print(vs4)
输出:
hs1 =
[[1 9 1 9]
[8 5 0 0]
[4 3 5 0]]
沿水平方向平均切割成2块后 hs2 =
[array([[1, 9],
[8, 5],
[4, 3]]), array([[1, 9],
[0, 0],
[5, 0]])]
沿水平方向切割成3块后 hs3 =
[array([[1],
[8],
[4]]), array([[9],
[5],
[3]]), array([[1, 9],
[0, 0],
[5, 0]])]
==============================
vs1 =
[[6 0 2 5 0]
[3 5 1 7 6]
[7 2 2 6 6]
[5 7 2 3 3]]
平均分成4行后 vs2 =
[array([[6, 0, 2, 5, 0]]), array([[3, 5, 1, 7, 6]]), array([[7, 2, 2, 6, 6]]), array([[5, 7, 2, 3, 3]])]
分成3大块后 vs3 =
[array([[6, 0, 2, 5, 0]]), array([[3, 5, 1, 7, 6],
[7, 2, 2, 6, 6]]), array([[5, 7, 2, 3, 3]])]
平均分成4行后 vs4 =
[array([[6, 0, 2, 5, 0]]), array([[3, 5, 1, 7, 6]]), array([[7, 2, 2, 6, 6]]), array([[5, 7, 2, 3, 3]])]
10. 数组转置
import numpy as np
t1 = np.random.randint(0,10,size=(2,4))
print("t1 = ")
print(t1)
# ndarray 有一个 T 属性,可以返回这个数组的转置的结果。
t2 = t1.T
print("t1转置后 t2 = ")
print(t2)
# 如做矩阵的内积的时候。
# 就必须将矩阵进行转置后再乘以之前的矩阵:
t3 = t1.dot(t1.T)
print("矩阵内积 t1.dot(t1.T) = ")
print(t3)
#还有一个转置方法叫做 transpose ,这个方法返回的是一个View,
#也即修改返回值,会影响到原来数组。
t4 = t1.transpose()
t4[0] = 100
print("transpose并且修改后的 t1 = ")
print(t1)
输出:
t1 =
[[1 6 5 5]
[4 1 6 3]]
t1转置后 t2 =
[[1 4]
[6 1]
[5 6]
[5 3]]
矩阵内积 t1.dot(t1.T) =
[[87 55]
[55 62]]
transpose并且修改后的 t1 =
[[100 6 5 5]
[100 1 6 3]]