python入门

基础语法

自变量

代码中被写下来的固定的值,Python中常用的有6种值(数据)的类型:没有double

类型描述说明
数字num整数(int)整数(int),如:10、-10
浮点数(float)浮点数(float),如:13.14、-13.14
复数(complex)复数(complex),如:4+3j,以j结尾表示复数
布尔(bool)布尔(bool)表达现实生活中的逻辑,即真和假,True表示真False表示假。True本质上是一个数字记作1,False记作0
字符串string描述文本的一种数据类型

字符串(string)又称文本,是由任意数量的字符如中文、英文、各类符号、数字等组成。所以叫做字符的串。

列表list

有序的可变序列Python中使用最频繁的数据类型,可有序记录一堆数据
元组tuple有序的不可变序列可有序记录一堆不可变的Python数据集合
集合set无序不重复集合可无序记录一堆不重复的Python数据集合
字典dict无序Key-Value集合可无序记录一堆Key-Value型的Python数据集合

注释

在程序代码中对程序代码进行解释说明的文字。

作用:注释不是程序,不能被执行,只是对程序代码进行解释说明,让别人可以看懂程序代码。

单行注释:以 #开头,#右边 的所有文字当作说明,起辅助说明作用。#号和注释内容一般建议以一个空格隔开.
多行注释: 以 一对三个双引号 引起来 ("""...""")来解释说明一段代码的作用使用方法
三引号即能用做 多行注释 又能用做 字符串定义

变量

在程序运行时,能储存计算结果或能表示值的抽象概念 (记录数据)

变量名 = 变量值

数据类型查看

变量无类型而数据有类型

  • 可使用 type(变量) 查看数据的类型
# 1.使用print直接输出类型信息
print(type(1.1)) # 输出 <class 'float'>

# 2.使用变量存储type()语句的结果(调用type()有返回值)
int_type = type(1) 
print(int_type) # 输出 <class 'int'>

# 3.查看变量中存储的数据类型
name = "a"
print(type(name)) # 输出 <class 'str'>

数据类型转换

在特定的场景下,数据类型之间是可以相互转换的

(1) 转为整数

  • 使用 int(x) ,将x转换为一个整数  (float转换成int精度会丢失)

(2) 转为浮点数

  • 使用 float(x) ,将x转换为一个浮点数 (int转换成float会自动补位)

(3) 转为字符串

  • 使用 str(x) ,将x转换为一个字符串

(4)小结

  • 同type()语句一样,这三个语句,都是带有结果的(返回值),可以用print直接输出或用变量存储结果值输出。

  • 任何类型,都可以通过str(),转换成字符串。

  • 字符串内必须真的是数字,才可以将字符串转换为数字,否则会报错。

标识符

用户在编程的时候所使用的一系列用于给变量、类、方法等命名的名字

(1) 命名规则

1. 内容限制:标识符命名中,只允许出现这四类元素,其余任何内容都不被允许。

  • 英文

  • 中文 (不推荐使用)

  • 数字 (不可以作为开头)

  • 下划线(_)

2. 大小写敏感:字母的大写和小写,是完全能够被区分的。

3. 不可使用关键字:不可以使用特定用途的关键字作为标识符。

b58fcb8a5762434d9226f58b5e621b34.png

class  with  for  nonlocal  yield

(2) 命名规范

1. 变量的命名规范

  • 见名知意(尽量做到,看到名字,就知道是什么意思)

  • 下划线命名法(多个单词组合变量名,要使用下划线做分隔)

  • 英文字母全小写(使用驼峰)

  • 不遵守规则:会出现问题

  • 不遵守规范:不太高级

运算符

(1) 算数(数学)运算符

cf1e7dc39d2943b49a5208d3e92f0679.png

 (2) 赋值运算符

98c25e2b75f0476e9897c157990a546b.png

(3) 复合运算符

2cc2b013fe2b4834b9383634fdbd13c0.png

字符串扩展

1、定义方式
单引号定义法:name = 'a'
双引号定义法:name = "a" 
三引号定义法:name = """a"""

2、字符串引号嵌套
如果想要定义的字符串本身是包含单引号、双引号可通过:
--单引号定义法,可以内含双引号
--双引号定义法,可以内含单引号
--可以使用转义字符(\)来将引号解除效用,变成普通字符串
print('st\'u\'dy') # 输出 'study'

3、字符串的拼接
可以将两个字符串通过+号将其拼接成一个字符串 或者 将字面量和变量或变量和变量之间进行使用拼接
    缺点:
字符串无法和非字符串变量进行拼接因为类型不一致,无法接上
变量过多,拼接起来麻烦
字符串无法和数字或其它类型完成拼接

4、字符串格式化:完成字符串和变量的快速拼接
% 右边变量的值替换 %s ("%占位符" % 变量)
hobby = "eat"
name = "a"
message = "爱好 %s ,姓名 %s" % (hobby, name)
print(message)  # 输出 爱好eat ,姓名 a

5、格式化的精度控制
用辅助符号"m.n"来控制数据的宽度和精度
m,控制宽度,要求是数字(很少使用),设置的宽度小于数字自身,不生效
.n,控制小数点精度,要求是数字,会进行小数的四舍五入
age = 1  # %5d 表示将整数的宽度控制在5位,用三个空格补足宽度
money = 1.00  # %.2f 将小数点精度设置为2位
message = "a%5d, money:%.2f" % (age, money)
print(message)  # 输出 a   1, money:1.00

6、通过:f"内容{变量}"的格式来快速格式化
message = f"a:{age}, money:{money}"
适用于快速格式化字符串,缺点:
无法做做精度控制
不理会数据类型

7、对表达式进行格式化,表达式:一条具有明确执行结果的代码语句
1 + 1、5 * 2,就是表达式,因为有具体的结果,结果是一个数字
在无需使用变量进行数据存储的时候,可以直接格式化表达式简化代码
print(f"money:{1+1}")  # 输出 money:2

23984963a05d4852b9401b33be8103fd.png

数据输入

使用input()语句可以从键盘获取输入

  • 数据输出:print :可以完成将内容(字面量、变量等)输出到屏幕上。

  • 数据输入:input :可以用来获取键盘输入

# 输入的数值都将转为字符串类型,可通过数据类型转换获取需要的数据类型
name = input('Enter:') #控制台显示:Enter:     输入 5
print(type(name)) # 输出 <class 'str'>
print(type(int(name))) # 输出 <class 'int'>

判断类型

布尔类型

用来表达现实生活中的逻辑,即真与假

(1) 定义

# 定义布尔类型的字面量:
True  表示真(是、肯定)
False 表示假 (否、否定)
# True本质上是一个数字记作1,False记作0

(2) 获取

# 变量名称 = 布尔类型字面量
name = True
name = False

可以通过使用比较运算符进行比较运算得到布尔类型的结果

8244692904b14aba85588f27acf5a98e.png

比较运算符优先级高于赋值运算符

bool_a = 9 <= 8
print(f"a:{bool_a}") # 输出 a:False

逻辑运算符

0ba790ad5c5f4819b34a536cbdd2f0dd.png

以下变量都会被当成False:任何数值类型的0、""或’'空字符串、空元组()、空列表[]、空字典{}等。
and和or运算符会将其中一个表达式的值作为最终结果,而不是将 True 或者 False 作为最终结果
当遇到一个语句当中有多个逻辑运算符时,按照优先级not>and>or顺序来运算

(1) and运算符
        两边都是表达式:and两边的表达式都为真时,才为真,否则为假。

print(15 > 10 and 15 > 6)  # 打印 True
print(15 > 10 and 15 < 6)  # 打印 False

        不全是表达式:左假取左;左真取右

print({} and 15)  # 打印 {}
print(6 and 15)  # 打印 15

(2) or运算符
        两边都是表达式:or两边的表达式只要有一个真即为真,否则为假

print(15 > 10 or 15 < 6)  # 打印 True
print(15 < 10 or 15 < 6)  # 打印 False

        不全是表达式:左假取右;左真取左

print({} or 15)  # 打印 15
print(6 or 15)  # 打印 6

(3) not运算符
当表达式为真时,运算结果就为假;当表达式为假时,运算结果为真。not可以理解为取反
 

print(not 16 > 9)  # 打印 False
print(not 16 < 9)  # 打印 True

if判断语句

条件为True 执行,条件为False跳过

if 要判断的条件:
    条件为True时执行该处语句

if 要判断的条件:
    条件为True时执行该处语句
else:
    条件为False时执行该处语句

if 判断的条件:
    条件为True时执行
elif 判断的条件:
    条件为True时执行
else:
    上述条件都为False时执行
# 判断是互斥且有序

判断语句的嵌套:当满足前置条件时进行二次判断

if 判断的条件:
    条件为True时执行
    if 判断的条件:
        条件为True时执行
    else:
        条件为False时执行
else:
    条件为False时执行
    if 判断的条件:
        条件为True时执行
    else:
        条件为False时执行

# 嵌套的关键点在于:空格缩进
# 通过空格缩进,来决定语句之间的:层次关系

 循环类型

while 循环

条件满足无限执行

定义格式

while 条件:
	条件为True时重复执行

6e0ee7c32cb94777a8962b27fcd0a088.png

for循环

对一批内容进行逐个处理

定义格式

for 临时变量 in 待处理数据集(可迭代对象): 
        循环满足条件时执行的代码

a2c66ce65f4443d0b6134d338861d631.png

  • 待处理数据集,也称之为:可迭代类型

  • 可迭代类型指,其内容可以一个个依次取出的一种类型,包括:

    • 字符串

    • 列表

    • 元组等

  • for循环语句,本质上是遍历:可迭代对象。

for区别while

  • for循环是无法定义循环条件的。只能从被处理的数据集中,依次取出内容进行处理.
  • 理论上讲,for循环无法构建无限循环(被处理的数据集不可能无限大)

range语句

用于获得一个简单的数字序列(可迭代类型的一种)

  • 语法一: range(num)  # 获取一个从0开始,到num结束的数字序列(不含num本身)
  • 语法二: range(num1,num2) # 获得一个从num1开始,到num2结束的数字序列(不含num2本身)
  • 语法三: range(num1, num2, step) # 获得一个从num1开始,步长为step的,到num2结束的数字序列(不含num2本身)

循环中断

(1) continue关键字

临时跳过: 暂时跳过本次循环,直接进行下一次

  • 中断本次循环,直接进入下一次循环

  • 可用于for循环和while循环,效果一致

  • 在嵌套循环中只对所在层循环生效

(2) break关键字

直接结束: 提前退出循环,不再继续

  • 直接结束所在循环

  • 可以用for循环和while循环,效果一致

  • 在嵌套循环中只对所在层循环生效

函数

函数基础

组织好的,可重复使用的,用来实现特定功能的代码段

(1) 完整格式

# 定义
def 函数名(传入参数):
    函数体
    return 返回值
# 使用
函数名(传入参数)

传入参数的数量是不受限制的:

可以不使用参数,省略;也可以使用任意N个参数;返回值如不需要,可以省略

(2) 简单格式

# 定义
def 函数名():
    函数体
# 使用
函数名()

函数必须先定义后使用

(3) 带参格式
在函数进行计算的时候,可接受外部(调用时)提供的数据

# 定义
def 函数名(传入参数):
    函数体
# 使用
函数名(传入参数)

传入的时候,按照顺序传入数据,参数之间使用逗号进行分隔

# 定义
def add(x, y): # x和y称为形式参数(形参)
    res = x + y
    print(res)
# 使用
add(10, 6) # 10和6称为实际参数(实参)
# 输出 16

(4) 带返回值格式
所谓“返回值”,就是程序中函数完成事情后,最后给调用者的结果

# 定义
def 函数名(传入参数):
    函数体
    return 返回值
# 或
def 函数名():
    函数体
    return 返回值
# 使用
变量 = 函数名(传入参数)
变量 = 函数名()

(5) None类型
如果函数没有使用return语句返回数据,则函数返回值为None,其类型是:<class ‘NoneType’>

None表示:空的、无实际意义的意思

(6) 其他应用:

        用在if判断上

                在if判断中,None等同于False

                一般用于在函数中主动返回None,配合if判断做相关处理

        用于声明无内容的变量上

# 暂不赋予变量具体值
name = None

(7) 函数的嵌套调用
一个函数里面又调用了另外一个函数,在一个函数中先把当前函数中的任务都执行完毕之后才会回到上次调用位置继续执行

def fun_1():
    fun_2()

变量的作用域

定义:变量的作用范围(变量在哪里可用,在哪里不可用)

(1) 局部变量:定义在函数体内部的变量,即只在函数体内部生效,函数外部访问则立即报错,在函数体内部,临时保存数据,即当函数调用完成后,则销毁局部变量。

(2) 全局变量:在函数体内、外都能生效的变量

(3) global关键字:一般情况下,在函数内无法修改全局变量的值,使用 global关键字可以在函数内部声明变量为全局变量, 如下所示

num = 100
def test():
    # 声明num为全局变量
    global num
    num = 200
    print(num)
test() # 输出 200
print(num) # 输出 200

函数进阶

(1) 多返回值:按照返回值的顺序,写对应顺序的多个变量接收即可,变量之间用逗号隔开

def test():
    return 'a', '1', 16
x, y, z= test()
print(f"第一个值为{x},第二个值为{y},第三个值为{z}")
# 输出 第一个值为a,第二个值为1,第三个值为16

(2) 多种传参方式
(2.1) 位置参数:调用函数时根据函数定义的参数位置来传递参数,传递的参数和定义的参数的顺序及个数必须一致

def user_info(name, age):
    print(f"您的名字是{name},年龄是{age}")
user_info('M', 2)
# 输出 您的名字是M,年龄是2

(2.2) 关键字参数:函数调用时通过“键=值”形式传递参数,可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求.

def user_info(name, age):
    print(f"您的名字是{name},年龄是{age}")
user_info(name = 'M', age = 2)
# 输出 您的名字是M,年龄是2

函数调用时,如果有位置参数时,位置参数必须在关键字参数的前面,但关键字参数之间不存在先后顺序

def user_info(name, age):# 位置参数必须在关键字参数前面
    print(f"您的名字是{name},年龄是{age}")
user_info('M', age=2)
# 输出 您的名字是M,年龄是2

(2.3) 缺省参数:也叫默认参数,用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值

所有位置参数必须出现在默认参数前,包括函数定义和调用
当调用函数时没有传递参数, 就会使用默认是用缺省参数对应的值
函数调用时,如果为缺省参数传值则修改默认参数值, 否则使用这个默认值

def user_info(name, age, gender='男'):
    print(f"您的名字是{name},年龄是{age},性别是{gender}")
user_info('M', 2)
# 输出 您的名字是TOM,年龄是2,性别是男
user_info('M', 2, '女')
# 输出 您的名字是M,年龄是2,性别是女

(2.4) 不定长参数
也叫可变参数. 用于不确定调用的时候会传递多少个参数(不传参也可以)的场景

(2.4.1) 位置传递
以*号标记一个形式参数,以元组的形式接受参数,传进的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元组(tuple),args是元组类型

def user_info(*args):
    print(args)
user_info('M')
# 输出 ('M',)
user_info('M', 2)
# 输出 ('M', 2)

(2.4.2) 关键字传递
关键字不定长传递以**号标记一个形式参数,以字典的形式接受参数,参数是“键=值”形式的形式的情况下, 所有的“键=值”都会被kwargs接受, 同时会根据“键=值”组成字典.

def user_info(**kwargs):
    print(kwargs)
user_info(name='M', age=2)
# 输出 {'name': 'TM', 'age': 2}

(3) 函数作为参数传递

函数本身也可以像普通变量一样作为参数传递使用,函数名存放的是函数所在空间的地址;

函数名可以像普通变量一样赋值,func1 = func2;

函数本身也可以像普通变量一样作为参数传递使用

def func():
    print("hello world~")
print(func) # 打印 <function func at 0x0000022E77983EB0>

func1 = func
func1() # 打印 hello world~

def func2():
    func()
func2() # 打印 hello world~


(4) lambda匿名函数

无名称的函数,lambda关键字,可以定义匿名函数(无名称),无名称的匿名函数,只可临时使用一次。

def关键字,可以定义带有名称的函数,有名称的函数,可以基于名称重复使用。

定义格式:

lambda 传入参数:函数体(一行代码)
# lambda 是关键字,表示定义匿名函数
# 传入参数表示匿名函数的形式参数,如:x, y 表示接收2个形式参数
# 函数体,就是函数的执行逻辑,要注意:只能写一行,无法写多行代码

def compute(add):
    result = add(6, 3)
    print(result)
# 输出 9 
compute(lambda x, y: x + y)

文件操作

文件编码

编码就是一种规则集合,记录了内容和二进制间进行相互转换的逻辑。

  • 思考:计算机只能识别0和1,那么丰富的文本文件是如何被计算机识别,并存储在硬盘中呢?

  • 答案:使用编码技术(密码本)将内容翻译成0和1存入。

  • 计算机中有许多可用编码:UTF-8,GBK,Big5等不同的编码,将内容翻译成二进制也是不同的

  • 对内容的编码与解码必须使用同一套编码,否则会导致错误的结果

  • UTF-8是目前全球通用的编码格式,除非有特殊需求,否则,一律以UTF-8格式进行文件编码即可。

文件操作

文件操作主要包括打开、关闭、读、写等操作

操作过程中注意文件路径的书写

  • 只有操作文件与python文件在同一目录才能直接写文件名。否则写绝对路径。

(1) 文件的打开

(1.1) 基本格式

  • 在Python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件

open(name, mode, encoding)
# name:是要打开的目标文件名的字符串(可以包含文件所在的具体路径)。
# mode:设置打开文件的模式(访问模式):只读、写入、追加等。
# encoding:编码格式(推荐使用UTF-8)
f = open("C:/code/bill.txt", "r", encoding="UTF-8")

(1.2) 打开模式

  • 文件常用的三种基础访问模式,可通过mode指定。

  • r->read(读取),w->write(写入),a->append(追加)

fb02b95f088546229111e67c5411d643.png

(2) 文件的读取

  • 每次读取会从上一次读取结束的位置开始
  • 每次open()中的内容只能被读取一次

19ecf7d83f74478e84c16fd966d06a53.png

(2.1) read方法
num表示要从文件中读取的数据的长度(单位是字节),如果没有传入num,那么就表示读取文件中所有的数据。

语法:文件对象.read(num)

f = open("C:/code/test.txt", "r", encoding="UTF-8")
content = f.read() # 不传入num,读取文件中所有的数据。
content = f.read(2) # 传入num,读取2字节长度数据。
print(content)

(2.2) readline()方法
一次读取一行内容

语法:文件对象.readline()

f = open("C:/code/test.txt", "r", encoding="UTF-8")
content = f.readline()
print(f"第一行内容:{content}")  # 打印:第一行内容:
content = f.readline()
print(f"第二行内容:{content}")  # 打印 第二行内容:

(2.3) readlines方法
按照行的方式把整个文件中的内容进行一次性读取,并且返回的是一个列表,其中每一行的数据为一个元素。

语法:文件对象.readlines()

f = open("C:/code/test.txt", "r", encoding="UTF-8")
content = f.readlines()
print(content)  # 换行符也会被打印 
print(type(content))  # 打印 <class 'list'>

(2.4) for循环读取
for循环读取每一行数据

# 每一个line临时变量,就记录了文件的一行数据
for line in open("C:/code/test.txt", "r", encoding="UTF-8"):
    print(line)

(2.5) close关闭文件对象
如果不调用close,同时程序没有停止运行,那么这个文件将一直被Python程序占用,无法操作

f = open("C:/code/test.txt", "r", encoding="UTF-8")
# 需要执行代码
f.close()

代码中不关闭文件对象,且python程序未停止运行,无法对文件删除重命名等操作:

(2.6) 自动close
通过在with open的语句块中对文件进行操作,可以在操作完成后自动关闭close文件,即使出现异常也会自动调用关闭文件操作
语法:with open() as f

with open("C:/code/test.txt", "r", encoding="UTF-8") as f:
    f.readlines()

(3) 文件的写入

f = open("C:/code/test.txt", "w")
# 文件如果不存在,使用”w”模式,会创建新文件
# 文件如果存在,使用”w”模式,会将原有内容清空
# 2.文件写入
f.write('hello world')
# 3. 内容刷新
f.flush()

直接调用write,内容并未真正写入文件,而是会积攒在程序的内存中,称之为缓冲区,当调用flush的时候,内容会真正写入文件
close()方法,附带flush()方法的功能,避免频繁的操作硬盘,导致效率下降(攒一堆,一次性写盘)
(4) 文件的追加
使用w模式,每次写入会将原有内容清空,写入新内容

使用a模式,文件不存在会创建文件,文件存在会在最后追加内容写入文件

f = open("C:/code/test.txt", "a")
# 2.文件写入
f.write('study')
# 3. 内容刷新
f.flush()

异常

程序运行的过程中出现了错误

        在程序运行中,检测到一个错误,程序中止运行并且出现了一些错误的提示,也称作BUG

为什么要捕获异常
        避免程序中止,提前准备处理可能出现的异常

        在真实工作中, 不能因为一个小的BUG就让整个程序全部奔溃,而是对BUG进行提醒, 整个程序继续运行

捕获异常

        在可能出现异常的地方,做好提前准备,当真的出现异常的时候,可以有后续手段。

(1) 捕获常规异常

try:
    可能发生错误的代码
except:
    如果出现异常执行的代码
# 未发生错误try全部代码都会执行
# 未发生错误不会执行except中的代码
# 发生错误try中只会执行到报错行为止的代码
# 发生错误会执行except中的代码

(2) 捕获特定异常

        如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常

try:
    可能发生错误的代码
except 待捕获异常名 as 别名:
    如果出现异常执行的代码

(3) 捕获多个异常

  • 格式一:当待捕获异常名为Exception可以捕获所有类型异常,作用与(1)一致

try:
    code1
except Exception as e:
    code2
  • 格式二:把要捕获的异常类型的名字,放到except 后,并使用元组的方式进行书写

try:
    可能发生错误的代码
except (异常名1,异常名2) as 别名:
    如果出现异常执行的代码

(4) 其他用法

(4.1) 打印异常信息

  • 异常描述信息存贮在别名中,可以通过打印别名获取

try:
    print(num) # 未定义,报错
except (NameError, ZeroDivisionError) as e:
    print(e) # 打印 name 'num' is not defined

(4.2) 异常else
else表示的是如果没有异常要执行的代码。

-- 出现异常,打印结果与(4.1)一致
try:
    print(num) # 未定义,报错
except (NameError, ZeroDivisionError) as e:
    print(e) # 打印 name 'num' is not defined
else:
    print("无异常") # 有异常,不执行

-- 无异常
try:
    print("正常") # 不报错
except (NameError, ZeroDivisionError) as e:
    print(e) # 不执行
else:
    print("无异常") # 执行

(4.3) 异常finally
finally表示的是无论是否异常都要执行的代码

global f
try:
    f = open("C:/code/aaa.txt", "r")
except Exception as e:
    print(e)  
finally:
    f.close() # 一定会执行close操作

异常的传递

异常是具有传递性的(向上一级抛出)

  • 当函数调用链中出现异常,如果所有函数都没有捕获异常的时候, 程序就会报错
  • 利用异常具有传递性的特点, 当想要保证程序不会因为异常崩溃的时候, 就可以在主函数中设置异常捕获, 由于无论在整个程序哪里发生异常, 最终都会传递到主函数中, 这样就可以确保所有的异常都会被统一捕获

af52e98c262c4066b9e13492edabb714.png

模块与包

模块

一个Python文件, 以.py 结尾, 能定义函数,类和变量,也能包含可执行的代码

作用:可以认为不同的模块就是不同工具包,每一个工具包中都有各种不同的工具(如函数)使用进而实现各种不同的功能.
模块的导入
模块在使用之前需要先导入正在开发的文件

[from 模块名] import [模块|类|变量|函数|*] [as 别名]
# *表示导入所有
  • from可以省略,直接import
  • as别名可以省略
  • 通过”.”来调用模块提供的功能
  • 模块的导入一般写在代码文件的开头位置

自定义模块

有时候需要一些个性化(满足自己特定需求)的模块, 就可以通过自定义模块实现,即自己制作一个模块

上述提到:每个Python文件都可以作为一个模块,模块的名字就是文件的名字.也就是说将自己编写的文件导入另一个文件即可当作模块使用。

  • 在实际开发中,当一个开发人员编写完一个模块后,为了让模块能够在项目中达到想要的效果,开发人员可能会在py文件中添加一些测试信息

  • 此时,无论是当前文件,还是其他已经导入了该模块的文件,在运行的时候都会自动执行测试信息

if条件判断中解决

  • 只有运行模块文件时才会执行测试代码,运行导入模块的文件时不再执行测试代码:
# 在模块文件名加入该行代码
# 只在当前文件中运行条件才为True,导入其他文件时均为False
if __name__ == '__main__':
    测试代码
# __main__ 运行时程序的名称
# __name__ 系统自动赋值,不用管
# 在Run时为 __main__ 
# 未Run时为 文件名称
  • 当导入多个模块的时候,如果模块内有同名功能,且未使用别名方式导入形式,后面导入的模块将会覆盖前面模块内同名的功能。

  • 如果一个模块文件中有__all__变量,当使用from xxx import *导入时,只能导入__all__这个列表中的元素

当Python的模块太多了,就可能造成一定的混乱,此时可以通过Python包的功能来管理。

  • 从物理上看,包就是一个文件夹,在该文件夹下包含了一个 __init__.py 文件,该文件夹可用于包含多个模块文件

  • 从逻辑上看,包的本质依然是模块

b6bda3d0727849a1a1338469e5ce626f.png

自定义包

  • 当我们的模块文件越来越多时,包可以帮助我们分类管理这些模块,包的作用就是包含多个模块,但本质依然是模块

16cd22a55db94334b896db36f332a539.png

创建包

  • 新建包后,包内部会自动创建__init__.py文件,这个文件控制着包的导入行为

3d779be50b664720bb0b4e14f6c621c0.png

导入包

  • 导入包与导入模块几种方式类似
import 包名.模块名
包名.模块名.功能名()

限制导入

  • 可以在__init__.py文件中添加__all__ = ['模块名',...],控制允许导入的模块列表

  • 与导入模块类似__all__只针对from 包名.模块名 import * 而对其他方式无效

三方安装包

pip install package
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名称
# 网站为清华大学提供的一个网站,可供pip程序下载第三方包

--配置成镜像源
python -m pip install --upgrade pip
# 升级pip版本,防止版本过低无法配置
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
# 配置为全局镜像源

类型注解

在代码中提供数据类型的注解(显式的说明),使用时能获得相关提示;帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示

显示声明时,pycharm确定这个对象是list类型,使用时能有对应提示

b493502599d54856a02c38553dbb827b.png

没有声明具体类型时,使用不会有任何相关提示

3d5288bd64bd49ec8e768da354d026bf.png

  • 帮助开发者自身对变量进行类型注释(备注),后面调用不易出错

变量的类型注解

提示变量的数据类型

变量名: 数据类型 = 数值

3604d3247d0d4fcf99d56cb15d665e66.png

(2) 基础类型
整数类型注解

var_1: int = 1

浮点数类型注解

var_2: float = 0.21

布尔类型注解

var_3: bool = True 

字符串类型注解

var_4: str = "hhybd" 

(3) 类对象

# 定义学生类
class Student:
    pass

stu: Student = Student()  # 学生类类型注解

(4) 数据容器
列表类型注解

my_list: list = [1, 2, 3]
my_list: list[int] = [1, 2, 3]

元组类型注解

my_tuple: tuple = (1, 2, 3)
my_tuple: tuple[str, int, bool] = ("bd", 521, True)

集合类型注解

my_set: set = {1, 2, 3}
my_set: set[int] = {1, 2, 3}

字典类型注解

my_dict: dict = {"hhbdy": 250}
my_dict: dict[str, int] = {"hhbdy": 250}

字符串类型注解

my_str: str = "hhybd"

(5) 注释中进行类型注解

# type:类型
stu = Student()  # type:Student
var_1 = 123  # type:int

(6) 函数(方法)的类型注解

标注形参和返回值数据类型

  • 类型注解仅仅起到提示作用
def 函数方法名(形参名1:类型,形参名2:类型):
	函数体

5d248583c32e459b8790f4dd3240e2e0.png

(7) 返回值注解

def 函数方法名(形参名1:类型,形参名2:类型) -> 返回值类型:
	函数体
def add(x: int, y: int) -> int:
    return x + y

(8) Union类型注解

联合类型注解,在变量注解、函数(方法)形参和返回值注解中均可使用

需要导包使用

当数据类型不唯一时基本格式无法满足要求,此时便可使用Union类型

Union[类型,类型]:

在变量中:

from typing import Union
# 数据为字符串或整数
my_list: list[Union[str, int]] = [2, "hhy", 5, "bd", 0]
# 键为字符串,值为字符串或整数
my_dict: dict[str, Union[str, int]] = {"name": "hhy", "QS": 250}

在函数中:

from typing import Union

# 接收字符串或整数,返回字符串或整数
def func(data: Union[int, str]) -> Union[int, str]:
    pass

连接mysql

pip install pymysql

# 1.导入操作包
from pymysql import Connection

# 2.获取到MySQL数据库的连接对象
conn = Connection(
    host='localhost',  # 主机名或IP地址
    port=3306,  # 端口号,默认3306
    user='root',  # MySQL账号
    password='pwd'  # MySQL密码
    # autocommit=True  # 设置自动提交(commit)
)

# 打印MySQL版本信息
print(conn.get_server_info())

"""
建表
"""
# 获取游标对象(用于操作数据库)
cursor = conn.cursor()
# 选择要操作的数据库
conn.select_db("db1")
# 使用游标对象,执行建表sql语句
cursor.execute("CREATE TABLE tb_user(id INT,name VARCHAR(8),age int)")

"""
查询
"""
# 获取游标对象(用于操作数据库)
cursor = conn.cursor()
# 选择要操作的数据库
conn.select_db("db1")
# 使用游标对象,执行sql语句
cursor.execute("SELECT * FROM tb_user")
# 获取查询结果,返回元组对象
results: tuple = cursor.fetchall()
for result in results:
    print(result)


"""
插入
"""
# 获取游标对象(用于操作数据库)
cursor = conn.cursor()
# 选择要操作的数据库
conn.select_db("db1")
# 使用游标对象,执行sql语句
cursor.execute("Insert into tb_user values(1,'h','250')")
# 确认插入行为
# 如果在获取连接对象时设置自动提交可以不用再写
conn.commit()


"""
修改
"""
# 获取游标对象(用于操作数据库)
cursor = conn.cursor()
# 选择要操作的数据库
conn.select_db("db1")
# 使用游标对象,执行sql语句
cursor.execute("UPDATE tb_user set username='hhy' where username = 'fsp'")
# 确认修改行为
# 如果在获取连接对象时设置自动提交可以不用再写
conn.commit()

"""
删除
"""
# 获取游标对象(用于操作数据库)
cursor = conn.cursor()
# 选择要操作的数据库
conn.select_db("db1")
# 使用游标对象,执行sql语句
cursor.execute("DELETE from tb_user WHERE username = 'hhy'")
# 确认删除行为
# 如果在获取连接对象时设置自动提交可以不用再写。
conn.commit()



# 3.关闭到数据库的连接
conn.close()

pymysql在执行数据插入或其它产生数据更改的SQL语句时,默认是需要提交更改的,即,需要通过代码“确认”这种更改行为。

如果不想手动commit确认,可以在构建连接对象的时候,设置自动commit的属性。

查询后,使用游标对象.fetchall()可得到全部的查询结果封装入嵌套元组内

可使用游标对象.execute()执行SQL语句

闭包

可以保存函数内变量,不会随着函数调用完而销毁

  • 在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。

# 1.在函数嵌套(函数中定义函数)的前提下
def func_out(num1):
    def func_inner(num2):
        # 2.内部函数使用了外部函数的变量
        num = num1 + num2
        print(f"num的值为:{num}")

    # 3.外部函数返回了内部函数
    return func_inner

# 创建闭包实例
f = func_out(10)
# 执行闭包
f(6) # 打印 num的值为:16

修改外部函数变量的值

  • 在闭包函数(内部函数中)想要修改外部函数的变量值,必须用nonlocal声明这个外部变量
# 1.在函数嵌套(函数中定义函数)的前提下
def func_out(num1):
    def func_inner(num2):
        # 声明外部变量
        nonlocal num1
        # 2.内部函数使用了外部函数的变量
        num1 += num2
        print(f"num1的值为:{num1}")

    # 3.外部函数返回了内部函数
    return func_inner

# 创建闭包实例
f = func_out(10)
# 执行闭包
f(8)  # 打印 num的值为:18
  • 优点:

    • 无需定义全局变量即可实现通过函数,持续的访问、修改某个值
    • 闭包使用的变量于所在的函数内,难以被错误的调用修改,可使变量更安全不易被恶意行为修改
  • 缺点:

    • 由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存(额外的内存占用)

装饰器

也是一种闭包,可在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能

  • 装饰器就是把一个函数当做参数传递给闭包中的外部函数,同时在内部函数中使用这个函数,并给他添加新的功能。
  • 外部函数只能有一个参数,往往是被装饰的函数
  • 内部函数可以根据被装饰的函数提供多个参数以及返回值
# 定义一个装饰器
def remind(func):
    # 为目标函数增加新功能
    def inner():
        print("我睡觉了")
        func()
        print("我起床了")

    return inner


# 需要被装饰的函数
def sleep():
    import random
    import time
    print("睡眠中...")
    time.sleep(random.randint(1, 5))
    
# 未装饰
sleep()
# 睡眠中...

# 使用装饰器装饰函数(增加睡前起床提醒)
# 返回增强后的inner函数
fn = remind(sleep)
fn()
# 我睡觉了
# 睡眠中...
# 我起床了

语法糖使用

  • 可直接在需要被装饰的函数上加@装饰器名字,解释器碰到时会自动执行装饰过程,简化使用流程
# 定义一个装饰器
def remind(func):
    def inner():
        print("我睡觉了")
        func()
        print("我起床了")

    return inner


# 需要被装饰的函数
# 解释器遇到@remind 会立即执行 sleep = remind(sleep)
@remind
def sleep():
    import random
    import time
    print("睡眠中...")
    time.sleep(random.randint(1, 5))

# 通过语法糖注解,直接调用即可达到效果
sleep()
# 我睡觉了
# 睡眠中...
# 我起床了

多个装饰器使用

  • 将装饰器都写在需要被装饰的函数上面即可
  • 谁离被装饰的函数最近,谁就先去装饰函数
# 定义装饰器1
def remind(func):
    def inner():
        print("我睡觉了")
        func()
        print("我起床了")

    return inner


# 定义装饰器2
def study(func):
    def inner():
        func()
        print("我要敲代码")

    return inner


# 谁近谁先装饰
@study   # 2.执行 sleep = study(remind(sleep))
@remind  # 1.执行 sleep = remind(sleep)
def sleep():
    import random
    import time
    print("睡眠中...")
    time.sleep(random.randint(1, 5))


sleep()
# 我睡觉了
# 睡眠中...
# 我起床了
# 我要敲代码

带参数的装饰器

  • 需要再增加一层函数嵌套来接收传递的参数
# 第一层:用于接收装饰器传递的参数
def logging(flag):
    # 第二层:外部函数用于接收待装饰函数
    def decorator(fn):
        # 第三层:内部函数用于装饰接收的函数
        def inner(num1, num2):
            # 使用参数
            if flag == "+":
                print(">正在进行加法运算<")
            elif flag == "-":
                print(">正在进行减法运算<")
            result = fn(num1, num2)
            return result
		
        return inner

    # 返回装饰器
    return decorator


# 被带有参数的装饰器装饰的函数
@logging('+')
def add(a, b):
    result = a + b
    return result


result = add(1, 3)
print(result)

1. 装饰器调用 @logging('+')

当 Python 看到 @logging('+') 装饰器时,它首先执行 logging('+'),并将参数 '+' 传递给函数 logging。这个函数返回了 decorator 函数。

此时,decorator 函数还没有执行,它只是被返回给 Python 解释器,等待下一步。

2. 装饰函数 add

@logging('+') 装饰器将 add 函数传递给了返回的 decorator 函数,等同于 add = decorator(add)

  • decorator(fn) 接收了 add 这个函数作为参数,并返回了 inner 函数。

  • 结果是,原始的 add 函数现在已经被替换为 inner 函数。

3. 调用被装饰的函数 add(1, 3)

当你调用 add(1, 3) 时,实际上执行的是 inner(1, 3) 函数,因为 add 函数已经被 inner 替代。

  • inner(num1, num2) 函数首先根据传递给装饰器的参数 flag(也就是 '+')执行条件判断,输出 "正在进行加法运算"

4. 执行原始函数 fn(num1, num2)

inner 函数接着调用了 fn(num1, num2),其中 fn 实际上就是最初传递进来的 add 函数。因此,相当于调用了 add(1, 3),并将返回值赋给 result

5. 返回最终结果

最后,inner 函数返回原始 add 函数的结果,最终在控制台输出结果为 4

类装饰器

  • 一个类里面一旦实现了__call__方法,那么这个类创建的对象就是一个可调用对象,可以像调用函数一样进行调用
# 定义类
class Login:
    def __call__(self, *args, **kwargs):
        print("登录中。。。")

# 创建实例
login = Login()
# 如函数般调用
login()  # 打印 登录中。。。
  • 类装饰器装饰函数的功能通过call方法实现
# 定义类装饰器
class Check:
    # 接收待装饰的函数
    def __init__(self, fn):   # fn = comment
        self.__fn = fn
	
    def __call__(self, *args: object, **kwargs: object) -> object:
        print("登录")
        self.__fn()   # comment()


# 被装饰的函数
@Check  # comment = Check(comment)
def comment():
    print("发表评论")


comment()

#登录
#发表评论

property属性

把类中的一个方法当作属性进行使用,简化开发

  • 如果想获取和修改私有属性必须通过类方法修改:

class Person:
    def __init__(self):
        self.__age = 1

    def age(self):
        return self.__age

    def set_age(self, new_age):
        self.__age = new_age


p = Person()
age = p.age()
print(f"修改前年龄是:{age}") # 打印 修改前年龄是:1
p.set_age(6)
age = p.age()
print(f"修改后年龄是:{age}")  # 打印 修改后年龄是:6

(1) 装饰器方式使用

  • @property表示把方法当作属性使用,表示当获取属性时执行下面修饰的方法
    • property修饰的方法名要与属性名一样
  • @方法名.setter表示把方法当作属性使用,表示当设置属性值时会执行下面修饰的方法
class Person:
    def __init__(self):
        self.__age = 1

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, new_age):
        self.__age = new_age


p = Person()
# 可直接通过对象.属性使用
print(f"修改前年龄是:{p.age}") # 打印 修改前年龄是:1
p.age = 6
print(f"修改后年龄是:{p.age}") # 打印 修改后年龄是:6

(2) 类属性方式使用

  • property的参数说明:
    • 属性名 = property(获取值方法,设置值方法)
    • 第一个参数:获取属性时要执行的方法
    • 第二个参数:设置属性时要执行的方法
class Person:
    def __init__(self):
        self.__age = 1

    def get_age(self):
        return self.__age

    def set_age(self, new_age):
        self.__age = new_age

    # 类属性方式的property属性
    age = property(get_age, set_age)


p = Person()
print(f"修改前年龄是:{p.age}") # 打印 修改前年龄是:1
p.age = 66
print(f"修改后年龄是:{p.age}") # 打印 修改后年龄是:6

深拷贝、浅拷贝

开辟新的内存空间接收变量

  • 调用id()可获得变量的内存地址

可变类型浅拷贝

  • 使用copy函数进行浅拷贝,只对可变类型的第一层对象进行拷贝
    • 对拷贝的对象开辟新的内存空间进行存储
    • 不会拷贝对象内部的子对象
import copy

a = [1, 2, 3]
b = [11, 22, 33]
c = [a, b]
# 普通赋值,指向同一空间
d = c
print(f"c内存地址:{id(c)}")  # 打印 c内存地址:2265505547072
print(f"d内存地址:{id(d)}")  # 打印 d内存地址:2265505547072


a = [1, 2, 3]
b = [11, 22, 33]
c = [a, b]
# 浅拷贝,指向不同空间
d = copy.copy(c)
print(f"c内存地址:{id(c)}")  # 打印 c内存地址:2265505547648
print(f"d内存地址:{id(d)}")  # 打印 d内存地址:2265505548608

# 不会拷贝对象内部的子对象
print(id(a)) # 打印 2135734964288
print(id(c[0])) # 打印 2135734964288
print(id(d[0])) # 打印 2135734964288

不可变类型浅拷贝

  • 不可变类型进行浅拷贝不会给拷贝的对象开辟新的内存空间,只是拷贝了这个对象的引用
a = (1, 2, 3)
b = (11, 22, 33)
c = (a, b)
# 浅拷贝效果与普通赋值一样
d = c
e = copy.copy(c)
print(f"c内存地址:{id(c)}") # c内存地址:1536064302016
print(f"d内存地址:{id(d)}") # d内存地址:1536064302016
print(f"e内存地址:{id(e)}") # e内存地址:1536064302016

保障数据的独立性

可变类型深拷贝

  • 使用deepcopy函数进行深拷贝,会对可变类型内每一层可变类型对象进行拷贝,开辟新的内存空间进行存储

import copy

a = [1, 2, 3]
b = [11, 22, 33]
c = [a, b]

d = copy.deepcopy(c)
print(f"c内存地址:{id(c)}") # 打印 c内存地址:2603978212160
print(f"d内存地址:{id(d)}") # 打印 d内存地址:2603978215488

# 内部的可变类型也会拷贝
print(id(a)) # 打印 2603978215104
print(id(c[0])) # 打印 2603978215104
print(id(d[0])) # 打印 2603978212992

不可变类型深拷贝

  • 不可变类型进行深拷贝不会给拷贝的对象开辟新的内存空间,只是拷贝了这个对象的引用
a = (1, 2, 3)
b = (11, 22, 33)
c = (a, b)

d = copy.deepcopy(c)
print(f"c内存地址:{id(c)}")  # 打印  c内存地址:1312354282432
print(f"e内存地址:{id(d)}")  # 打印  e内存地址:1312354282432

7eff029191a74f7e8ff221c6f82ccad9.png

eval函数

  • eval()函数可将字符串当成有效的表达式求值并返回计算结果
# 基本的数学运算
res = eval("(1+9)*5")
print(res) 
# 打印 50

# 字符串重复
res = eval("'*'*10")
print(res) 
# 打印 **********

# 字符串转换成列表
print(type(eval("[1,2,3,4]")))
# 打印 <class 'list'>

# 字符串转成字典 
print(type(eval("{'name':'guanzhi','age':20}")))
# 打印 <class 'dict'>

# 不要使用eval直接转换input的结果
input_str = input() # 输入 __import__('os').system('rm -rf /*')
eval(input_str) # 直接运行可能导致主机崩溃

# 等价于
import os
os.system("终端命令")

面向对象

(1)万物皆对象

  • 现实世界的事物都有属性和行为,可在程序中抽离为类来描述现实世界的事物属性和行为。

1ef27247b6f940b492294d2402c728b8.png

  • 使用充当程序内现实事物的“设计图纸”,基于图纸(类)生产实体(对象),由对象做具体的工作,称之为:面向对象编程

  • 在现实世界中,生产事物:先设计图纸,完成功能属性分析,再批量制造

cc7b06b3da6149769cd4e4dd26f46b83.png

在程序中,通过类作为事物的设计图纸,记录事物的属性和行为,基于类(设计图纸)构建(生产)闹钟对象

(2)类与对象

使用类封装属性,基于类创建出一个个的对象来使用

# 创建类
class 类名称:
    类的属性(成员变量)
    
    类的行为(成员方法)
    
# 基于类创建对象
对象名 = 类名称()

# 调用
对象名.成员变量
对象名.成员方法()

"""
class:关键字,表示要定义类
类的属性:定义在类中的变量(成员变量) -> 事物的属性
类的行为:定义在类中的函数(成员方法) -> 事物的行为
"""

# 设计表格即设计类(class):
class Student:
    name = None  # 姓名
    sex = None  # 性别
    country = None  # 国籍
    native_place = None  # 籍贯
    age = None  # 年龄

# 打印表格即创建对象:
stu_1 = Student()  # 一张
stu_2 = Student()  # 两张
stu_3 = Student()  # 三张

# 填写表格即使用对象(为属性赋值):
stu_1.name = "q"
stu_2.name = "w"
stu_3.name = "e"

(3) 成员变量和成员方法

(3.1) 成员变量

  • 定义在类内部的变量称之为成员变量,用法与正常变量一致。

(3.2) 成员方法

定义在类内部的函数称之为方法,与函数存在细微区别。

# 函数
# 形参可以为0-N个
def 函数名(形参1,形参2,..,形参N):
    函数体

# 方法
# 形参可以为0-N个
# self关键字必须填写
def 方法名(self,形参1,形参2,..,形参N):
    方法体
  • self关键字在成员方法定义的时候必须填写,表示类对象自身
  • 在方法内部,想要访问类的成员变量,必须使用self
class fun():
    name = None  
    
    # 调用say_hi1时正常打印
    def say_hi1(self):
        print(f"大家好,我叫{self.name}") 
    
    # 调用say_hi2时报错,'name' is not defined
    def say_hi2(self):
        print(f"大家好,我叫{name}") 
  • 当我们使用对象调用方法时,self会自动被python传入,self尽管在参数列表中,但是传参的时候可以忽略它。
# 定义
class Student:
    name = None

    def say_hi(self, msg):
        print(f"大家好,我是{msg}")

# 创建
stu_1 = Student()
# 通过对象名调用
stu_1.say_hi("练习两年半的实习生")
# 打印 大家好,我是练习两年半的实习生

(4) 构造方法

通过传参的形式快速对属性赋值

  • 在类可以使用:__init__()方法,即构造方法,快速为对象赋值。
# 定义类
class Student:
    name = None  # 姓名
    sex = None  # 性别
    age = None  # 年龄

    def __init__(self, name, sex, age):
        self.name = name
        self.sex = sex
        self.age = age

# 创建对象并赋值
stu_1 = Student("李白", "男", 1000)

# 简化形式:可以省略成员属性定义,但仍可调用
class Student:

    def __init__(self, name, sex, age):
        self.name = name  # 姓名
        self.sex = sex  # 性别
        self.age = age  # 年龄

# 创建对象并赋值
stu_1 = Student("李白", "男", 1000)

在创建类对象(构造类)的时候,会自动执行,将传入参数自动传递给__init__方法使用。

构造方法也是成员方法,定义时也需要在参数列表中提供:self

变量定义在构造方法内部,如果要成为成员变量,需要用self来表示,例如self.name

使用了构造方法,创建对象时必须传参否则会报错

(5) 魔术方法

Python类内置的类方法,各自有各自特殊的功能

f0b56a3821b24e10b67ab889285c29fd.png

(5.1)__str__方法

  • 当直接打印类对象时,打印的是对象的内存地址。
class Student:

    def __init__(self, name, age):
        self.name = name  # 姓名
        self.age = age  # 年龄

stu_1 = Student("李白", 1000)
print(stu_1)
# 打印 <__main__.Student object at 0x0000024D8C6195D0>

通过__str__方法,自定义控制打印类对象时输出的内容。

class Student:

    def __init__(self, name, age):
        self.name = name  # 姓名
        self.age = age  # 年龄
        
	# 自定义打印输出内容,为类自定义打印的内容
    def __str__(self):
        return f"Student对象,name={self.name},age={self.age}"

stu_1 = Student("李白", 1000)
print(stu_1)
# 打印 Student对象,name=李白,age=1000

(5.2)__lt__方法

  • 直接对2个对象进行比较是不可以的,会报错。
class Student:

    def __init__(self, name, age):
        self.name = name  # 姓名
        self.age = age  # 年龄


stu_1 = Student("李白", 1000)
stu_2 = Student("罗辑", 300)
print(stu_1 > stu_2) # 报错
  • 在类中实现__lt__方法即可完成:小于符号 和 大于符号 2种比较
class Student:

    def __init__(self, name, age):
        self.name = name  # 姓名
        self.age = age  # 年龄

    def __lt__(self, other):
        return self.age < other.age


stu_1 = Student("李白", 1000)
stu_2 = Student("罗辑", 300)
print(stu_1 > stu_2) # 打印 True

(5.3) __le__方法

  • 在类中实现__le__方法即可完成:小于等于符号 和 大于等于符号 2种比较
class Student:

    def __init__(self, name, age):
        self.name = name  # 姓名
        self.age = age  # 年龄

    def __le__(self, other):
        return self.age <= other.age


stu_1 = Student("李白", 1000)
stu_2 = Student("罗辑", 1000)
print(stu_1 <= stu_2)  # True
print(stu_1 >= stu_2)  # True

(5.4) __eq__方法

  • 不实现__eq__方法,对象之间可以比较,比较的是内存地址,不同对象之间对于"=="的比较一定是False结果。
class Student:

    def __init__(self, name, age):
        self.name = name  # 姓名
        self.age = age  # 年龄


stu_1 = Student("李白", 1000)
stu_2 = Student("李白", 666)
print(stu_1 == stu_2)  # False
  • 实现了__eq__方法,就可以按照自己的想法来决定2个对象是否相等了。
class Student:

    def __init__(self, name, age):
        self.name = name  # 姓名
        self.age = age  # 年龄
	# 自定义比较规则
    def __eq__(self, other):
        return self.name == other.name


stu_1 = Student("李白", 1000)
stu_2 = Student("李白", 666)
print(stu_1 == stu_2)  # True

(6)三大特性

面向对象包含3大主要特性:封装,继承,多态

(1) 封装

将现实世界事物的属性和行为在类中描述为成员变量和成员方法,完成程序对现实世界事物的描述

89af566abe2e448e954a9eb3e28f26ff.png

现实世界中的事物,有属性和行为。但是不代表这些属性和行为都是开放给用户使用的

5f8f55dd2539478e9969164e899b704c.png

私有成员

在类中提供仅供内部使用的属性和方法,无法被对象调用,但可以通过提供的公有方法来间接访问。

  • 私有成员变量:变量名以__开头(2个下划线)
  • 私有成员方法:方法名以__开头(2个下划线)
  • 仅在成员内部可以使用

839f4572eb0b47409ed73bb92a21f91e.png

class Student:
    name = None  # 普通成员变量
    __age = 1  # 私有成员变量
    
    # 普通成员方法
    def say_hi(self):
        self.__DNA()  # 在类中使用私有成员变量
        if self.__age > 18: # 在类中使用私有成员变量
            print("成年人")
        else:
            print("未成年")
        print("你好")

    # 私有成员方法
    def __DNA(self):
        print("DNA数量")


class MyClass:
    def __init__(self, name):
        self.__secret = "This is private"  # 私有成员
        self.name = name  # 公有成员

    def get_secret(self):
        return self.__secret  # 提供一个方法访问私有成员

obj = MyClass("Alice")
print(obj.name)  # 可以直接访问公有成员
# print(obj.__secret)  # 这会导致错误,因为 __secret 是私有的
print(obj.get_secret())  # 可以通过类的方法访问私有成员,输出 "This is private"

公有成员

公有成员可以在类的外部访问。它们的访问权限是公开的,这意味着类外部的任何代码都可以访问和修改这些成员。一般来说,公有成员用于表示类的公共接口,供类外部的用户使用。

class MyClass:
    def __init__(self, name):
        self.name = name  # 这是一个公有成员

obj = MyClass("Alice")
print(obj.name)  # 输出 "Alice"

(2)继承

一个类继承另外一个类的所有成员变量和成员方法(不含私有)

(2.1) 单继承

class 类名(父类名):
    类内容体
# 待继承的类
class Phone:
    producer = "apple"  # 厂商

    def call_by_3g(self):
        print("3g通话")

# 继承Phone
class Phone2025(Phone):
    face_id = True  # 面部识别

    def call_by_4g(self):
        print("2025最新4G通话")
# 创建对象
phone = Phone2022()
# 使用
print(phone.producer) # 可调用 继承自Phone的成员变量
print(phone.face_id) # 可调用 自身的成员变量
phone.call_by_4g() # 可调用 继承自Phone的成员方法
phone.call_by_5g() # 可调用 自身的成员方法

(2.2) 多继承

  • 一个类也可以继承多个类
  • 多个父类中,如果有同名的成员,默认以继承顺序(从左到右)为优先级。即:后继承的被先继承的覆盖
class 类名(父类1,父类2,...,父类N):
    类内容体
class Phone:
    producer = "apple"  # 厂商

class Camera:
    producer = "suoni"  # 厂商

class Phone2025(Phone, Camera):
    face_id = True  # 面部识别

    def call_by_4g(self):
        print("2025最新4G通话")

phone = Phone2022()

print(phone.producer)  # 打印结果为apple而非suoni

(2.3) 复写

  • 子类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写。即:在子类中重新定义同名的属性或方法。

  • 一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员

class Phone2025:
    producer = "apple"  # 厂商

    def call_by_4g(self):
        print("2025版4G通话")


class Phone2028(Phone2025):
    face_id = True  # 面部识别

    def call_by_4g(self):
        print("2028升级版8G通话")


phone = Phone2028()

phone.call_by_5g()  # 打印 2028升级版8G通话

如果需要使用被复写的父类的成员,只能在子类内通过如下方式调用父类的同名成员:

  • 方式一:使用父类名调用
使用成员变量:父类名.成员变量
使用成员方法:父类名.成员方法(self)
  • 方式二:使用super()调用
使用成员变量:super().成员变量
使用成员方法:super().成员方法()
class Phone2025:
    producer = "apple"  # 厂商

    def call_by_5g(self):
        print("2021版5G通话")


class Phone2028(Phone2025):
    face_id = True  # 面部识别

    def call_by_5g(self):
        # 方式一调用
        print(Phone2025.producer)  # 打印 apple
        Phone2025.call_by_5g(self)# 打印 2021版5G通话
        # 方式二调用
        print(super().producer)# 打印 apple
        super().call_by_5g()# 打印 2021版5G通话

(3)多态

多种状态,即完成某个行为时,使用不同的对象会得到不同的状态

多态常作用在继承关系上,函数(方法)形参声明接收父类对象,实际传入父类的子类对象进行工作,即

  • 以父类做定义声明

  • 以子类做实际工作

  • 用以获得同一行为, 不同状态

69d8f7d98e9940ac82edf3a62c3ad159.png

(3.1) 抽象类(接口)

抽象类就好比定义一个标准,包含了一些抽象的方法,要求子类必须实现

d9edec44dd9e4c81b0825d9b5cb62c37.png

提出标准后,不同厂家各自实现标准的要求。

  • 抽象类:包含抽象方法的类

  • 抽象方法:没有具体实现的方法(只含pass)称之为抽象方法

  • pass是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思

  • 多用于做顶层设计(设计标准),以便子类做具体实现。是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法,并配合多态使用,获得不同的工作状态。

86890f225d6b49c9a24ef305d9f7195a.png

数据容器

一种可以容纳多份数据的数据类型,容纳的每一份数据称之为1个元素

  • 每一个元素,可以是任意类型的据数,如字符串、数字、布尔等
  • 根据特点的不同可分为5类:列表(list)、元组(tuple)、字符串(str)、集合(set)、字典(dict)

列表(list)

列表内的每一个数据,称之为元素

# 定义列表
变量名称 = [元素1, 元素2, 元素3, 元素4, 元素5]
# 定义空列表
变量名称 = []
变量名称 = list()

["qwq", 20, True, ["qwq", 20]]
  • 以中括号 [] 作为标识

  • 列表内每一个元素之间用, 逗号隔开

  • 列表可以一次存储多个数据,且可以为不同的数据类型,支持嵌套

列表的下标(索引)

可以使用下标索引从列表中取出特定位置的数据

  • 列表中的每一个元素,都有其对应位置下标索引
  • 要注意下标索引的取值范围(有值的位置),超出范围(没值的位置)无法取出元素,并且会报错
  • 语法:变量 = 列表[下标索引]

正向索引:

  • 从前向后的方向,从0开始,依次递增

反向索引:

  • 从后向前:从**-1**开始,依次递减(-1、-2、-3…)

嵌套索引

  • 如果列表是嵌套的列表,同样支持下标索引,且用法与上述类似

my_list = [["李白", "章北海"], ["罗辑", "杜甫"]]
print(my_list[0][0])

列表提供了一系列方法:如果将函数定义为class(类)的成员,那么函数称之为:方法

9c6392dbcc9f47db89ff50141a678129.png

列表[索引 ] = 值 修改元素

while index < len(列表)  for 临时变量 in 数据容器:  列表遍历

for vs while

在循环控制上:

while循环可以自定循环条件,并自行控制

for循环不可以自定循环条件,只可以一个个从容器内取出数据

在无限循环上:

while循环可以通过条件控制做到无限循环

for循环理论上不可以,因为被遍历的容器容量不是无限的

在使用场景上:

while循环适用于任何想要循环的场景

for循环适用于,遍历数据容器的场景或简单的固定次数循环场景

元组(tuple)

元组同列表一样,但一旦定义完成,就不可修改

# 定义元组
变量名称 = (元素1, 元素2, 元素3, 元素4, 元素5)
# 定义只有一个元素的元组
变量名称 = (元素1,)
# 定义空元组
变量名称 = ()
变量名称 = tuple()
  • 以小括号 () 作为标识

  • 元组内每一个元素之间用, 逗号隔开

  • 元组可以一次存储多个数据,且可以为不同的数据类型,支持嵌套, 支持元组嵌套

  • 元组只有一个数据,这个数据后面要添加逗号,否则不是元组
my_tuple = ("a")
print(type(my_tuple)) # 打印 <class 'str'>
my_tuple = ("a",)
print(type(my_tuple))  # 打印 <class 'tuple'>

159163a311a84cb4beec157c8f388640.png

查询元素

元组[下标索引] 

print(my_tuple[0])
  • 查找特定元素的第一个匹配项

元组.index(元素)

print(my_tuple.index("a"))
  • 不可以修改元组的内容,否则会直接报错
  • 可以修改元组内的list的内容(修改元素、增加、删除、反转等)
  • 不可以替换list为其它list或其它类型
my_tuple = (1, True, "a")
my_tuple[0] = 5 # Error

my_tuple = (1, True, [2, 3, 4])
my_tuple[2][0] = 5
print(my_tuple) # 打印 (1, True, [5, 3, 4])

my_tuple = (1, True, [2, 3, 4])
my_tuple[2] = [1, 2, 3] # 报错
  • 可以与列表一样使用for与while循环遍历
  • 多数特性和list一致,不同点在于不可修改的特性
  • 可以容纳多个、多种数据
  • 数据是有序存储的(下标索引)
  • 允许重复数据存在
  • 不可以修改(增加或删除元素等)

字符串(str)

字符串是字符的容器,一个字符串可以存放任意数量的字符。

  • 同元组一样,字符串是一个无法修改的数据容器

索引取值

  • 同列表、元组一样,字符串也可以通过下标进行访问
    • 从前向后,下标从0开始
    • 从后向前,下标从-1开始

9fa7220dc87e4c6c95c22e262fbd880d.png

name = "   abcd    "
new_name = name.strip()
print(new_name)  # 打印 abcd


name = "20abcd20"
new_name = name.strip("20")
print(name)  # 打印 20abcd20
print(new_name)  # 打印 abcd

name = "20abcd20"
print(name.count("20"))  # 打印 2

同列表、元组一样,字符串也支持while循环和for循环进行遍历

特点:

只可以存储字符串
长度任意(取决于内存大小)
支持下标索引
允许重复字符串存在
不可以修改(增加或删除元素等)
基本和列表、元组相同

不同与列表和元组的在于:字符串容器可以容纳的类型是单一的,只能是字符串类型。

不同于列表,相同于元组的在于:字符串不可修改

切片

序列:内容连续、有序,可使用下标索引的一类数据容器

切片:从一个序列中,取出一个子序列

  • 序列的典型特征就是:有序并可用下标索引,字符串、元组、列表均满足这个要求
  • 序列支持切片,即:列表、元组、字符串,均支持进行切片操作
序列[起始下标:结束下标:步长]

表示从序列中,从指定位置开始,依次取出元素,到指定位置结束,得到一个新序列:

起始下标表示从何处开始,可以留空,留空视作从头开始

结束下标(不含)表示何处结束,可以留空,留空视作截取到结尾

步长表示,依次取元素的间隔

步长1表示,一个个取元素
步长2表示,每次跳过1个元素取
步长N表示,每次跳过N-1个元素取
步长为负数表示,反向取(注意,起始下标和结束下标也要反向标记)

  • 起始下标可以省略,省略从头开始
  • 结束下标可以省略,省略到尾结束
  • 步长可以省略,省略步长为1(可以为负数,表示倒序执行)
my_list = [1, 2, 3, 4, 5]
new_list = my_list[::2]       # 从头开始,到最后结束,步长2
print(new_list)       # 结果:[1, 3, 5]

my_str = "12345"
new_str = my_str[:4:2]  # 从头开始,到下标4(不含)结束,步长2
print(new_str)  # 结果:"13"

my_list = [1, 2, 3, 4, 5]
new_list = my_list[3:1:-1]  # 从下标3开始,到下标1(不含)结束,步长-1(倒序)
print(new_list)  # 打印 [4, 3]

  • 这个操作对列表、元组、字符串是通用的
  • 此操作不会影响序列本身,而是会得到一个新的序列(列表、元组、字符串)
  • 起始位置,结束位置,步长(正反序)都是可以自行控制的

集合(set)

不支持元素的重复(自带去重功能)、并且内容无序

# 定义集合
变量名称 = {元素1, 元素2, 元素3, 元素4, 元素5}
# 定义空集合
变量名称 = set()
  • 以大括号 {} 作为标识

  • 集合内每一个元素之间用, 逗号隔开

  • 集合可以一次存储多个数据,且可以为不同的数据类型,支持嵌套

  • 去重且无序
my_set = {"a", True, "a"}
print(my_set)  # 打印 {True, 'a'}

集合不支持下标索引,所以也就不支持使用while遍历

for i in my_set:

1dcf79b5c31744f49fe6e0cefb9159b6.png

  • 可以容纳多个数据
  • 可以容纳不同类型的数据(混装)
  • 数据是无序存储的(不支持下标索引)
  • 不允许重复数据存在
  • 可以修改(增加或删除元素等)

字典、映射(dict)

# 定义字典
变量名称 = {key:value, key:value, key:value}
# 定义空字典
变量名称 = {}
变量名称 = dict()
  • 使用{}存储,每一个元素是一个键值对
  • 每一个键值对包含Key和Value(用冒号分隔)
  • 键值对之间使用逗号分隔
  • Key和Value可以是任意类型的数据(key不可为字典)
  • Key不可重复,重复会对原有数据覆盖
  • 字典同集合一样,不可以使用下标索引取值
  • 字典可以通过Key值来取得对应的Value
  • 字典的Key和Value可以是任意数据类型(Key不可为字典),即字典是可以嵌套的
  • 字典不支持下标索引,同样不可以用while循环遍历
my_dict = {"李白": 120, "杜甫": 110}
print(my_dict["李白"])  # 打印 120


my_dict = {
    "李白": {"语文": 110, "数学": 100}, 
    "观止": {"语文": 90, "数学": 120}
}
print(my_dict["李白"])  # 打印 {'语文': 110, '数学': 100}
print(my_dict["李白"]["语文"])  # 打印 110


my_dict = {"李白": 120, "观止": 110}
for name in my_dict:
    print(f"key为:{name},value为:{my_dict[name]}")
# key为:李白,value为:120
# key为:观止,value为:110

c109363f411946a3bd7a88012fcc5112.png

  • 如果key不存在字典中执行下面操作,就是新增元素
  • 如果key存在字典被修改,字典Key不可以重复
字典[Key] = Value
  • 可以容纳多个数据
  • 可以容纳不同类型的数据
  • 每一份数据是Key-Value键值对
  • 可以通过Key获取到Value,Key不可重复(重复会覆盖)
  • 不支持下标索引
  • 可以修改(增加或删除更新元素等)

数据容器对比

是否支持下标索引

        支持:列表、元组、字符串 - 序列类型

        不支持:集合、字典 - 非序列类型

是否支持重复元素:

        支持:列表、元组、字符串 - 序列类型

        不支持:集合、字典 - 非序列类型

是否可以修改

        支持:列表、集合、字典

        不支持:元组、字符串

a4f9d5d3e5994d1b9d47142fc61f41e8.png

应用场景

  • 列表:一批数据,可修改、可重复的存储场景
  • 元组:一批数据,不可修改、可重复的存储场景
  • 字符串:一串字符串的存储场景
  • 集合:一批数据,去重存储场景
  • 字典:一批数据,可用Key检索Value的存储场景

f1f4e9e5347e4b08b3ccc1a1efe5bfc7.png

遍历

  • 5类数据容器都支持for循环遍历

  • 列表、元组、字符串支持while循环,集合、字典不支持(无法下标索引)

统计

len(容器)  统计容器的元素个数
max(容器)  统计容器的最大元素
min(容器)  统计容器的最小元素

排序

  • 将给定容器进行排序,排序后都会得到列表(list)对象。

sorted(容器, [reverse=True])

my_list = [1, 4, 2]
my_list_asc = sorted(my_list)
print(my_list_asc)  # 结果 [1, 2, 4]
my_list_des = sorted(my_list, reverse=True)
print(my_list_des)  # 结果 [4, 2, 1]

转换

  • 将给定容器转换为列表

                list(容器)

  • 将给定容器转换为字符串

                str(容器)

  • 将给定容器转换为集合

                set(容器)

  • 将给定容器转换为元组

                tuple(容器)

pandas库详解

1.1 Series

Series:一维的带索引数据结构(单列)

Series类:

pd.Series(data=None,index=None,dtype=None,name=None,copy=False,fastpath=False)

1、创建Series对象  # 第一列为索引,第二列为Series数据

sdata = pd.Series(np.arange(1,4), index=list('abc'))

2、Series对象访问

.iloc[]确保是按位置(即第几行或第几列,位置是从0开始)访问Series对象

.loc[]确保是按照标签(/索引)访问。

print(sdata.iloc[0]) # 默认数字位置
print(sdata['b']) # 使用标签[a,b,c]
print(sdata.loc['c']) # 使用loc方式,只能使用标签(/索引)
for item in sdata.items(): # tuple
    print(item)

3、获取index与value

sdata.index.values # 获取索引
sdata.values # 获取值

4、index与value转成列表

sdata.index.values.tolist() # 将索引转成列表
sdata.values.tolist() # 将数据转成列表

1.2  dataframe

DataFrame:多种类型的列构成的二维标签数据结构(多列);

DataFrame类:

pd.DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)
data:一维数据,二维数据
index:行标签
columns:列标签

1、Dataframe创建

pd.DataFrame(data=np.arange(1,4))  # 一列数据

data = np.arange(16).reshape(4,4) # 多维数据 data为4X4
pd.DataFrame(data=data)

data = np.arange(16).reshape(4,4) # 设置index与columns
pdata = pd.DataFrame(data=data, index=list('abcd'), columns=['c1','c2','c3','c4'])

data = {'c1':[1,2,3], 'c2':[4,5,6]} # 设置index与columns
pdata = pd.DataFrame(data=data)

pdata.columns = ['t1','t2'] # 设置列标签

2、DataFrame对象访问

pdata['c1'] # 获取一列数据,返回Series对象
pdata[['c1','c2']]  # 取多列数据

loc操作:使用类似列表方式去对数据进行访问,支持bool索引

pdata=pd.DataFrame(data=np.arange(16).reshape(4,4),index=['a','b','c','d'],columns=['c1','c2','1','2'])
pdata.loc['a'] # 获取索引为'a'的行
pdata.loc['a',['c1','c2']] # 获取索引为'a'的指定c1,c2列
pdata.iloc[0] # 获取第一行

for item in pdata: # 获取列索引
    print(item)

for item in pdata.items(): # 按列遍历
    print(item)

for item in pdata.iterrows(): # 按行遍历
    print(item)

pdata['c1'] = 0 # 修改c1列值
pdata['c1'] = [-1,-1,-1,1] # 修改c1列值
data.loc['2'] = [2,3,4,5] # 直接插入行
data.iloc[:,1] = [2,2,2,2] # 修改第二列的值   
data.iloc[1:1,1] = 2  # 修改失败原因是左开右闭
data.iloc[:,4] = [2,3,4,5] # 无法改变原始数据框大小

1.3 数据导入 and 保存

1、读取csv or excel or json

pd.read_csv(file_path_or_buffer, sep=',', delimiter=None, header='infer', names=None, index_col=None, encoding=’GBK’,...)

pd.read_excel(io, sheet_name=0, names=None, index_col=None, usecols=None, encoding=’GBK’,...)   # usecols = ['  ',’  ’]   # 导入指定列  # header=1/None   # 导入指定表头

pd.read_json(path_or_buf=None, orient=None, typ='frame', dtype=None,encoding=’GBK’, ...)

2、保存csv or excel or json

pdata.to_csv(path_or_buf=None,index=False, sep=',',columns=['1990','1991'] ...)  # 保存指定列

pdata.to_excel(excel_writer, sheet_name='Sheet1',index=False, na_rep='', ...)

pdata.to_json(path_or_buf=None,index=False, orient=None, ...)

1.4缺失数据处理

缺省值:数据集中数值为空的值, pandas使用Nan / Na/None 表示

空值:空字符串 ""

1、缺失值判断

pd.isnull(data)=data.isnull()  #  缺省值对应的值为True,返回值为Boolean的Series或者DataFrame对象

pd.notnull(data)  # 缺省值对应的值为False,返回值为Boolean的Series或者DataFrame对象

pd.isnull(data).sum()  # 统计每列缺失值的个数

np.all(pd.notnull(data))  # np.all 与 pd.notnull结合,返回False, 说明包含缺省值,否则不包含缺省值

np.any(pd.isnull(data))  # np.any 与 pd.isnull结合,返回False,说明不含缺省值,返回True说明包括缺省值

2、缺省值处理:

过滤缺省值(按行列) 

bindex = np.all(pdata.notnull(), axis=1)  # 获取boolean索引

data[bindex]

删除缺省值(按行列)

data.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)

axis:0按行操作,1按列操作
How:根据 axis 指定操作方式,any:只要有一个 Na 就删除,all:全部为 Na 才删除
thresh 指定非 Na 值的数量,非 Na 数量大于等于 thresh 时不删除
subset 指定操作的列子集
inplace True:在原始数据中进行修改,不指定inplace时都不会对原始数据修改

3、填充值,填充值方式:

插入均值,中位数,最大值,最小值等

插入特殊值

插入前(后)值入前(后)值

pdata.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)

value 填充值
method 填充方式:{'backfill', 'bfill', 'pad', 'ffill', None}
axis 指定行列:0 或 'index' 表示按行,1 或 'columns' 表示按列
limit 插入数量限制
data.fillna(0)  # 固定值0
pdata.fillna(method='ffill')  # 使用前一行数据填充
pdata.ffill()  # 使用向前填充 (ffill) 替代 fillna
pdata.fillna(method='bfill') # 使用后一行数据填充
pdata.bfill()  # 使用向后填充 (bfill) 替代 fillna
pdata.fillna(axis=1,method='bfill')  # 使用后一列数据填充
pdata.bfill(axis=1)  # 使用向后填充 (bfill) 替代 fillna

插入均值,中位数,最大值,最小值

data.mean/max/min/median(axis=None, skipna=None, level=None, numeric_only=None, **kwargs)

axis   方向,0 表示按列,1 表示按行
skipna 是否忽略 NaN,True 表示不计算 NaN,默认为 True
pdata.fillna(pdata.mean())  #插入中位数
pdata.fillna(pdata.median())  #插入中位数

按特定条件筛选数据生成boolean索引

bindex = data['math'] > 80  # 数学成绩大于80的所有成绩
data[bindex]

data[(data['math']>59) & (data['chinese']>59)]  # 数学语文都及格成绩   与条件
data[(data['math']>59)  |  (data['chinese']>59)]  # 数学语文有一门大于等于80分  或条件

bindex = pdata['math'].isin([100, 90])  # 根据集合获取数据
pdata[bindex]

1.5数据排序

1、排序方式1:根据索引排序

data.sort_index(axis=0,level=None,ascending=True,...)  # 降序,ascending=False

排序方式2:根据指定列内容排序

data.sort_values(by=’columns1’ / [columns1, columns2], axis=0, ascending=True,...)

2、pandas汇总与描述性统计方法:

最大值:data.max(axis=None, skipna=None, level=None, numeric_only=None, **kwargs)
最小值:data.min(axis=None, skipna=None, level=None, numeric_only=None, **kwargs)
均值:data.mean(axis=None, skipna=None, level=None, numeric_only=None, **kwargs)
中位数:data.median(axis=None,skipna=None,level=None,numeric_only=None, **kwargs)
求和:data.sum(axis=None,skipna=None,level=None,numeric_only=None,min_count=0,**kwargs)
方差:data.var(axis=None,skipna=None,level=None,ddof=1,numeric_only=None,**kwargs)
标准差:data.std(axis=None,skipna=None,level=None,ddof=1,numeric_only=None,**kwargs)
累加和:data.cumsum(axis=None, skipna=True, *args, **kwargs)
分位数:data.quantile(q=0.5, axis=0, numeric_only=True, interpolation='linear')
每个数值到均值的平均差:data.mad(axis=None, skipna=None, level=None)
元素与先前元素的相差百分比:data.pct_change(periods=1,fill_method='pad',limit=None,freq=None,**kwargs)
偏度:data.skew(axis=None, skipna=None, level=None, numeric_only=None, **kwargs)
峰度:data.kurt(axis=None, skipna=None, level=None, numeric_only=None, **kwargs)
数据描述:data.describe(percentiles=None, include=None, exclude=None)

1.6设置索引

1、重置索引方法:

pdata.set_index(keys,drop=True,append=False,inplace=False)
keys 指定索引名称,可以是多列
drop True:删除列数据,False:保留列数据
append True:在原有列基础上追加,False:替代原有列
inplace True:在原数据中进行修改,False:返回新数据

data.set_index('name'/['name','math'])

2、多级索引  该方法和上述set_index一样(不相邻时不会合并,一级索引相邻有重复会自动合并)

pd.MultiIndex.from_arrays(arrays, sortorder=None, names=None)   # 创建MultiIndex对象
mindex = pd.MultiIndex.from_arrays([list1, list2])
data = pdata.set_index(mindex)

data.loc[‘1’]   # 取一级索引标签为1的所有数据(如果二级索引有多行,会取出一级索引相同的所有数据)

如果想取出二级索引相同值的所有行,就需要交换一二级索引
data = data.swaplevel(‘column1’,’column2’)  # 针对MultiIndex对象,普通set_index不支持

3、行列变换

names = list('ABCDABCD')
pdata = pd.DataFrame(np.random.randint(30,100, size=(8,2)),columns=['math','chinese'])
lv1 = [1]*4+[2]*4
lv2 = list('ABCDABCD')

mindex = pd.MultiIndex.from_arrays([lv1, lv2])
pdata = pdata.set_index(mindex)

pdata.stack(level=0, dropna=True):将列“旋转”为行   # 将学期转到列
pdata.unstack(level=0, fill_value=None):将行“旋转”为列  # 将学科转为行

pdata.loc['A'][1]
pdata.swaplevel(axis=1)[1]   # 列索引层级交换,获取第一学期数据
pdata.sort_index(level = 1)   # 按二级索引排序, level = 0 按一级索引排序

1.7时间序列

1、时间戳方法:

pd.Timestamp(ts_input=<object object at 0x00000258D4E907F0>,freq=None, tz=None,...)
pd.to_datetime(arg,errors='raise', dayfirst=False,...)

print(pd.Timestamp(2020))#年
print(pd.Timestamp(2020, 6, 2))#年月日
print(pd.Timestamp('2020-05-07'))#字符串
print(pd.Timestamp('2020-05-07 04:02:01'))#字符串时间
print(pd.Timestamp('2017-01-01T12'))#字符串时间
print(pd.Timestamp(1513393355.5, unit='s'))#时间戳
print(pd.to_datetime('2017-03-01',format="%Y-%m-%d"))#2017-03-01与format对应
print(pd.to_datetime('20170301',format="%Y%m%d"))#20170301与年月日对应
print(pd.to_datetime('2017-02-01',format="%Y-%m-%d"))
print(pd.to_datetime(['2017-02-01'],format="%Y-%m-%d"))#生成时间索引

2、时间索引

pd.date_range(start=None,end=None,periods=None,freq=None,tz=None, ... **kwargs):生成DatetimeIndex
start 开始时间
end 结束时间
periods 产生周期数量
freq 间隔,默认为 D(天),可选其他频率,例如:H(小时)、T(分钟)、Q(季度)等
closed 闭区间:None、'left'、'right'

index = pd.date_range('1/1/2000', periods=9, freq='2T')
print(pd.date_range('2017-01-01', periods=2))# 周期单位为Day
print(pd.date_range('2017-01-01 02', periods=2, freq='H'))# 周期单位为hour
print(pd.date_range('2017-01', periods=3, freq='MS'))# 每个月月初
print(pd.date_range('2017-01', periods=3, freq='M'))# 每个月月底

3、周期

通过时间段与固定时间间隔一系列时间

周期作用:可以获取指定年,指定月,指定日等的数据

周期:

pd.Period(value=None,freq=None,ordinal=None,year=None,...)

周期序列:

pd.period_range(start=None, end=None, periods=None, freq=None, name=None)

生成PeriodIndex:

pdata.to_period(freq=None, axis=0, copy=True)

print(pd.Timestamp('2017-01-02'))
print(pd.Period('2017-01-02'))
print(pd.Period('2017-01'))
print(pd.Period('2017'))
print(pd.period_range('2017-01-01', periods=2))# 周期单位为Day
print(pd.period_range('2017-01', periods=2, freq='M'))# 周期单位为月
print(pd.period_range('2017-01-02', periods=2, freq='H'))# 周期单位为小时

pd.to_datetime(['2017-01-02', '2017-03-04']).to_period('M')

4、时间差值

timedalte:两个datetime值之间的差(如日,秒和微妙)的类型

pd.Timedelta(value= <object object at 0x0000023DD1424CC0> , unit=None, **kwargs)
pd.Timestamp('2019-01-02')-pd.Timestamp('2019-01-01')# Timestamp相减

5、重采样

重采样作用:降低采样率    提升采样率

data.resample(rule,how=None,axis=0,fill_method=None,closed=None,label=None,convention='start'...)

rule 规则,例如:'T'(分钟)、'M'(月份)等
fill_method 提升采样率填充方式,'ffill'(向前填充)、'bfill'(向后填充)等
closed 降低采样率时的闭合方式,'right' 或 'left',默认为 'right'
label 降低采样率时的聚合值标签,{'right', 'left'}
loffset 时间偏差,用于调整聚合后的时间索引,可以是 timedelta 类型
kind 聚合方式,'period' 或 'timestamp',默认聚合到时间索引
index = pd.date_range('1/1/2000', periods=9, freq='2T')
series = pd.Series(range(9), index=index)
s = series.resample('4T')  # 降低采样率,将时间间隔改成4S,每个时间对应值为均值
s.groups

rd = series.resample('T')  #提高采样率,将时间间隔改成S,每个时间对应值为均值
rd.bfill()

Resampler对象相关方法:

s.groups 返回 Resampler 对象,字典
s.max() 降频分组后的最大值
s.min() 降频分组后的最小值
s.first() 降频分组后的第一个值
s.last() 降频分组后的最后一个值
s.mean() 降频分组后的均值
s.median() 降频分组后的中位数

6、时间迁移:对数据按照时间进行迁移

迁移数据:df.shift(periods=1, freq=None, axis=0, fill_value=None)

index = pd.date_range('1/1/2000', periods=9, freq='D')
series = pd.Series(range(9), index=index)
series.shift(1, freq='T')  /  series.shift(1)

1.8数据清洗

获取某列的唯一值:

Series.unique()

每个值出现次数:

Series.value_counts()

删除指定行列:

pdata.drop(labels=None,axis=0,index=None,columns=None, level=None,inplace=False,errors='raise')

print(pdata.drop(0)) / print(pdata.drop(index=[1,2,3])) / pdata.drop(columns='ts')  # 删除单行

去重:

pdata.drop_duplicates(subset=None, keep='first', inplace=False)

pdata.drop_duplicates(subset='ts', keep='last')   #保留最后一次

1.9数据合并

1、merge:将不同数据集根据指定字段进行合并得到新的数据集。

pd.merge(left,right,how='inner',on=None,left_on=None,right_on=None,left_index=False, right_index=False,sort=False,suffixes=('_x', '_y'),copy=True,indicator=False,validate=None)

left 左侧数据集
right 右侧数据集
how 合并方式:left right inner outer
on 索引或者列名,用于连接数据集
left_on 数据连接,左侧数据集的列名
right_on 数据连接,右侧数据集的列名
left_index 使用左侧数据集的索引进行连接
right_index 使用右侧数据集的索引进行连接
sort 是否根据连接键排序
suffixes 合并后相同列名的后缀

2、join方法:DateFrame对象方法,与megre方法类似,how的方式默认为left

df1.join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False)

on 指定连接列  公有列
how 拼接方式
lsuffix 左侧 DataFrame 的列名后缀
rsuffix 右侧 DataFrame 的列名后缀

df1.join(df2.set_index('class'), lsuffix='_x', rsuffix='_y', on ='class')

3、concat:根据设置轴与条件,将两个数据进行拼接

pd.concat(objs,axis=0,join='outer',join_axes=None,ignore_index=False,keys=None,levels=None,names=None...)

objs 一个包含 Series 列表、DataFrame 列表或字典的列表
axis 指定拼接轴,0 表示按索引(index),1 表示按列(columns)
join 连接方式,inner 表示交集,outer 表示并集
ignore_index 是否不使用并置轴上的索引值,True 表示不使用
join_axes 用于指定连接轴的 Index 对象列表
keys 序列,用于构建层次化索引(MultiIndex)
levels 多级索引的特定值
names 列表,用于指定层级索引的名称

1.10数据处理常用函数:apply, agg,str等函数

1、apply函数:对pandas中DataFrame或者Series中每个数据进行处理

apply方法:

df.apply(func,axis=0,broadcast=None, raw=False,reduce=None, result_type=None,args=(), **kwds)

2、func 处理函数,用于处理一系列值

axis 轴设置,指定处理函数的轴,0 表示按列,1 表示按行

DataFrame/series.apply(lambda x: condition/calulation)

df[['math','chinese']].apply(func)其中func处理对象:

<class 'pandas.core.series.Series'>
<class 'pandas.core.series.Series'>

其本质就是定义一个可以匿名表示的函数,函数需要在’一行’之内完成

def func1(x):
    return x-x.mean()

df[['math','chinese']].apply(func1)
等价于
df[['math','chinese']].apply(lambda x:x-x.mean())

3、map

适用于Series对象或DataFrame的某一列
map方法:

Series.map(arg, na_action=None)
对Series中的每个数值进行处理处理
df[['math','chinese']].apply(lambda x : x.map(lambda x: 'pass' if x > 59 else 'failed'))

4、replace:替换

对当前数据集中指定数据进行替换方法:

df.replace(to_replace=None,value=None,inplace=False,limit=None,regex=False,method='pad')

to_replace 替换值,可以是字符串、正则表达式、列表等
value 替换目标值
limit 替换次数的限制
inplace 是否替换原数据,True 表示替换原数据
regex 是否使用正则表达式进行替换,需要设置为 True

df.replace(list('ABCD'), list('abcd'))   # 一组数据替换

5、agg:聚合操作

按照设置axis对数据进行聚合操作(mean, max,…)

df.agg(func, axis=0, *args, **kwargs)
axis: 0:func应用到column, 1:func应用到row

df[['chinese', 'math']].agg(['mean', 'std'])

6、transform:处理数据

根据设置方法,对数据进行处理,得到新的数据

df.transform(func, axis=0, *args, **kwargs)

df[['chinese', 'math']].transform(lambda x:x-x.mean())

7、filter:过滤

根据标签过滤符合条件数据

df.filter(items=None, like=None, regex=None, axis=None)

items labels 值,类似于列表
like 标签模糊匹配
regex 正则表达式匹配
axis 设置轴,指定操作的轴,例如 0(按行)、1(按列)

df.filter(regex=r'.*e')  # 正则表达式:获取e结尾的列

1.11分组处理

根据指定条件,对数据进行分组,然后在依据分组进行计算

1、groupby分组:

df.groupby(by=None,axis=0,level=None,as_index=True,sort=True,group_keys=True,squeeze=False,observed=False,**kwargs)

by 分组依据
axis 轴设置,0 或 'index' 表示按行,1 或 'columns' 表示按列,默认为 0
group_keys 聚合输出,以组标签作为索引,默认为 True
sort 根据分组标签排序,默认为 True
level 多级索引,指定索引
dfg = df.groupby(['cname','height'])  # 分组对象
dfg.groups
dfg.count()  # 分组统计

2、聚合:分组得到groupby对象,可以通过聚合函数对其操作,获取聚合结果

dfg.agg(['max', 'mean', 'std', 'count'])

3、transform

作用:将分组数据处理,得到一组新的数据方法:

dfg.transform(func, *args, **kwargs)

dfg.transform(lambda x: x-x.mean())  # 每组数据与其均值之差

4、Filter:过滤数据

dfg.filter(func, dropna=True, *args, **kwargs):根据过滤条件返回分组数据

5、cut分组

根据设置区间进行分段汇总方法:

pd.cut(x,bins,right=True,labels=None,retbins=False,precision=3,include_lowest=False,duplicates='raise')

r = pd.cut(df, [70,80,90,101], right=False, labels=['70+','80+','100+'])
r.groupby(r, observed=False).count()

6、透视表

透视表是一种可以对数据动态排布并且分类汇总的表格格式,使用方式与groupby类似,但是比其简单,方法:

pd.pivot_table(data,values=None,index=None,columns=None,aggfunc='mean',fill_value=None,margins=False,...)

data 数据
values 用于计算数据项的列
index 行分组键,可以是列名、Grouper、数组等
columns 列分组键,可以是列名、Grouper、数组等
aggfunc 聚合函数或函数列表,或者字典形式的函数
fill_value 设置缺省值
dropna 删除缺省值,True 表示删除,默认为 True
margins 是否增加统计列,True 表示增加,默认为 False
margins_name 新增统计列的列名
df.pivot_table(values=’eat’,index='sex', columns=['class'])

df.pivot_table(values=’eat’,index='sex', columns=['class'],margins=True, margins_name='all_mean')

cuts = pd.cut(df.age,[0,18,100])    # 根据class等级与年龄段,统计男女吃没吃的比例

df.pivot_table(values=’eat’,index=['sex',cuts], columns=['class'])

df.pivot_table(values=’eat’,index=['sex'], columns=['class'], aggfunc=['mean', 'count'],margins=True)  # 根据class等级与年龄段,统计男女获救的比例,数量,并统计所有值

7、str相关方法

str方法是Series对象内置方法,用于对字符串处理,与字符串相关方法类似;

cat(others=None, sep=None, na_rep=None, join=None):拼接字符串
split(pat=None, n=-1, expand=False):切分字符串
get(i):获取指定位置的字符串
join(sep):字符串拼接
find(sub, start=0, end=None):查找,返回第一次出现子集位置
contains(pat, case=True, flags=0, na=nan, regex=True):判断是否包含指定的值
replace(pat, repl, n=-1, case=None, flags=0, regex=True):替换
sf.str.repeat(repeats):重复repeats次
Sf.Startswith(pat, na=nan):判断是否已pat开头
sf.str.endswith(pat, na=nan):判断是否已pat结尾
sf.str.strip(to_strip=None):根据指定字符掐头去尾
sf.str.extract(r'([a-zA-Z]+)')  #提取有效字符
sf.str.match(r'([a-zA-Z]+)')   #字符开头
sf.str.findall(r'([a-z0-9]+)')  #查找所有字符与数字
sf = pd.Series(['a_1', 'b_2', 'c_3'])
sf.str.cat(list('ABC'), sep = '-')

1.12可视化

pandas可以直接绘制图表,实现基于matplotlib,使用方式与其类似,方法:

df.plot(*args, **kwargs)
data Series 或 DataFrame 对象
x 标签或索引,用于指定 x 轴数据
y 标签或索引,用于指定 y 轴数据
kind 绘制图像的样式,例如:line、bar、barh、hist 等
figsize 图像大小
use_index 是否使用 index 作为 x 轴刻度,默认为 True
grid 是否使用栅格,默认为 False
legend 是否显示图例,默认为 True
df.plot()   #绘制折线图   #x:index, y:默认所有columns
df.A.plot()   #A用左侧Y轴
df.B.plot(secondary_y=True, style='g')  #B使用右侧Y轴
折线图:df.plot.line(x=None, y=None, **kwargs)
柱状图:df.plot.bar(x=None, y=None, **kwargs)
条形图:df.plot.barh(x=None, y=None, **kwargs)
直方图:df.plot.hist(by=None, bins=10, **kwargs)
KDE图:df.plot.kde(bw_method=None, ind=None, **kwargs)
饼状图:df.plot.pie(**kwargs)
散点图:df.plot.scatter(x, y, s=None, c=None, **kwargs)
箱状图:df.plot.box(by=None, **kwargs)
区域块状图:df.plot.area(x=None, y=None, **kwargs)*kwargs)

更多参考一文教会pandas-优快云博客

numpy库详解

NumPy是一个Python包。它代表“NumericPython”。由多维数组对象和用于处理数组的例程集合组成的库。

Numeric,即NumPy的前身,是由JimHugunin开发的。也开发了另一个包Numarray,它拥有一些额外的功能。2005年,TravisOliphant通过将Numarray的功能集成到Numeric包中来创建NumPy包,使用NumPy,开发人员可以执行以下操作:

数组的算数和逻辑运算。

傅立叶变换和用于图形操作的例程。

与线性代数有关的操作。NumPy拥有线性代数和随机数生成的内置函数。

1.1 NumPy - Ndarray 对象

NumPy 中定义的最重要的对象是称为 ndarray 的 N 维数组类型。 它描述相同类型的元素集合。可以使用基于零的索引访问集合中的项目。

Ndarray中的每个元素在内存中使用相同大小的块。 ndarray中的每个元素是数据类型对象的对象(称为 dtype)。

从ndarray对象提取的任何元素(通过切片)由一个数组标量类型的 Python 对象表示。 下图显示了ndarray,数据类型对象(dtype)和数组标量类型之间的关系。

numpy.array

它从任何暴露数组接口的对象,或从返回数组的任何方法创建一个ndarray:

numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)

object 任何暴露数组接口方法的对象都会返回一个数组或任何(嵌套)序列。

dtype 数组的所需数据类型,可选。

copy 可选,默认为true,对象是否被复制。

order C(按行)、F(按列)或A(任意,默认)。

subok 默认情况下,返回的数组被强制为基类数组。 如果为true,则返回子类。

ndmin 指定返回数组的最小维数。

import numpy as np
np.array([1,2,3]) # [1,2,3]
np.array([[1,  2],  [3,  4]]) # [[1,  2] [3, 4]]
np.array([1,2,3,4,5], ndmin=1) # array([1, 2, 3, 4, 5])
np.array([1,2,3,4,5], ndmin=2) # array([[1, 2, 3, 4, 5]])
np.array([1, 2, 3], dtype = complex) # [ 1.+0.j,  2.+0.j,  3.+0.j]

支持的数据类型:

bool_ 存储为一个字节的布尔值(真或假)

int_ 默认整数,相当于 C 的long,通常为int32int64

intc 相当于 C 的int,通常为int32int64

intp 用于索引的整数,相当于 C 的size_t,通常为int32int64

int8 字节(-128 ~ 127)

int16 16 位整数(-32768 ~ 32767)

int32 32 位整数(-2147483648 ~ 2147483647)

int64 64 位整数(-9223372036854775808 ~ 9223372036854775807)

uint8 8 位无符号整数(0 ~ 255)

uint16 16 位无符号整数(0 ~ 65535)

uint32 32 位无符号整数(0 ~ 4294967295)

uint64 64 位无符号整数(0 ~ 18446744073709551615)

float_ float64的简写

float16 半精度浮点:符号位,5 位指数,10 位尾数

float32 单精度浮点:符号位,8 位指数,23 位尾数

float64 双精度浮点:符号位,11 位指数,52 位尾数

complex_ complex128的简写

complex64 复数,由两个 32 位浮点表示(实部和虚部)

complex128 复数,由两个 64 位浮点表示(实部和虚部)

NumPy 数字类型是dtype(数据类型)对象的实例,每个对象具有唯一的特征。 这些类型可以是np.bool_,np.float32等。

数据类型对象 (dtype)

数据类型对象描述了对应于数组的固定内存块的解释,取决于以下方面:

        数据类型(整数、浮点或者 Python 对象)

        数据大小

        字节序(小端或大端)

        在结构化类型的情况下,字段的名称,每个字段的数据类型,和每个字段占用的内存块部分。

        如果数据类型是子序列,它的形状和数据类型。

字节顺序取决于数据类型的前缀<或>。 <意味着编码是小端(最小有效字节存储在最小地址中)。 >意味着编码是大端(最大有效字节存储在最小地址中)。

dtype构造:

numpy.dtype(object, align, copy)
Object:被转换为数据类型的对象。
Align:如果为true,则向字段添加间隔,使其类似 C 的结构体。
Copy:生成dtype对象的新副本,如果为flase,结果是内建数据类型对象的引用。
np.dtype(np.int32) # int32 # int8,int16,int32,int64 可替换为等价的字符串 'i1','i2','i4',以及其他。
np.dtype('>i4')  # >i4  # 使用端记号

结构化数据类型的使用

dt = np.dtype([('age',np.int8),(...)]) # 声明字段名称和相应的标量数据类型
A = np.array([(10,),(20,),(30,)], dtype = dt) # [(10,) (20,) (30,)]  # 应用于 ndarray 对象
A['age'] # [10 20 30]  # 文件名可用于访问 age 列的内容

每个内建类型都有一个唯一定义它的字符代码:

'b':布尔值

'i':符号整数

'u':无符号整数

'f':浮点

'c':复数浮点

'm':时间间隔

'M':日期时间

'O':Python 对象

'S', 'a':字节串

'U':Unicode

'V':原始数据(void)

1.2 NumPy - 数组属性

ndarray.shape # 返回一个包含数组维度的元组,它也可以用于调整数组大小
np.array([[1,2,3],[4,5,6]]).shape # (2,3)
A=np.array([[1,2,3],[4,5,6]]);A.shape=(3,2);A
np.array([[1,2,3],[4,5,6]]).reshape(3,2) # [[1, 2],[3, 4],[5, 6]]

ndarray.ndim  # 返回数组的维数
np.arange(24).ndim # 1
A=np.arange(24);A.reshape(2,4,3).ndim # 3 # 2个ndarray,每个ndarray为4x3

numpy.itemsize # 返回数组中每个元素的字节单位长度
np.array([1,2,3,4,5], dtype = np.int8).itemsize  # 数组的 dtype 为 int8(一个字节)
np.array([1,2,3,4,5], dtype = np.float32).itemsize  # 数组的 dtype 现在为 float32(四个字节)

numpy.flags  #  ndarray对象拥有以下属性,返回它们的当前值

C_CONTIGUOUS (C) 数组位于单一的、C 风格的连续区段内

F_CONTIGUOUS (F) 数组位于单一的、Fortran 风格的连续区段内

OWNDATA (O) 数组的内存从其它对象处借用

WRITEABLE (W) 数据区域可写入。 将它设置为flase会锁定数据,使其只读

ALIGNED (A) 数据和任何元素会为硬件适当对齐

UPDATEIFCOPY (U) 这个数组是另一数组的副本。当这个数组释放时,源数组会由这个数组中的元素更新

np.array([1,2,3,4,5]).flags

C_CONTIGUOUS : True
F_CONTIGUOUS : True
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False

1.3 数据创建例程

numpy.empty:创建指定形状和dtype的未初始化数组, 使用以下构造函数:

numpy.empty(shape, dtype = float, order = 'C')
numpy.zeros(shape, dtype = float, order = 'C')
numpy.ones(shape, dtype = None, order = 'C')

Shape 空数组的形状,整数或整数元组
Dtype 所需的输出数组类型,可选
Order 'C'为按行的 C 风格数组,'F'为按列的 Fortran 风格数组

np.empty([3,2], dtype = int) # 随机值
np.zeros(5) # [0., 0., 0., 0., 0.]  #  np.zeros((5,), dtype = np.int)
np.zeros((2,2), dtype =  [('x',  'i4'),  ('y',  'i4')]) # [[(0,0)(0,0)][(0,0)(0,0)]]
np.ones(5) # [1., 1., 1., 1., 1.]

numpy.asarray:类似numpy.array,除了它有较少的参数。 这个例程对于将 Python 序列转换为ndarray非常有用

numpy.asarray(a, dtype = None, order = None)

a 任意形式的输入参数,比如列表、列表的元组、元组、元组的元组、元组的列表
dtype 通常,输入数据的类型会应用到返回的ndarray
order 'C'为按行的 C 风格数组,'F'为按列的 Fortran 风格数组

np.asarray([(1,2,3),(4,5)]) # [(1, 2, 3) (4, 5)]
np.asarray([1,2,3], dtype = float) # [ 1.  2.  3.]

numpy.frombuffer # 此函数将缓冲区解释为一维数组, 暴露缓冲区接口的任何对象都用作参数来返回ndarray

numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)

buffer 任何暴露缓冲区借口的对象
dtype 返回数组的数据类型,默认为float
count 需要读取的数据数量,默认为-1,读取所有数据
offset 需要读取的起始位置,默认为0

np.frombuffer('Hello World', dtype =  'S1') # ['H'  'e'  'l'  'l'  'o'  ' '  'W'  'o'  'r'  'l'  'd']

numpy.fromiter: 此函数从任何可迭代对象构建一个ndarray对象,返回一个新的一维数组

numpy.fromiter(iterable, dtype, count = -1)

iterable 任何可迭代对象
dtype 返回数组的数据类型
count 需要读取的数据数量,默认为-1,读取所有数据


# 从列表中获得迭代器
list = range(5); it = iter(list)  
# 使用迭代器创建 ndarray
x = np.fromiter(it, dtype =  float) # [0.   1.   2.   3.   4.]

numpy.arange  # 返回ndarray对象,包含给定范围内的等间隔值

numpy.arange(start, stop, step, dtype)

start 范围的起始值,默认为0
stop 范围的终止值(不包含)
step 两个值的间隔,默认为1
dtype 返回ndarray的数据类型,如果没有提供,则会使用输入数据的类型。

np.arange(10,20,2) # [10  12  14  16  18]

numpy.linspace # 类似于arange()函数,在此函数中指定了范围之间的均匀间隔数量,而不是步长

numpy.linspace(start, stop, num, endpoint, retstep, dtype)

start 序列的起始值
stop 序列的终止值,如果endpoint为true,该值包含于序列中
num 要生成的等间隔样例数量,默认为50
endpoint 序列中是否包含stop值,默认为ture
retstep 如果为true,返回样例,以及连续数字之间的步长
dtype 输出ndarray的数据类型

np.linspace(10,20,5) # [10.  12.5  15.  17.5  20. ]
np.linspace(10,20,5, endpoint = False) # [10. 12. 14. 16. 18.]
np.linspace(10,20,5, retstep = True) # (array([10. , 12.5, 15. , 17.5, 20. ]), 2.5)

numpy.logspace # 返回一个ndarray对象,其中包含在对数刻度上均匀分布的数字。 刻度的开始和结束端点是某个底数的幂,通常为 10

numpy.logscale(start, stop, num, endpoint, base, dtype)

start 起始值是base ** start
stop 终止值是base ** stop
num 范围内的数值数量,默认为50
endpoint 如果为true,终止值包含在输出数组当中
base 对数空间的底数,默认为10
dtype 输出数组的数据类型,如果没有提供,则取决于其它参数

np.logspace(1,10,num =  10,  base  =  2) # [ 2.     4.     8.    16.    32.    64.   128.   256.    512.   1024.]

1.4 切片和索引

ndarray对象的内容可以通过索引或切片来访问和修改,就像 Python 的内置容器对象一样。

ndarray对象中的元素遵循基于零的索引。 有三种可用的索引方法类型: 字段访问,基本切片和高级索引。

基本切片是 Python 中基本切片概念到 n 维的扩展。 通过将start,stop和step参数提供给内置的slice函数来构造一个 Python slice对象。 此slice对象被传递给数组来提取数组的一部分。

np.arange(10)[slice(2,7,2)] # [2, 4, 6] # 0开始,左开右闭
np.arange(10)[2:7:2] # [2, 4, 6]
np.array([[1,2,3],[3,4,5],[4,5,6]])[1:,1:] # [[4,5] [5,6]]   # 其中 : 等价于 ...

高级索引: 如果一个ndarray是非元组序列,数据类型为整数或布尔值的ndarray,或者至少一个元素为序列对象的元组,就能够用它来索引ndarray, 高级索引始终返回数据的副本。 与此相反,切片只提供了一个视图, 有两种类型的高级索引:整数和布尔值。

整数索引

这种机制有助于基于 N 维索引来获取数组中任意元素。 每个整数数组表示该维度的下标值。 当索引的元素个数就是目标ndarray的维度时,会变得相当直接。

np.array([[1,2],[3,4],[5,6]])[[0,1,2],[0,1,0]]  # 获取指定行列位置((0,0), (1,1)和(2,0))的元素
x = np.array([[  0,  1,  2],[  3,  4,  5],[  6,  7,  8],[  9,  10,  11]])  
rows = np.array([[0,0],[3,3]])  # 行索引是[0,0]和[3,3]
cols = np.array([[0,2],[0,2]])  # 列索引是[0,2]和[0,2]
y = x[rows,cols] # 获取指定行列位置((0,0),(0,2),(3,0),(3,2))的元素,返回2x2
x[1:4,1:3]等价x[1:4,[1,2]]

布尔索引:当结果对象是布尔运算(例如比较运算符)的结果时,将使用此类型的高级索引

a=np.array([1, 2+6j, np.nan, 5, 3.5+5j])  
a[~np.iscomplex(a)]  # a[~np.isnan(a)]

1.5 广播

NumPy在算术运算期间处理不同形状的数组的能力, 对数组的算术运算通常在相应的元素上进行, 如果两个阵列具有完全相同的形状,则这些操作被无缝执行。

如果两个数组的维数不相同,则元素到元素的操作是不可能的。然而在 NumPy 中仍然可以对形状不相似的数组进行操作,因为它拥有广播功能,较小的数组会广播到较大数组的大小,以便使它们的形状可兼容。

如果满足以下规则,可以进行广播:

ndim较小的数组会在前面追加一个长度为 1 的维度。

输出数组的每个维度的大小是输入数组该维度大小的最大值。

如果输入在每个维度中的大小与输出大小匹配,或其值正好为 1,则在计算中可用它。

如果输入的某个维度大小为 1,则该维度中的第一个数据元素将用于该维度的所有计算。

如果上述规则产生有效结果,并且满足以下条件之一,那么数组被称为可广播的。

数组拥有相同形状。

数组拥有相同的维数,每个维度拥有相同长度,或者长度为 1。

数组拥有极少的维度,可以在其前面追加长度为 1 的维度,使上述条件成立。

np.arange(12).reshape(4,3)+np.ones([4,1]) # 列拓展
np.arange(12).reshape(4,3)+np.array([0,1,2]) # 行拓展

1.6 数组迭代

NumPy包含一个迭代器对象numpy.nditer。 它是一个有效的多维迭代器对象,可以用于在数组上进行迭代,数组的每个元素可使用Python的标准Iterator接口来访问。

[x for x in np.nditer(np.arange(0,60,5).reshape(4,3))]
# [print(x) for x in np.nditer(np.arange(0,60,5).reshape(4,3))] # print函数本身返回None
迭代的顺序匹配数组的内容布局,而不考虑特定的排序, 这可以通过迭代上述数组的转置来验证
[x for x in np.nditer(np.arange(0,60,5).reshape(4,3).T)]  # 结果一致,因为在 nditer 中,默认情况下迭代顺序是按行(C 顺序)进行,要明白reshape 和 T 操作在数据排列上并没有改变元素的顺序,只是改变了视图(即如何看待它们)
[x for x in np.nditer((np.arange(0,60,5).reshape(4,3).T).copy(order='C'))]  # 结果不一样因为此处将转置后的数组按C风格复制
[x for x in np.nditer((np.arange(0,60,5).reshape(4,3).T).copy(order='F'))]  # 结果一致

修改数组的值

nditer对象有另一个可选参数op_flags。 其默认值为只读,但可以设置为读写或只写模式。 这将允许使用此迭代器修改数组元素

a=np.arange(0,60,5).reshape(4,3)
for x in np.nditer(a,op_flags=['readwrite']):  # or ValueError: assignment destination is read-only
    x[...]=x*2
a

外部循环 nditer类的构造器拥有flags参数,它可以接受下列值:

c_index 可以跟踪 C 顺序的索引
f_index 可以跟踪 Fortran 顺序的索引
multi-index 每次迭代可以跟踪一种索引类型
external_loop 给出的值是具有多个值的一维数组,而不是零维数组

a=np.arange(0,60,5).reshape(4,3)
for x in np.nditer(a, flags = ['external_loop'], order = 'F'):  # 迭代器遍历对应于每列的一维数组
    print (x)

广播迭代:如果两个数组是可广播的,nditer组合对象能够同时迭代它们。 假设数组a具有维度 3X4,并且存在维度为 1X4 的另一个数组b,则使用以下类型的迭代器(数组b被广播到a的大小)。

for x,y in np.nditer([a,b]):
    print ("%d:%d" %(x,y))

1.7 数组操作

NumPy包中有几个例程用于处理ndarray对象中的元素。 它们可以分为以下类型:

reshape 不改变数据的条件下修改形状

flat 数组上的一维迭代器

flatten 返回折叠为一维的数组副本  order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'k' -- 元素在内存中的出现顺序

ravel 返回连续的展开数组  order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'k' -- 元素在内存中的出现顺序

numpy.ndarray.flat:返回数组上的一维迭代器,行为类似 Python 内建的迭代器。

np.arange(0,60,5).reshape(4,3).flat[3] # 15
np.arange(0,60,5).reshape(4,3).flatten("C")  # [ 0,  5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]
np.arange(0,60,5).reshape(4,3).ravel('C') # [ 0,  5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55]
np.arange(0,60,5).reshape(4,3).ravel('F') # [ 0, 15, 30, 45,  5, 20, 35, 50, 10, 25, 40, 55]

翻转操作

transpose 翻转数组的维度

ndarray.T 和np.transpose()相同

rollaxis 向后滚动指定的轴

swapaxes 互换数组的两个轴

numpy.transpose: 这个函数翻转给定数组的维度。如果可能的话它会返回一个视图

numpy.transpose(arr, axes)
arr:要转置的数组
axes:整数的列表,对应维度,通常所有维度都会翻转
np.transpose(np.arange(0,60,5).reshape(4,3)) # 行列互换且维度互换

numpy.rollaxis: 该函数向后滚动特定的轴,直到一个特定位置

numpy.rollaxis(arr, axis, start)

arr:输入数组
axis:要向后滚动的轴,其它轴的相对位置不会改变
start:默认为零,表示完整的滚动。会滚动到特定位置

np.rollaxis(np.arange(8).reshape(2,2,2),2)  # 将轴 2 滚动到轴 0(宽度到深度)
np.rollaxis(np.arange(8).reshape(2,2,2),2,1)  # 将轴 2 滚动到轴 1(宽度到高度)

修改维度

broadcast 产生模仿广播的对象

broadcast_to 将数组广播到新形状

expand_dims 扩展数组的形状

squeeze 从数组的形状中删除单维条目

x = np.array([[1], [2], [3]]) # 3x1
y = np.array([4, 5, 6])  # 1x3
b = np.broadcast(x,y)  # 3x3, 对 y 广播 x, 拥有 iterator 属性,基于自身组件的迭代器元组
for r in b.iters:
    print(r.base)

c = np.empty(b.shape)
c.flat=[u+v for u,v in b]
print(c)
print(x+y)

numpy.broadcast_to:将数组广播到新形状。 它在原始数组上返回只读视图,它通常不连续。 如果新形状不符合 NumPy 的广播规则,该函数可能会抛出ValueError。

np.broadcast_to(np.arange(4).reshape(1,4),(4,4)) # copy much row or column

numpy.expand_dims: 在指定位置插入新的轴来扩展数组形状

numpy.expand_dims(arr, axis)

arr:输入数组

axis:新轴插入的位置

x = np.array(([1,2],[3,4]))
np.expand_dims(x, axis = 0) # [[[1, 2],[3, 4]]]  # (1, 2, 2)
np.expand_dims(x, axis = 1) # [[[1, 2]],[[3, 4]]]  # (2, 1, 2)

numpy.squeeze: 函数从给定数组的形状中删除一维条目

numpy.squeeze(arr, axis)

arr:输入数组

axis:整数或整数元组,用于选择形状中单一维度条目的子集

np.squeeze(np.arange(27).reshape(3,3,3)) #无效, 此函数鸡肋,不能删除维度中数据量超过1的维度
np.squeeze(np.arange(9).reshape(1,3,3)) 

数组的连接

concatenate 沿着现存的轴连接数据序列

stack 沿着新轴连接数组序列

hstack 水平堆叠序列中的数组(列方向)

vstack 竖直堆叠序列中的数组(行方向)

numpy.concatenate:用于沿指定轴连接相同形状的两个或多个数组

numpy.concatenate((a1, a2, ...), axis)

a1, a2, ...:相同类型的数组序列

axis:沿着它连接数组的轴,默认为 0

a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
np.concatenate((a,b)) # 行堆叠
np.concatenate((a,b),axis = 1) # 列堆叠

numpy.stack:沿新轴连接数组序列(参数一致)

np.stack((a,b)) # 行堆叠
np.stack((a,b),axis = 1) # 列堆叠

numpy.hstack: numpy.stack函数的变体,通过堆叠来生成水平的单个数组

np.hstack((a,b))等价于np.stack((a,b),axis = 1) # 列堆叠

numpy.vstack:numpy.stack函数的变体,通过堆叠来生成竖直的单个数组

np.vstack((a,b))等价于np.stack((a,b)) # 行堆叠

数组分割

split 将一个数组分割为多个子数组

hsplit 将一个数组水平分割为多个子数组(按列)

vsplit 将一个数组竖直分割为多个子数组(按行)

numpy.split:沿特定的轴将数组分割为子数组

numpy.split(ary, indices_or_sections, axis)

ary:被分割的输入数组

indices_or_sections:可以是整数,表明要从输入数组创建的,等大小的子数组的数量。 如果此参数是一维数组,则其元素表明要创建新子数组的点。

axis:默认为 0

np.split(np.arange(16).reshape(4,2,2),4) # 分割成4个大小相等的子数组
np.split(np.arange(16).reshape(4,2,2),[2,3]) # 按照宽度的位置分割,# (0,1)(2)(3)

numpy.hsplit: split()函数的特例,其中轴为 1 表示水平分割

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

numpy.vsplit:split()函数的特例,其中轴为 0 表示竖直分割

np.vsplit(np.arange(16).reshape(4,4),[1])

添加/删除元素

resize 返回指定形状的新数组

append 将值添加到数组末尾

insert 沿指定轴将值插入到指定下标之前

delete 返回删掉某个轴的子数组的新数组

unique 寻找数组内的唯一元素

numpy.resize:返回指定大小的新数组。 如果新大小大于原始大小,则包含原始数组中的元素的重复副本

numpy.resize(arr, shape)

arr:要修改大小的输入数组

shape:返回数组的新形状

np.resize(np.array([[1,2,3],[4,5,6]]), (3,2)) # 内容和元数据一样
np.resize(np.array([[1,2,3],[4,5,6]]), (3,3)) # 添加重复行

numpy.append:在输入数组的末尾添加值。 附加操作不是原地的,而是分配新的数组。 此外,输入数组的维度必须匹配否则将生成ValueError。

numpy.append(arr, values, axis)

arr:输入数组

values:要向arr添加的值,比如和arr形状相同(除了要添加的轴)

axis:沿着它完成操作的轴。如果没有提供,两个参数都会被展开

np.append(np.array([[1,2,3],[4,5,6]]), [7,8,9]) # 不指定轴返回一维数组
print np.append(np.array([[1,2,3],[4,5,6]]), [[5,5,5],[7,8,9]],axis = 1)

numpy.insert:在给定索引之前,沿给定轴在输入数组中插入值。 如果值的类型转换为要插入,则它与输入数组不同。 插入没有原地的,函数会返回一个新数组。 此外,如果未提供轴,则输入数组会被展开

numpy.insert(arr, obj, values, axis)

arr:输入数组

obj:在其之前插入值的索引

values:要插入的值

axis:沿着它插入的轴,如果未提供,则输入数组会被展开

np.insert(np.array([[1,2],[3,4],[5,6]]),1,[11],axis=0) # 行插入
np.insert(np.array([[1,2],[3,4],[5,6]]),1,[11],axis=1) # 列插入

numpy.delete: 返回从输入数组中删除指定子数组的新数组。 与insert()函数的情况一样,如果未提供轴参数,则输入数组将展开

Numpy.delete(arr, obj, axis)

arr:输入数组

obj:可以被切片,整数或者整数数组,表明要从输入数组删除的子数组

axis:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开

numpy.unique: 返回输入数组中的去重元素数组。 该函数能够返回一个元组,包含去重数组和相关索引的数组, 索引的性质取决于函数调用中返回参数的类型。

numpy.unique(arr, return_index, return_inverse, return_counts)

arr:输入数组,如果不是一维数组则会展开

return_index:如果为true,返回输入数组中的元素下标

return_inverse:如果为true,返回去重数组的下标,它可以用于重构输入数组

return_counts:如果为true,返回去重数组中的元素在原数组中的出现次数

values,indices=np.unique(np.array([[1,2],[2,4],[1,6]]),return_inverse = True) # array([1, 2, 4, 6]), array([0, 1, 1, 2, 0, 3]
values[indices] # 使用下标重构原数组

位操作

bitwise_and 对数组元素执行位与操作

bitwise_or 对数组元素执行位或操作

invert 计算位非

left_shift 向左移动二进制表示的位

right_shift 向右移动二进制表示的位

bitwise_and: 通过np.bitwise_and()函数对输入数组中的整数的二进制表示的相应位执行位与运算,右对齐,相同为True

bitwise_or: 通过np.bitwise_or()函数对输入数组中的整数的二进制表示的相应位执行位或运算,右对齐,为1即为True

Invert: 此函数计算输入数组中整数的位非结果。 对于有符号整数,返回补码

left_shift: numpy.left shift()函数将数组元素的二进制表示中的位向左移动到指定位置,右侧附加相等数量的 0

right_shift: numpy.right_shift()函数将数组元素的二进制表示中的位向右移动到指定位置,左侧附加相等数量的 0

bin(31),bin(365)  # 二进制码 : '0b11111', '0b101101101'
bitwise_and(31,365) # 13
bitwise_or(31,365) # 383
np.invert(31)  #  -32  -0b100000
np.left_shift(10,2)  # 10:00001010; 40: 00001010

1.8 字符串函数

以下函数用于对dtype为numpy.string_或numpy.unicode_的数组执行向量化字符串操作,是基于 Python 内置库中的标准字符串函数。

add() 返回两个str或Unicode数组的逐个字符串连接

multiply() 返回按元素多重连接后的字符串

center() 返回给定字符串的副本,其中元素位于特定字符串的中央

capitalize() 返回给定字符串的副本,其中只有第一个字符串大写

title() 返回字符串或 Unicode 的按元素标题转换版本

lower() 返回一个数组,其元素转换为小写

upper() 返回一个数组,其元素转换为大写

split() 返回字符串中的单词列表,并使用分隔符来分割, 默认是空格用作分隔符

splitlines() 返回元素中的行列表,以换行符分割

strip() 返回数组副本,其中元素移除了开头或者结尾处的特定字符

join() 返回一个字符串,它是序列中字符串的连接

replace() 返回字符串的副本,其中所有子字符串的出现位置都被新字符串取代

decode() 按元素调用str.decode

encode() 按元素调用str.encode

np.char.add(['hello', 'hi'],[' abc', ' xyz']) # ['hello abc' 'hi xyz']
np.char.multiply('Hello ',3) # Hello Hello Hello
np.char.center('hello', 20,fillchar = '*') # *******hello********
np.char.capitalize('hello world') # Hello world
np.char.title('hello how are you?') # Hello How Are You?
np.char.split ('TutorialsPoint,Hyderabad,Telangana', sep = ',') # ['TutorialsPoint', 'Hyderabad', 'Telangana']
np.char.strip(['arora','admin','java'],'a') # ['ror' 'dmin' 'jav']
np.char.join(':','dmy'); np.char.join([':','-'],['dmy','ymd']) #  d:m:y # ['d:m:y' 'y-m-d']
np.char.replace ('He is a good boy', 'is', 'was')

1.9 算数函数

NumPy 提供标准的三角函数,算术运算的函数,复数处理函数等。

三角函数:NumPy 拥有标准的三角函数,它为弧度制单位的给定角度返回三角函数比值

a = np.array([0,30,45,60,90])  

np.sin(a*np.pi/180)  
np.cos(a*np.pi/180)  
np.tan(a*np.pi/180)
np.arcsin(a*np.pi/180) # 弧度为单位
np.degrees(np.arcsin(a*np.pi/180)) # 角度制单位
np.arccos(a*np.pi/180)  
Np.arctan(a*np.pi/180)

舍入函数

numpy.around(): 返回四舍五入到所需精度的值。 该函数接受以下参数:

numpy.around(a,decimals)

a 输入数组

decimals 要舍入的小数位数。 默认值为0。 如果为负,整数将四舍五入到小数点左侧的位置

np.around(np.array([1.0,5.55,  123,  0.567,  25.532]), decimals = -1) # 四舍五入到十位

numpy.floor():返回不大于输入参数的最大整数。 即标量x 的下限是最大的整数i ,使得i <= x。 注意在Python中,向下取整总是从 0 舍入

numpy.ceil():ceil()函数返回输入值的上限,即,标量x的上限是最小的整数i ,使得i> = x

执行算术运算(如add(),subtract(),multiply()和divide())的输入数组必须具有相同的形状或符合数组广播规则

np.add(a,b)
np.subtract(a,b)
np.multiply(a,b)
np.divide(a,b)

numpy.reciprocal(): 返回参数逐元素的倒数, 由于 Python 处理整数除法的方式,对于绝对值大于 1 的整数元素,结果始终为 0,整数带浮点形式则不为0,对于整数 0,则发出溢出警告。

np.reciprocal(np.array([0.25,  1.33,  1,  0,  100]))

numpy.power():将第一个输入数组中的元素作为底数,计算它与第二个输入数组中相应元素的幂

np.power(np.array([0.25,  1.33,  1,  0]),2)

numpy.mod():返回输入数组中相应元素的除法余数,函数numpy.remainder()也产生相同的结果

np.mod(np.array([10,20,30]),np.array([3,5,7]))

对含有复数的数组执行操作。

numpy.real() 返回复数类型参数的实部。

numpy.imag() 返回复数类型参数的虚部。

numpy.conj() 返回通过改变虚部的符号而获得的共轭复数。

numpy.angle() 返回复数参数的角度。 函数的参数是degree。 如果为true,返回的角度以角度制来表示,否则为以弧度制来表示。

1.10 统计函数

numpy.amin() 和 numpy.amax():从给定数组中的元素沿指定轴返回最小值和最大值

np.amax(np.array([[3,7,5],[8,4,3],[2,4,9]]),1) #[7, 8, 9] 

numpy.ptp():返回沿轴的值的范围(最大值 - 最小值),不指定轴返回一个最大的值

np.ptp(a, axis = 1)

numpy.median():中值定义为将数据样本的上半部分与下半部分分开的值。 numpy.median()函数的用法和ptp一致

numpy.mean():算术平均值是沿轴的元素的总和除以元素的数量。 numpy.mean()函数返回数组中元素的算术平均值,用法和ptp一致

numpy.average():加权平均值是由每个分量乘以反映其重要性的因子得到的平均值。 根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。 该函数可以接受一个轴参数。如果没有指定轴,则数组会被展开。

np.average([1,2,3, 4],weights = [4,3,2,1], returned = True) #  2, 10

numpy.percentile():百分位数是统计中使用的度量,表示小于这个值的观察值占某个百分比

numpy.percentile(a, q, axis)

a 输入数组

q 要计算的百分位数,在 0 ~ 100 之间

axis 沿着它计算百分位数的轴

标准差:与均值的偏差的平方的平均值的平方根:

std = sqrt(mean((x - x.mean())**2))
np.std([1,2,3,4])

方差:与均值的偏差的平方的平均值:

mean((x - x.mean())** 2)
np.var([1,2,3,4])

1.11 排序、搜索和计数函数

NumPy中提供了各种排序相关功能。 这些排序函数实现不同的排序算法,每个排序算法的特征在于执行速度,最坏情况性能,所需的工作空间和算法的稳定性。 关于时间复杂度和空间复杂度的内容在小知识+时间复杂度+空间复杂度解释-优快云博客下,下表显示了三种排序算法的比较

种类

速度

最坏情况

工作空间

稳定性

'quicksort'(快速排序)

1

O(n^2)

0

'mergesort'(归并排序)

2

O(n*log(n))

~n/2

'heapsort'(堆排序)

3

O(n*log(n))

0

numpy.sort():sort()函数返回输入数组的排序副本:

numpy.sort(a, axis, kind, order)

a 要排序的数组

axis 沿着它排序数组的轴,如果没有数组会被展开,沿着最后的轴排序

kind 默认为'quicksort'(快速排序)

order 如果数组包含字段,则是要排序的字段

dt = np.dtype([('name', 'S10'),('age', int)])
a = np.array([("raju",21),("anil",25),("ravi", 17), ("amar",27)], dtype = dt)
np.sort(a, order = 'name')

numpy.argsort(): 对输入数组沿给定轴执行间接排序,并使用指定排序类型返回数据的索引数组, 这个索引数组用于构造排序后的数组

np.argsort(np.array([3, 1, 2]))

numpy.lexsort(): 使用键序列执行间接排序, 键可以看作是电子表格中的一列, 返回一个索引数组,使用它可以获得排序数据,注意最后一个键恰好是 sort 的主键

nm =  ('raju','anil','ravi','amar')
dv =  ('f.y.',  's.y.',  's.y.',  'f.y.')
ind = np.lexsort((dv,nm)) # 对nm排序,dv作为索引附属行
[nm[i]  +  ", "  + dv[i]  for i in ind] # ['amar, f.y.', 'anil, s.y.', 'raju, f.y.', 'ravi, s.y.']

numpy.argmax() 和 numpy.argmin():分别沿给定轴返回最大和最小元素的索引

np.argmax(a, axis = 0) # 不指定轴会展开为一维数组

numpy.nonzero():返回输入数组中非零元素的索引

numpy.where():返回输入数组中满足给定条件的元素的索引

np.where(np.arange(9.).reshape(3, 3) > 3)  # (array([1, 1, 2, 2, 2]), array([1, 2, 0, 1, 2]))

numpy.extract(): 返回满足任何条件的元素

np.extract(np.mod(np.arange(9.).reshape(3, 3),2) == 0, np.arange(9.).reshape(3, 3))

1.12 副本和视图

在执行函数时,其中一些返回输入数组的副本,而另一些返回视图。 当内容物理存储在另一个位置时,称为副本。 另一方面,如果提供了相同内存内容的不同视图,称为视图。

无复制:简单的赋值不会创建数组对象的副本。 相反,它使用原始数组的相同id()来访问它。 id()返回 Python 对象的通用标识符,类似于 C 中的指针。

此外,一个数组的任何变化都反映在另一个数组上。 例如,一个数组的形状改变也会改变另一个数组的形状。

a=np.arange(5)
print(id(a)) # 虚拟地址2833585541744
b=a
print(id(b)) # 2833585541744
b[1]=4; a  # array([0, 4, 2, 3, 4])

视图或浅复制: ndarray.view()方法,它是一个新的数组对象,并可查看原始数组的相同数据。 与前一种情况不同,新数组的维数更改不会更改原始数据的维数, 数组的切片也会创建视图

b = a.view()

深复制:ndarray.copy()函数创建一个深层副本。 它是数组及其数据的完整副本,不与原始数组共享

b = a.copy()
b is a # False

1.13 矩阵库

NumPy 包包含一个 Matrix库numpy.matlib。此模块的函数返回矩阵而不是返回ndarray对象。

import numpy.matlib

matlib.empty():返回一个新的矩阵,而不初始化元素

numpy.matlib.empty(shape, dtype, order)

shape 定义新矩阵形状的整数或整数元组

Dtype 可选,输出的数据类型

order C 或者 F

np.matlib.empty((2,2))  # 填充为随机数据

numpy.matlib.zeros():返回以零填充的矩阵
np.matlib.zeros((2,2))

numpy.matlib.ones():返回以1填充的矩阵

numpy.matlib.eye():返回对角线元素为1的矩阵

numpy.matlib.eye(n, M,k, dtype)

n 返回矩阵的行数

M 返回矩阵的列数,默认为n

k 对角线的索引

dtype 输出的数据类型

np.matlib.eye(n =3, M = 4, k = 0, dtype = float)

numpy.matlib.identity():返回给定大小的单位阵

np.matlib.identity(5, dtype = float)

numpy.matlib.rand():返回给定大小的填充随机值的矩阵

np.matlib.rand(3,3)  # 矩阵总是二维的,而ndarray是一个 n 维数组。 两个对象可互换
np.matrix('1,2;3,4')
np.asarray(np.matrix('1,2;3,4'))
np.asmatrix (np.asarray(np.matrix('1,2;3,4')))

1.14 线性代数

包含numpy.linalg模块,提供线性代数所需的所有功能

dot 两个数组的点积,正常矩阵乘积运算,横x列,返回矩阵

vdot 两个向量的点积,结果值

inner 两个数组的内积,数组横向运算,数组x数组,返回矩阵

matmul 两个数组的矩阵积,等同于dot

determinant 数组的行列式

numpy.linalg.solve() 求解线性矩阵方程,给出矩阵形式的线性方程的解

numpy.linalg.inv() 寻找矩阵的乘法逆矩阵

a = np.array([[1,2],[3,4]])
b = np.array([[11,12],[13,14]])
c= np.array([[11],[13]])

np.dot(a,b)   # [[1*11+2*13, 1*12+2*14],[3*11+4*13, 3*12+4*14]]
np.vdot(a,b)  # 1*11 + 2*12 + 3*13 + 4*14 = 130
np.inner(np.array([1,2,3]),np.array([0,1,0])) # 2
np.inner(a,b) # [[35, 41],[81, 95]] # 1*11+2*12, 1*13+2*14  3*11+4*12, 3*13+4*14
np.matmul(a,b)
np.linalg.det(np.array([[6,1,1], [4, -2, 5], [2,8,7]]))  # -306  6*(-2*7 - 5*8) - 1*(4*7 - 5*2) + 1*(4*8 - -2*2)
np.linalg.solve(a,c) # [[-9.],[10.]]
np.dot(np.linalg.inv(np.array([[1,2],[3,4]])),np.array([[1,2],[3,4]])) # 结果为单位阵

1.15 绘图

Matplotlib 是 Python 的绘图库。 它可与 NumPy 一起使用,提供了一种有效的 MatLab 开源替代方案, 它也可以和图形工具包一起使用,如 PyQt 和 wxPython。

from matplotlib import pyplot as plt  
x = np.arange(1,11)
y =  2  * x +  5
plt.title("Matplotlib demo")
plt.xlabel("x axis caption")
plt.ylabel("y axis caption")
plt.plot(x,y);plt.plot(x,y,"ob")
plt.show()

作为线性图的替代,可以通过向plot()函数添加格式字符串来显示离散值。 可以使用以下格式化字符:

字符

描述

'-'

实线样式

'--'

短横线样式

'-.'

点划线样式

':'

虚线样式

'.'

点标记

','

像素标记

'o'

圆标记

'v'

倒三角标记

'^'

正三角标记

'<'

左三角标记

'>'

右三角标记

'1'

下箭头标记

'2'

上箭头标记

'3'

左箭头标记

'4'

右箭头标记

's'

正方形标记

'p'

五边形标记

'*'

星形标记

'h'

六边形标记 1

'H'

六边形标记 2

'+'

加号标记

'x'

X 标记

'D'

菱形标记

'd'

窄菱形标记

`' or '`

竖直线标记

'_'

水平线标记

字符

颜色

'b'

蓝色

'g'

绿色

'r'

红色

'c'

青色

'm'

品红色

'y'

黄色

'k'

黑色

'w'

白色

subplot(): 允许在同一图中绘制不同的东西  

x = np.arange(0,  3  * np.pi,  0.1)
y_sin = np.sin(x)
y_cos = np.cos(x)  
# 建立 subplot 网格,高为 2,宽为 1  
plt.subplot(2,  1,  1)  # 激活第一个 subplot
# 绘制第一个图像
plt.plot(x, y_sin)
plt.title('Sine')  
# 将第二个 subplot 激活,并绘制第二个图像
plt.subplot(2,  1,  2)
plt.plot(x, y_cos)
plt.title('Cosine')  
plt.show()

1.16 IO

ndarray对象可以保存到磁盘文件并从磁盘文件加载。 可用的 IO 功能有:

load()和save()函数处理 numPy 二进制文件(带npy扩展名)

loadtxt()和savetxt()函数处理正常的文本文件

NumPy 为ndarray对象引入了一个简单的文件格式。 这个npy文件在磁盘文件中,存储重建ndarray所需的数据、图形、dtype和其他信息,以便正确获取数组,即使该文件在具有不同架构的另一台机器上。

a = np.array([1,2,3,4,5])
np.savetxt('out.txt',a)
b = np.loadtxt('out.txt')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值