1.python基础
1.1 数据类型
1.1.1 number(数字)
(1) 整型(int):整型就是整数,包括正整数、负整数、零,不带小数点。
int(x) :将x转换为一个整数
(2) 浮点型(float)):浮点型由整数部分与小数点组成,必须包含小数点。
float(x):将x转换为一个浮点数
(3) 布尔型(bool) :布尔型是一种表示逻辑值的简单类型,只有俩个值,一个为 True(真,1),另一个为False(假,0)。
1.1.2 string(字符串)
str(x/s):将x/s转换为字符串
eval(str):用于字符串,去除字符串的引号,获取引号里面的内容
1.1.3 list(列表)
list(s):将序列s转换为一个列表
1.1.4 tuple(元组)
tuple(s):将序列s转换为一个元组
1.1.5 dictionary(字典)
dict(d):创建一个字典,d必须是一个(key,value)元组序列
1.1.6 set(集合)
set(s): 将序列s转换为一个集合
1.1.7
type()函数:查询某一变量的数据类型。
例:
>>>a = 123
>>>print(type(a))
<class 'int'>
1.2 运算符
(1)**(幂运算,返回乘方结果 )
(2)算术运算符: * /(两个数相除,结果为浮点数(小数) ) %(取模,返回两个数相除的余数) //(两个数相除,结果为向下取整数 ) + -
(3)比较运算符:<= < > >= ==(比较两个对象是否相等 ) !=(比较两个对象是否不相等 )
(4)赋值运算符:= %= /= //= -= += *= **=
(5)逻辑运算符:and(“与”运算符,一假为假,全真为真 )
or(“或”运算符,一真为真,全假为假 )
not(“非”运算符,为真则假,为假则真 )
算术运算符 > 比较运算符 > 赋值运算符
1.3 python语句
1.3.1 判断语句
1.if 判断条件 :
语句
2.if 判断条件:
语句
else:
语句
3.if 判断条件:
语句
elif 判断条件:
语句
……
else:
语句
例:
print("请输入学生的成绩:")
a=int(input())
if a>100:
print("error!")
elif a>=90:
print("A")
elif a>=80:
print("B")
elif a>=70:
print("C")
elif a>=60:
print("D")
elif a>=0:
print("E")
else:
print("error!")
1.3.2 循环语句
(1) while语句:
while 表达式:
循环体
(2) for循环:
for 循环变量 in 遍历对象(序列):
循环体
for 循环,从形式上可以分为俩种: 1.遍历对象。
2.使用range函数控制循环次数 range函数: range(起始值,终 止值,步长) 步长 :每次循环序列增长值,默认值为1,为1 时可以省略。
例:求出 1∼100中的质数
#用while语句
a=2
b=2
while a<=100:
c=b
while c<a:
if (a%c)==0:
break
c=c+1
else:
print(a)
a=a+1
#用for循环
for i in range(1, 101):
if i>1:
for j in range(2,i):
if (i%j)==0:
break
else:
print(i)
例:用循环语句画图
a,b,c,d,e = " ","/","\\","*","&"
for i in range(1,4):
print(a*(10-i),end="")
print(f"{d} "*i)
print(f"{d} "*10)
for i in range(1,3):
print(a*i,end="")
print(f"{d} "*(4-i),end="")
print(f"{b} ",end="")
print(f"{d} " * i, end="")
print(f"{c} ",end="")
print(f"{d} "*(4-i))
print(a*3,end="")
print(f"{d} "*3,end="")
print(f"{e} ",end="")
print(f"{d} "*3)
for i in range(3,1,-1):
print(a*i,end="")
print(f"{d} "*(4-i),end="")
print(f"{c} ",end="")
print(f"{d} " * i, end="")
print(f"{b} ",end="")
print(f"{d} "*(4-i))
print(f"{d} "*10)
for i in range(3,0,-1):
print(a*(10-i),end="")
print(f"{d} "*i)
运行结果
1.4 各数据类型的简单功能介绍
1.4.1 字符串
(1)转义字符:\' 输出为:'
\"
输出为:"
\' 输出为:制表符
\' 输出为:换行符
\' 输出为:倒斜杠
(2)
字符串的索引、切片与逆序
注意:索引从0开始
1.获取单个字符时可以使用变量名[索引]
例:
>>>a = "Hello , world!"
>>>print(a[9])
r
2.获取字符串时可以使用变量名变量名[起始索引:结束索引+1:间隔个数]
起始索引默认为0,结束索引默认为最后,间隔个数默认为1,若为默认时可以省略。
例:
>>>a = "Hello , world!"
>>>print(a[0:5])
Hello
>>>print(a[0:5:2])
Hlo
3.逆序 只需要使用变量名[结束索引:开始索引-1:-1]
例:
>>>a = "Hello , world!"
>>>print(a[4:-1:-1])
olleH
>>>print(a[4:-1:-2])
olH
(3) 使用ord()和chr()函数的字符的数值
1.ord(字符)获取一个单字符字符串的代码点。
2.chr(代码点)获取一个整数代码点的单字符字符串。
(4)字符串相关函数的用法
upper() | 字符串.upper() | 将字符串里的字符全部大写 |
lower() | 字符串.lower() | 将字符串里的字符全部小写 |
isupper() | 字符串.isupper() | 字符串中字符是否都是由大写字母组成 |
islower() | 字符串.islower() | 字符串中字符是否都是由小写字母组成 |
isdigit() | 字符串.isdigit() | 字符串中是否都是由数字组成 |
isnumeric() | 字符串.isnumeric() | 字符串中字符是否都是由数字字符组成 |
isalpha() | 字符串.isalpha() | 字符串中是否都是由字母组成,并且非空 |
isalnum() | 字符串.isalnum() | 字符串中是否都是由字母和数字组成,并且非空 |
isdecimal() | 字符串.isdecimal() | 字符串中是否都是由数字字符组成,并且非空 |
isspace() | 字符串.isspace() | 字符串中是否都是由空格、制表符和换行符组成,并且非空 |
istitle() | 字符串.istitle() | 字符串中是否以大写字母开头、后面都是小写字母的单词、数字或空格 |
find() | 字符串.find(字符,起始位置,结束位置) | 查找指定字符在字符串中的位置(索引)(找不到则返回-1) |
index() | 字符串.index(字符,起始位置,结束位置) | 查找指定字符在字符串中的位置(索引)(找不到会报错) |
count() | 字符串.count(字符) | 统计指定字符出现的次数 |
replace() | 字符串.replace(字符,新字符,替换次数) | 用于字符串的修改 |
split() | 字符串.split(分隔符,分割次数) | 拆分字符串。通过指定分隔符对字符串进行切片,并返回分割后的字符串列表。 |
join() | 分隔符.join(序列) | 返回一个用分隔符连接序列各个元素后的字符串(注:分隔符可以为空) |
title() | 字符串.title() | 字符串内的所有单词的首字母大写 |
capittalize() | 字符串.capittalize() | 字符串第一个字母大写 |
startswith() | 字符串1.startswith(字符串2) | 字符串2是否以字符串开始 |
endswith() | 字符串1.endswith(字符串2) | 字符串2是否以字符串结束 |
partition() | 字符串.partition(字符串中片段) | 以字符串中片段为分隔符分隔字符串 |
rjust() | 字符串.rjust(数字,'填充字符') | 右对齐字符串,左边填充上‘填充字符’,总字符长度为‘数字’ |
ljust() | 字符串.ljust(数字,'填充字符') | 左对齐字符串,右边填充上‘填充字符’,总字符长度为‘数字’ |
center() | 字符串.center(数字,'填充字符') | 字符串居中,两边填充上‘填充字符’,总字符长度为‘数字’ |
strip() | 字符串.strip(空格、制表符、换行符和字符串参数) | 删除字符串两边所选字符 |
rstrip() | 字符串.rstrip(空格、制表符、换行符和字符串参数) | 删除字符串右边所选字符 |
lstrip() | 字符串.lstrip(空格、制表符、换行符和字符串参数) | 删除字符串左边所选字符 |
注意:作用中有关是否的方法中,若符合则返回True,不符合则返回False。
例1:
#upper()函数
a="aBcD"
print(a.upper())
运行结果
例2:
#center()函数
a="aBcD"
print(a.center(8,'!'))
运行结果
1.4.2 列表
(1)列表相关函数的用法
列表操作 | 示范 |
---|---|
创建一个空列表 | a = [ ] |
访问列表中的某个元素 | a[索引] |
访问列表的最后一个元素 | a[-1] |
列表的切片和逆序与字符串格式一致,也是a[ : : ]和a[ : :-1],同时别忘记逆序时开始索引与结束索引的位置。
(2)列表推导式
1.[表达式 for 变量 in 列表]
2.[表达式 for 变量 in 列表 if 条件]
例:
a= [x for x in range(1,21)]
print(a)
b = [x for x in range(1,21) if x%2 == 0]
print(b)
运行结果
(3)len()函数
len()函数可以取得列表的长度。
(4) sum()函数
sum()函数可以将列表中所有数相加。
(5)列表相关函数的用法
操作 | 方法 | 描述 |
---|---|---|
增 | 列表.append(元素) | 在列表末尾添加一个元素 |
增 | 列表.extend(序列) | 在列表末尾追加一个序列 |
增 | 列表.insert(索引,元素) | 在列表对应的索引插入元素 |
删 | del 列表[索引] | 删除列表中对应索引的元素 |
删 | 列表.pop(索引) | 删除列表中对应索引的元素,并返回删除的元素,默认最后一个 |
删 | 列表.remove(元素) | 删除列表中对应元素的第一个匹配项 |
删 | 列表.clear() | 清空列表 |
改 | 列表[索引]=新元素 | 将列表对应索引的元素,修改为新元素 |
查 | 列表.index(元素) | 返回元素对应的索引 |
例1:
#append()函数
a=[1,2]
print(a)
a.append(3)
print(a)
运行结果
例2:
#remove()函数
a=[1,1,1,2,2,2]
print(a)
a.remove(1)
print(a)
运行结果
1.4.3 元组
(1)
列表操作 | 示范 |
---|---|
创建一个空元组 | a =() |
创建包含一个元素的元组 | b =(元素,) |
创建元组 | c =(元素1,元素2,……) |
注意:包含一个元素的元组必须有逗号 。
(2)元组索引
元组序列[开始索引,结束索引]
注意:元组是不可以修改的,包括不能删除其中的元素。元组内的直接数据如果修改则立即报错。但是,如果元组里面有列表,修改列表里面的数据不会报错。
(3)元组相关函数的用法
操作 | 作用 |
---|---|
index() | 从元组中找出某个对象第一个匹配项的下标位置。 |
count() | 统计某个元素在元组中出现的次数 |
len() | 计数元组元素的个数,并返回值 |
max() | 返回元组中元素的最大值 |
min() | 返回元组中元素的最小值 |
(4)
注意:元组除了两个方面,元组的数据类型几乎和列表数据类型一样: 1.元组输入时用圆括号(),不是方括号[ ] 2.元组的值无法修改、添加或删除。
1.4.4 字典
(1)
字典操作 | 代码示范 |
---|---|
创建空字典 | dict1 = {}/dict2 = dict() |
创建字典 | dict3 = { 键1 :值1 ,键2: 值2,……} |
(2)字典相关函数的用法
操作 | 代码示范 | 描述 |
---|---|---|
访问值 | 字典序列[键] | 访问已知键所对应的值 |
修改值 | 字典序列[键]=新值 | 修改已知键的值 |
添加键值对 | 字典序列[新键]=新值 | 添加新的键值对 |
删 | del 字典序列[键] | 删除字典中对应的键的键值对 |
删 | del 字典序列 | 删除字典 |
删 | 字典序列.clear() | 清空字典 |
查 | 字典序列.items() | 查找字典的所有的键值对 |
查 | 字典序列.keys() | 查找字典的所有的key(键) |
查 | 字典序列.values() | 查找字典的所有的value(值) |
例1:
a={'a':1,'b':2,'c':3}
a['b']=4
print(a)
运行结果
例2:
#keys()
a={'a':1,'b':2,'c':3}
print(a.keys())
运行结果
(3)使用enumerate()函数枚举键值对
enumerate(序列, start=0)
其中start = 0为默认开始值为0
1.4.5 集合
(1)
可以使用大括号 { } 或者 set() 函数创建集合,但创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
集合特点: 1.集合是一个无序的不重复元素序列
2.集合中的元素是唯一的
3.集合可以用来去重
(2)集合相关函数的用法
操作 | 代码示范 | 描述 |
---|---|---|
增 | 集合序列.add(数据) | 添加一个数据 |
增 | 集合序列.update(序列数据) | 添加序列 |
删 | 集合序列.remove(数据) | 删除集合中指定的数据,如果数据不存在就报错 |
删 | 集合序列.pop() | 随机删除集合中的某个数据 |
删 | 集合序列.discard(数据) | 删除集合中指定的数据,如果数据不存在不做任何操作 |
例:
#add()函数
a={1,2,3,5}
a.add(6)
print(a)
运行结果
1.5 函数
1.5.1 定义与调用
(1)定义
def 函数名 ( ):
函数语句
(2)调用
函数名( )
注意:1.函数先定义后调用,如果先调用会报错。
2.函数没有被调用时,函数里面的执行语句不会被执行。
1.5.2 返回值
语法: def 函数名 ( ):
函数语句
return 返回值
注意:函数中可以同时包含多个 return 语句,但只会执行了一个return,return的功能是返回值并退出当前函数,return语句后面的语句都不执行。
1.5.3 形参和实参
(1)定义
def 函数名(形参1,形参2):
函数体
(2)调用
函数名(实参1,实参2)
注意:
1.传递的实参与形参个数必须保持一致,否则将发生参数不匹配错误。
2.编写函数时可给每个形参指定默认值,调用函数时给形参提供实参的,将使用指定的实参,若没有则使用默认值。
3.调用函数时,会将实参1传递给形参1,实参2传递给形参2,……如果参数位置不对,可能达不到预期效果,如果参数过多时可以在调用函数时直接指明形参1=实参1。
1.5.4 参数
参数分为三种:
1.位置参数(必备参数)。
2.默认参数(缺省参数)。
3.不定长参数(*args,kwargs) *args常以元组的形式输出,收集任意数量的位置实参 kwargs常以字典的形式输出,收集任意数量的关键字实参。
(1)位置参数
def 函数名(形参1,形参2):
函数体
函数名(实参1,实参2)
(2)默认参数
def 函数名(形参1=数据,…):
函数体
(3)不定长参数
1.不定长参数(*args)
def 函数名(*args):
函数体
函数名(实参1,实参2,实参3,……)
2.不定长参数(kwargs)
def 函数名(kwargs):
函数体
(4)参数定义顺序
位置参数、默认参数、不定长参数(*args,kwargs)
1.5.5 作用域
(1)局部作用域
定义在函数内部的变量拥有一个局部作用域,表示只能在声明它的函数内部访问。在函数体内部,临时保存数据,即当函数调用完成后,则销毁局部变量。
(2)全局作用域
定义在函数外部的变量拥有全局作用域,表示可以在整个程序范围内访问(函数内、外部都能生效)。
(3)修改作用域
global | nonlocal |
---|---|
声明变量的作用域为全局作用域 | 数中的下划线关键字用来在函数中使用外层(非全局)变量 |
例1:
>>>def great():
>>> global a
>>> a = 40
>>> print(f'函数内:{a}')
>>>a = 20
>>>great()
>>>print(f'函数外:{a}')
函数内:40
函数外:40
例2:
>>>def outer():
>>> num = 10
>>> print(f'outer1:{num}')
>>> def inner():
>>> nonlocal num
>>> num = 20
>>> print(f'inner: {num}')
>>> inner()
>>> print(f'outer2:{num}')
>>>outer()
outer1:10
inner: 20
outer2:20
2.机器学习
常用的工具有如下几
工具 | 作用 |
---|---|
matplotlib | 画图工具 |
numpy | 表格处理工具 |
padas | 信息处理工具 |
2.1 Matplotlib工具
2.1.1 创建画布
注意:后面的matplotlib.pyplot均代指画布名称。
plt.figure(figsize = (a,b),dpi = )
figsize:指图像的长(a)宽(b) dpi:图像清晰度(越大越清晰)
2.1.2 绘制图像
plt.plot(x,y.color = '',linestyle = '',marker = '',linestyle='',label='')
x:横轴数据
y:纵轴数据
color:图像颜色,可以直接输入英文名称,或者是RGB颜色值(下面附有图)
linewidth:线条宽度
marker: 标记风格
linestyle: 线条样式
label:图例
2.1.3 常用颜色
颜色 | 说明 | 颜色 | 说明 |
---|---|---|---|
r | 红色 | g | 绿色 |
b | 蓝色 | w | 白色 |
c | 青色 | m | 洋红 |
y | 黄色 | k | 黑色 |
2.1.4 标记风格
标记字符 | 说明 | 标记字符 | 说明 |
---|---|---|---|
'.' | 点标记 | ',' | 像素标记(极小点) |
'v' | 倒三角标记 | ’^‘ | 上三角标记 |
'>' | 右三角标记 | '<' | 左三角标记 |
'1' | 下花三角标记 | '2' | 上花三角标记 |
'3' | 左花三角标记 | '4' | 右花三角标记 |
'o' | 实心圈标记 | 's' | 实心方形标记 |
'p' | 实心五角标记 | '*' | 星形标记 |
'h' | 竖六边形标记 | 'H' | 横六边形标记 |
'+' | 十字标记 | 'x' | x标记 |
'D' | 菱形标记 | 'd' | 瘦菱形标记 |
2.1.5 线条样式
样式 | 说明 |
---|---|
’-‘ | 实线 |
’--‘ | 虚线 |
’-.‘ | 点划线 |
':' | 点虚线 |
2.1.6 设置图例位置
plt.legend(loc=)
loc:图例所在位置
loc位置表
位置 | 描述 | 对应数字 |
---|---|---|
best | 最佳位置 | 0 |
upper right | 右上方 | 1 |
upper left | 左上方 | 2 |
lower left | 左下方 | 3 |
lower right | 右下方 | 4 |
right | 右边 | 5 |
center left | 中间左边 | 6 |
center right | 中间右边 | 7 |
lower center | 下方中间 | 8 |
upper center | 上方中间 | 9 |
center | 正中心 | 10 |
2.1.7 图像保存
plt.savefig(path_or_buffer)
path_or_buffer:文件地址
注意:图像保存需要放在显示图像的前面,因为plt.show()会释放figure资源,如果在显示图像之后保存图片将只能保存空图片。
2.1.8 显示图像
plt.show()
2.1.9 基本统计图
(1) 折线图
例:
import matplotlib.pyplot as plt
x = [4, 8, 12, 16, 20]
y = [1, 5, 2, 3, 1]
plt.plot(x, y)
plt.show()
(2) 散点图
plt.scatter(x,y)
例:
import matplotlib.pyplot as plt
a = [1, 2, 3, 4, 5]
b = [6, 7, 8, 9, 10]
plt.scatter(a, b, linewidths=15,c='red',edgecolors=['black', 'green','cyan','lightgreen'])
plt.show()
(3 )柱状图
plt.bar(x,width=,height=,label=,alpha=,align=,color=)
x: 柱状图中的横坐标点list height: 柱状图对应每个横坐标的高度值
width: 柱状图的宽度,默认值为0.8
label: 每个数据样本对应的label,后面调用legend()函数可以显示图例
alpha: 透明度
align:每个柱状图的对齐方法
color:选择柱状图的颜色
例:
import matplotlib.pyplot as plt
import random
x_data = [f"20{i}年" for i in range(16, 21)]
y_data = [random.randint(100, 300) for i in range(6)]
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
for i in range(len(x_data)):
plt.bar(x_data[i], y_data[i])
plt.title("销量分析")
plt.xlabel("年份")
plt.ylabel("销量")
plt.show()
(4)
(4) 直方图
plt.hist(x,bins=None)
x:需要传递的数据 bins:组距
例:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
random_data = np.random.normal(170, 10, 250)
dataframe = pd.DataFrame(random_data)
dataframe.hist()
plt.show()
(5) 饼图
plt.pie(x,explode=None,labels=None,autopct=None,pctdistance=0.6,shadow=False,
labeldistance=1.1,startangle=None,radius=None,counterclock=True,wedgeprops=None,
textprops=None,center=(0,0),frame=False,rotatelabels=False,*,data=None)
x:表示扇形或锲形的数据
explode:表示扇形或锲形离开圆心的距离
labels:表示扇形或锲形对应的标签文本
autopct:表示控制扇形或锲形的数值显示的字符串,可通过格式字符串指定小数点后的位数. pctdistance:表示扇形或锲形对应的数值标签距离圆心的比例,默认为0.6
shadow:表示是否显示阴影
labeldistance:表示标签文本的绘制位置(相对于半径的比例),默认为1.1.
startangle:表示起始绘制角度,默认从x轴的正方向逆时针绘制 radius:表示扇形或锲形的半径. wedgeprops:表示控制扇形或锲形属性的字典.例如:通过wedgeprops={’‘width’:0.7}将锲形的宽度设为0.7.
textprops:表示控制图表中文本属性的字典
center:表示图表中心点位置,默认为(0,0)
frame:表示是否显示图框
例:
import matplotlib.pyplot as plt
x = [1, 2, 3, 4]
plt.pie(x)
plt.show()
2.2 Numpy工具
2.2.1 导入库
import numpy as np
2.2.2 创建ndarray
注意:后面的ndarray均代指对象名称
data = np.array()
2.2.3 基本方法
名称 | 作用 |
---|---|
data.shape | 查看数组的维度(以元组的形式输出) |
data.ndim | 查看数组维数 |
data.size | 查看数组中的元素数量 |
data.itemsize | 查看一个数组元素的长度 |
data.dtype | 查看数组元素的类型 |
2.2.4 创建数组时指定类型
>>>data = np.array([[1,2,3],[4,5,6]],dtype=np.float32)
>array([[1., 2., 3.],
[4., 5., 6.]], dtype=float32)
名称 | 描述 | 简写 |
---|---|---|
np.bool | 用一个字节存储的布尔类型(Ture或False) | 'b' |
np.int8 | 一个字节大小,-128至127 | 'i' |
np.int16 | 整数,-32768至32767 | 'i2' |
np.int32 | 整数,-2^31^至2^31^-1 | 'i4' |
np.int64 | 整数,-2^63^至2^63^-1 | 'i8' |
np.uint8 | 无符号整数,0至255 | 'u' |
np.uint16 | 无符号整数,0至65535 | 'u2' |
np.uint32 | 无符号整数,0至2^32^-1 | 'u4' |
np.uint64 | 无符号整数,0至2^64^-1 | 'u8' |
np.float16 | 半精度浮点数,16位,正负号1位,指数5倍,精度10位 | 'f2' |
np.float32 | 半精度浮点数,32位,正负号1位,指数8倍,精度23位 | 'f4' |
np.float64 | 半精度浮点数,64位,正负号1位,指数11倍,精度52位 | 'f8' |
np.complex64 | 复数,分别用两个32位浮点数表示实部和虚部 | 'c8' |
np.complex128 | 复数,分别用两个64位浮点数表示实部和虚部 | 'c16' |
np.object_ | python对象 | 'o' |
np.string_ | 字符串 | 's' |
np.unicode_ | unicode类型 | 'U' |
注意: 1.np.object,np.string,np.unicode这三种类型后面加上""
2.np.unicode_简写类型为大写的'U',np.uint8简写类型位小写的'u'
2.2.5 生成只含0和1的数组
one = np.ones([index, columns]) #生成index行,columns列且所有元素都为1的数组
zero = np.zeros([index, columns]) #生成index行,columns列且所有元素都为0的数组
ones = np.ones_like(ndarray) #生成一个行数和列数都与ndarry相同的且所有元素均为1的数组
zeros = np.zeros_like(ndarray) #生成一个行数和列数都与ndarry相同的且所有元素均为0的数组
2.2.6 从现有数组中生成
data1 = np.array(data)
data2 = np.asarray(data)
2.2.7 np.array和np.asarray的区别
例:
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
print(a)
a1 = np.array(a)
a2 = np.asarray(a)
a[0][0] = 100
print(a1)
print(a2)
运行结果
类似于深拷贝与浅拷贝,可以看到数组a1使用array进行复制,将a的原始数据拷贝过来,对于数组a中的元素改变,对数组a1的元素没有影响,数组a2使用asarray进行复制,对于数组a中的元素改变,数组a2的元素也跟着数组a中的元素改变而改变。
2.2.8 生成固定范围内的数组
(1) np.linspace
np.linspace(start, stop, num, endpoint)
创建等差数组,指定数量(步长自动计算)
start:序列的起始值
stop:序列的结束值
num:要生成的等间隔样例数量,默认为50
endpoint:序列中是否包含stop值,默认为true
(2) np.arange
np.arange(start,stop,step,dtype)
创建等差数组,指定步长(数量自动计算)
step:步长,默认为1
(3) np.logspace
np.logspace(start,stop,num)
创建等比数组,生成以10的N次幂的数据
num:要生成的等比数组数量,默认为50
2.2.9 生成随机数组
导入库
import random
(1) 正态分布
1.np.random.randn
np.random.randn(d0,d1,d2,……,dn)
功能:从标准正态分布中返回一个或多个样本值
2.np.random.normal
np.random.normal(loc = 0.0,scale = 1.0,size = None)
loc:float 此概率分布的均值(对应整个分布的中心)
scale:float 此概率分布的标准差(对应于分布的宽度,scale值越大越矮胖,scale值越小越瘦高) size:int or tuple of ints 输出的shape,默认为None,只输出一个值
3.np.random.standard_normal
np.random.standard_normal(size = None)
返回指定形状的标准正态分布的数组
(2) 均匀分布
1.np.random.rand
np.random.rand(d0,d1,d2,……,dn)
返回[0.0,1.0)内的一组均匀分布的数
2.np.random.uniform
np.random.uniform(low = 0.0,high = 1.0,size = None)
从一个均匀分布[low,high)中随机采样,注意定义域是左闭右开,即包含low,不包含high
low:采样下界,float类型,默认值为0
high:采样上界,float类型,默认值为1
size:输出样本数目,为int或tuple类型,缺少时输出1个值。例如:size=(m,n,k)则输出mnk个样本 返回值:ndarray类型,其形状和参数与size中定义的一致
3.np.random.randint
np.random.randint(low, high = None,size = None,dtype = 'i')
从一个均匀分布中随机采样,生成一个整数或N维整数数组
取数范围:若high不为None时,取(low,high)之间的随机整数,否则取值[0,low)之间随机整数
2.2.10 数组索引,切片
data[a:b,c:d]
注意:这里的数组切片遵循的规律是先行后列
2.2.11 类型修改
(1) ndarray.astype
ndarray.astype(type)
返回修改类型之后的数组
(2) ndarray.tostring和ndarray.tobytes
ndarray.tostring([order])
ndarray.tobytes([order])
构造包含数组中原始数据字节的python字节
2.2.11 ndarray运算
逻辑运算
(1) np.logical_and
np.logical_and(condition1,condition2)
condition:条件 当两个条件同时满足时返回Ture
(2) np.logical_or
np.logical_or(condition1,condition2)
当其中一个条件满足时返回Ture
(3)np.all
np.all()
所有条件都满足要求返回True,有任一个不满足返回False
(4)np.any
np.any()
任一个条件满足要求返回True
(5)np.where(三元运算符)
满足条件返回前一块内容,不满足返回后一块内容
np.where(condition,1,0)
满足条件返回1,不满足返回0
注意:复合逻辑需要结合np.logical_and和np.logical_or使用
2.2.12 统计指标
方法 | 作用 |
---|---|
np.min(ndarray,axis) | 查询所有行或所有列的最小值 |
np.max(ndarray,axis) | 查询所有行或所有列的最大值 |
np.median(ndarray,axis) | 查询所有行或所有列的中位数 |
np.mean(ndarray,axis) | 查询所有行或所有列的平均值 |
np.std(ndarray,axis,dtype) | 查询所有行或所有列的标准差 |
np.var(ndarray,axis,dtype) | 查询所有行或所有列的方差 |
np.ardmax(ndarray) | 查询最大值的位置 |
np.ardmin(ndarray) | 查询最小值的位置 |
注意:axis轴的取值并不一定,Numpy中不同的API轴的值都不一样
2.3 Pandas工具
导入库
import pandas as pd
2.3.1 三种主要的数据结构
数据结构 | 描述 |
---|---|
Series | 一维数据结构 |
DataFrame | 二维数据结构 |
MultiIndex | 三维数据结构 |
Panel | 三维数据结构(MultiIndex老版本) |
2.3.2 DataFrame
注意:后面的dataframe均代指二维的对象名
pd.DataFrame(data = None,index = None,columns = None)
index:行标签,如果没有传入索引参数,则默认会自动创建一个从0-N的整数索引
columns:列标签,如果没有传入索引参数,则默认会自动创建一个从0-N的整数索引
属性 | 作用 |
---|---|
dataframe.shape | 获取维度 |
dataframe.index | 获取行索引表 |
dataframe.columns | 获取列索引表 |
dataframe.values | 获取其中array的值 |
dataframe.T | 行列互换(转置) |
dataframe.head() | 默认获取前5行,其他行数自行添加 |
dataframe.tail() | 默认获取后5行,其他行数自行添加 |
dataframe.info | 获取每一列的非空元素个数 |
2.3.3 DataFrame索引设置
(1) 修改行列索引值
data.index = new_index
data.columns = new_columns
注意:修改索引值不能单个修改,必须整体修改
(2) 重设索引
dataframe.reset_index(drop = False)
设置新的下标索引 drop:默认为False,不删除原来索引,如果为True,删除原来索引值
(3) 以某列值设置为新的索引
dataframe.set_index(keys,drop = True)
keys:列索引命或者列索引名称的列表 drop:bool值默认为True,当做新的索引,删除原来的列
注意:行索引的修改与重设类似列索引
2.3.4 DataFrame排序
dataframe.sort_values(by = ,ascending =)
单个或多个键排序
by:指定排序参考的键
ascending:默认升序
ascending = False 降序
ascending = True 升序
2.3.5 DataFrame运算
(1) 基本运算
元素相加,维度相等时找不到元素默认用fill_value
dataframe.add(dataframe2, fill_value = None, axis = 1)
元素相减,维度相等时找不到元素默认用fill_value
dataframe.sub(dataframe2, fill_value = None, axis = 1)
元素相除,维度相等时找不到元素默认用fill_value
dataframe.div(dataframe2, fill_value = None, axis = 1)
元素相乘,维度相等时找不到元素默认用fill_value
dataframe.mul(dataframe2, fill_value = None, axis = 1)
(2) 逻辑运算函数
query(expr)
expr:查询字符串
通过逻辑运算函数可以使上面的过程更加方便简单
(3) 统计运算
dataframe.describe()
综合统计包括平均值,最大值,最小值等等
统计函数
函数 | 作用 |
---|---|
sum | 获取总和 |
mean | 获取平均值 |
median | 获取中位数 |
min | 获取最小值 |
max | 获取最大值 |
mode | 获取众数 |
abs | 获取绝对值 |
prod | 获取累积 |
std | 获取标准差 |
var | 获取方差 |
idxmax | 获取最大值索引 |
idxmin | 获取最小值索引 |
累计统计函数
函数 | 作用 |
---|---|
cumsum | 计算1/2/3/……/n个数的和 |
cummax | 计算1/2/3/……/n个数的最大值 |
cummin | 计算1/2/3/……/n个数的最小值 |
cumprod | 计算1/2/3/……/n个数的积 |
自定义运算
apply(func,axis=0)
func:自定义运算
axis=0默认是列,axis=1为行进行运算
2.3.6 Pandas画图
dataframe.plot(kind='line')
kind:str,需要绘制图形的种类
图形种类
种类 | 描述 |
---|---|
line | 折线图 |
bar | 条形图(竖直条状) |
bath | 条形图(水平条状) |
hist | 直方图 |
pie | 饼图 |
scatter | 散点图 |
注意: 1.条形图中可以添加是否堆积dataframe.plot(kind='bar',stacked=True) 2.stacked为True时堆积,为False时不堆积
具体过程跟matplotlib中类似,这里主要介绍利用pandas创造的二维对象dataframe,使用plot可以直接将dataframe转换成数据图类型。
2.3.7 文件读取与文件存储
类 | 数据类型 | 读取文件 | 存储文件 |
---|---|---|---|
text | CSV | read_csv | to_csv |
text | JSON | read_json | to_json |
text | HTML | read_html | to_json |
text | Local clipboard | read_clipboard | to_clipboard |
binary | MS Excel | read_excel | to_excel |
binary | HDF5 Format | read_hdf | to_hdf |
binary | Feather Format | read_feather | to_feather |
binary | Parquet Format | read_parquet | to_parquet |
binary | Msgpack | read_msgpack | to_msgpack |
binary | Stata | read_stata | to_stata |
binary | SAS | read_sas | -- |
binary | Python Pickle Format | read_pickle | to_pickle |
SQL | SQL | read_sql | to_sql |
SQL | Google Big Query | read_gbp | to_gbp |
例:
(1)使用numpy中的随机函数创建一个csv图表,图表一共分为5列10000行,各列名称依次为index,count,class,normal_distribution,0-1,分别代表序号,统计数据,类别,正态分布数据,0-1数据,其中count的数据范围在0-10000,class的数据范围为[1,2,3,4,5],normal_distribution的数据范围为0-10000,0-1的数据范围为[0,1],将创建的csv保存
(2)从创建的图表里读取数据,根据normal_distribution列画出画出正态分布的图像
(3)从创建的图表里读取数据,根据class列中各类的数量画饼图,并标注各类占比
(4)从创建的图表离读取数据,根据class和count列画出柱状图,其中y轴为各类的数值(对应count列)总和,x轴为类名称,并在各柱上方标注值
(5)从创建的图表离读取数据,根据count列画出各阶段分布直方图,均分为十段
(6)从创建的图表离读取数据,根据0-1列和class列模拟出各场红蓝对决比赛中人们的支持率
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy.stats import norm
np.random.seed(42)
row = 10000
index = np.arange(1,row + 1)
count = np.random.randint(0,10001,size = row)
class_data = np.random.choice([1,2,3,4,5],size = row)
normal = np.random.uniform(0,10001,size = row)
zero = np.random.rand(row)
data = {'index':index , 'count' : count, 'class' : class_data , 'normal_distribute' : normal,
'0 - 1' : zero}
df = pd.DataFrame(data)
df.to_csv('generated_data.csv',index = False)
data = pd.read_csv('generated_data.csv')
normal_data = data['normal_distribute']
mu,std = norm.fit(normal_data)
plt.hist(normal_data,bins = 50,density= True,alpha = 0.5, color = 'r')
xmin,xmax = plt.xlim()
x = np.linspace(xmin,xmax,100)
p = norm.pdf(x,mu,std)
plt.plot(x,p,'k',linewidth = 2)
plt.xlabel('value')
plt.ylabel('Frequency')
plt.legend(['Nornal_distribution','Data'])
plt.grid(True)
plt.show()
data = pd.read_csv('generated_data.csv')
class_counts = data['class'].value_counts()
plt.figure(figsize = (8,8))
plt.pie(class_counts,labels = class_counts.index,autopct = '%1.1f%%',startangle = 140)
plt.title('disribution of classes')
plt.show()
data = pd.read_csv('generated_data.csv')
plt.rcParams["font.sans-serif"] = ["SimHei"]
class_sum = df.groupby('class')['count'].sum()
plt.figure(figsize=(10,7))
class_sum.plot(kind='bar',color='green',edgecolor='black')
plt.title('各类别总计柱状图',fontsize='20')
plt.xlabel('类别',fontsize='15')
plt.ylabel('总数',fontsize='15')
plt.yticks(np.linspace(0,10000000, 11))
plt.tick_params(labelsize=15)
for a, b in enumerate(class_sum): #标记每列数值
plt.text(a, b, str(b),ha='center',va='bottom',fontsize=12)
plt.show()
data = pd.read_csv('generated_data.csv')
plt.figure(figsize=(8, 6))
plt.hist(data['count'], bins=10, color='azure', edgecolor='black')
plt.xlabel('Count')
plt.ylabel('Frequency')
plt.title('Distribution of Counts in Ten Bins')
plt.grid(True)
plt.show()
data = pd.read_csv('generated_data.csv')
support_rates = data.groupby('class')['0 - 1'].mean()
plt.figure(figsize=(8, 6))
colors = ['azure' if team == 1 else 'skyblue' for team in support_rates.index]
plt.bar(support_rates.index, support_rates, color=colors)
plt.xlabel('Team')
plt.ylabel('Support Rate')
plt.title('Support Rate for azure and skyblue Teams')
plt.ylim(0, 1)
plt.show()
2.4 高级数据处理
2.4.1 缺失值处理
首先需要获取缺失值的标记方式(NAN或者其他标记方式,一般来说都是NAN)
判断数据中是否包含NAN
方法 | 描述 |
---|---|
pd.isnull(dataframe) 或dataframe.isnull() | 有缺失值返回True,没有缺失值返回False |
pd.notnull(dataframe)或dataframe.isnull() | 没有缺失值返回True,有缺失值返回False |
(1) 删除存在缺失值的对象
dataframe.dropna(axis = 0)
默认删除缺失值所在行,可以通过设置axis=1删除所在列
注意:这里不会修改原数据,需要接收返回值
(2) 替换缺失值
dataframe.fillna(value, inplace = True)
value:替换成的值
inplace:True则会修改原数据,False则不替换修改原数据,生成新的对象
(3) 缺失值没有使用NAN标记
通过如下代码将其他标记(比如’?‘)替换为NAN,再使用上面的方法处理dataframe.replace(to_replace = '?',value = np.nan)
2.4.2 合并
(1) pd.concat
pd.concat([data1, data2], axis = 1)
按照行或列进行合并,axis=0为扩展行,axis=1为扩展列
(2) pd.merge
pd.merge(left, right, how = 'inner', on = None)
可以指定按照两组数据的共同键值对合并或者左右各自
left : dataframe
right :另一个dataframe
on :指定的共同键
how:按照什么方式连接
how的方式
方式 | 作用 | 描述 |
---|---|---|
left | 左连接 | 左边加左右交集的部分 |
right | 右连接 | 右边加左右交集的部分 |
outer | 外连接 | 并集部分 |
inner | 内连接 | 交集部分 |
2.4.3 分组与聚合
(1) 分组
DataFrame.groupby(key, as_index = True)
key:分组的列数据,可以多个
as_index:若为True则不保留原来的索引,若为False则保留原来的索引
(2) 聚合
一般是指对分组中的数据执行某些操作,比如求平均值、最大值等,并且会得到一个结果集。
3.sklearn
3.1 决策树
3.1.1 构建决策树
关键概念:全局最优,局部最优
(1) ID3算法构建决策树
重要概念:不纯度
注意:分类型决策树在叶子节点上的决策规则是少数服从多数
(2) 1.2.3 ID3的局限性
3.1.2 熵
在化学中,熵用来衡量一种物质内部的混乱程度,即这种物质的纯度。
在概率论中,设有一事件X XX,则它的熵H ( X ) H(X)H(X)可以衡量事件X XX发生的不确定性。
熵的公式为:
当一组数据中的纯度越高,熵值就越小。
3.1.3 Gini系数
当概率越小时,得到的Gini系数越大,这和熵值的定义是一样的。
3.1.4 分类树与回归树
结果字段来看,分类树必须是类别型的字段,回归树则是数值型的字段。他们的形态很像。建构的过程也很类似,只不过目标不同。
分类树一般能得到比较精准的结果,而且解读性比较高。
3.1.5 决策树的基本流程简单概括
直到没有更多的特征可用,或整体的不纯度指标已经最优,决策树就会停止生长。
3.1.6 建立一颗树
#导入需要的算法库和模块
from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
3.1.7 红酒数据集
#红酒数据集
#导入需要的算法库和模块
from sklearn import tree
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
wine = load_wine() #加载并返回葡萄酒数据集(分类)。
wine.data.shape #看一下这个表格是怎么样的
#输出(178, 13),代表存在178行,13列
wine.target #查看表格中有几个标签
# array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
# 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
# 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
# 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
# 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
# 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
# 2, 2])
#即数据集中的标签有三种,0,1和2,也就是这些红酒被分成了三类。
#如果wine是一张表,应该长这样
# import pandas as pd
# pd.concat([pd.DataFrame(wine.data),pd.DataFrame(
# .wine.target)],axis=1)
#这里是将红酒属性数据集和标签列进行了横向链接(也叫合并,学过数据库的都知道)
# wine.feature_names
#查看红酒的属性名字
# wine.target_names
#查看标签名字,也就是分类的名字
Xtrain,Xtest,Ytrain,Ytest=train_test_split(wine.data,wine.target,test_size=0.3)
#将数据集分为训练集和测试集,其中70%为训练集,30%为测试集。
Xtrain.shape
#训练集有124个样本,13个属性
Xtest.shape
#训练集有54个样本,13个属性
Ytrain
#查看训练集的目标属性;有三种,为0,1,2
#建立模型
clf = tree.DecisionTreeClassifier(criterion="entropy") #建立决策分类树,判断不纯度的方法是信息熵
clf = clf.fit(Xtrain,Ytrain) #用训练集数据训练模型
score = clf.score(Xtest,Ytest) #返回预测的准确accuracy(分数)
score#查看预测的模型分数
#画出这棵树
feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜 色强度','色调','od280/od315稀释葡萄酒','脯氨酸']
import graphviz
dot_data = tree.export_graphviz(clf,out_file = None,feature_names= feature_name,class_names=["琴酒","雪莉","贝尔摩德"],filled=True,rounded=True)
#以 DOT 格式导出决策树。
# decision_tree:决策树分类器;要导出到 GraphViz 的决策树。
# out_file:对象或字符串,默认=无;输出文件的句柄或名称。如果 None ,则结果以字符串形式返回。
# feature_names:str列表,默认=无;每个函数的名称。如果 None 将使用通用名称(“feature_0”、“feature_1”、...)。
# class_names:str 或 bool 的列表,默认 = 无
# 每个目标类别的名称按数字升序排列。仅与分类相关,不支持multi-output。如果 True ,则显示类名的符号表示。
# filled:布尔,默认=假
# 当设置为 True 时,绘制节点以指示分类的多数类、回归值的极值或 multi-output 的节点纯度。
#rounded:布尔,默认=假;当设置为 True 时,绘制圆角节点框。
graph = graphviz.Source(dot_data) #获取生成的决策树
graph #打印生成的决策树
#特征重要性
clf.feature_importances_
#打印每个属性的重要性的数值,只有数值,不知道数值对应的属性是什么
[*zip(feature_name,clf.feature_importances_)]
#打印每个属性及其对应的重要性的数值
# 建更多的不同的树,然后从中取最好的。
# 在每次分枝时,不从使用全部特征,而是随 机选取一部分特征,从中选取不纯度相关指标最优的作为分枝用的节点。
clf = tree.DecisionTreeClassifier(criterion="entropy",random_state=30)
# random_state 用来设置分枝中的随机模式的参数,默认 None
#random_state是一个随机种子,是在任意带有随机性的类或函数里作为参数来控制随机模式。
#当random_state取某一个值时,也就确定了一种规则。
# 在高维度时随机性会表现更明显,低维度的数据 (比如鸢尾花数据集),随机性几乎不会显现。
#固定random_state后,每次构建的模型是相同的、生成的数据集是相同的、每次的拆分结果也是相同的。
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest) #返回预测的准确度
score
#这里的score会固定在0.925,不论你运行多少遍,它都不会变,因为每次都是选择的最优的树。
#使用splitter来降低过拟合的可能性
clf = tree.DecisionTreeClassifier(criterion="entropy",random_state=30 ,splitter="random")
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest)
score #输出结果为0.944444
# splitter 也是用来控制决策树中的随机选项的,有两种输入值
# 输入 "best" :决策树在分枝时虽然随机,但是还是会 优先选择更重要的特征进行分枝(重要性可以通过属性feature_importances_ 查看)
# 输入 "random" :决策树在 分枝时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合。
# 这也是防止过拟合的一种方式。当你预测到你的模型会过拟合,用这两个参数来帮助你降低树建成之后过拟合的可能性。
#画出图像
import graphviz
dot_data = tree.export_graphviz(clf,feature_names= feature_name,class_names=["琴酒","雪莉","贝尔摩德"],filled=True,rounded=True )
graph = graphviz.Source(dot_data)
graph
#我们的树对训练集的拟合程度如何?
score_train = clf.score(Xtrain, Ytrain) #返回预测的准确分数
score_train #查看预测的准确分数,此时结果为1.0 过拟合了
#剪枝方法降低过拟合的可能性:
#(1)max_depth 限制树的最大深度
#(2)min_samples_split 限定,一个节点必须要包含至少 min_samples_split 个训练样本,这个节点才允许被分枝,否则分枝就不会发生。
#(3)min_samples_leaf 限定,一个节点在分枝后的每个子节点都必须包含至少 min_samples_leaf 个训练样本,否则分枝就不会发生
# 或者,分枝会朝着满足每个子节点都包含min_samples_leaf 个样本的方向去发生
#通过限制条件进行剪枝,得到的决策树会更简洁,预测的准确分数也不错
clf=tree.DecisionTreeClassifier(criterion="entropy",random_state=30,splitter="random",max_depth=3,min_samples_leaf=5,min_samples_split=5)
clf = clf.fit(Xtrain, Ytrain)
dot_data = tree.export_graphviz(clf,feature_names= feature_name,class_names=["琴酒","雪莉","贝尔摩德"],filled=True,rounded=True)
graph = graphviz.Source(dot_data)
graph
score = clf.score(Xtest, Ytest)
score #0.9629629629629629
# 超参数的学习曲线,是一条以超参数的取值为横坐标,模型的度量指标为纵坐标的曲线,它是用来衡量不同超参数取值下模型的表现的线。
# 在我们建好的决策树里,我们的模型度量指标就是score 。
import matplotlib.pyplot as plt #导入画图库
test = [] #创建一个列表
for i in range(10): #循环10次
clf = tree.DecisionTreeClassifier(max_depth=i+1,criterion="entropy",random_state=30,splitter="random")
clf = clf.fit(Xtrain, Ytrain) #训练模型
score = clf.score(Xtest, Ytest) #预测的准确分数
test.append(score) #往列表里面添加预测的分数值
plt.plot(range(1,11),test,color="red",label="max_depth") #画图
#横坐标为max_depth取值,纵坐标为score,图线颜色为red,label为图例的名称
#从图中我们可以看到,当max_depth取3的时候,模型得分最高
plt.legend() #给图像加图例
plt.show() #显示所打开的图形
3.2 随机森林
3.2.1 集成算法概述
3.2.2 sklearn中的集成算法
3.2.3 重要参数
(1) 控制基评估器的参数
(2) n_estimators
(3) random_state
(3) bootstrap & oob_score
bootstrap参数默认True,代表采用这种有放回的随机抽样技术。通常,这个参数不会被我们设置为False。
然而有放回抽样也会有自己的问题。由于是有放回,一些样本可能在同一个自助集中出现多次,而其他一些却可能被忽略,一般来说,自助集大约平均会包含63%的原始数据。因为每一个样本被抽到某个自助集中的概率为:
3.2.4 机器学习中调参的基本思想
(1) 泛化误差
3.2.5 综合展示
例:
import math
import matplotlib.pyplot as plt
import numpy as np
from sklearn.ensemble import RandomForestRegressor # 导入随机森林训练模型
from sklearn.metrics import r2_score # 使用拟合优度r2_score对实验结果进行评估
from sklearn.model_selection import train_test_split
from sklearn import datasets
class DecisionNode(object):
def __init__(self, f_idx, threshold, value=None, L=None, R=None):
self.f_idx = f_idx
self.threshold = threshold
self.value = value
self.L = L
self.R = R
# 改变:不需要排序,取实际的数据作为划分点
def find_best_threshold(dataset: np.ndarray, f_idx: int): # dataset:numpy.ndarray (n,m+1) x<-[x,y] f_idx:feature index
best_gain = -math.inf # 先设置 best_gain 为无穷小
best_threshold = None
candidate = list(set(dataset[:, f_idx].reshape(-1)))
for threshold in candidate:
L, R = split_dataset(dataset, f_idx, threshold) # 根据阈值分割数据集,小于阈值
gain = calculate_var_gain(dataset, L, R) # 根据数据集和分割之后的数
if gain > best_gain: # 如果增益大于最大增益,则更换最大增益和最大
best_gain = gain
best_threshold = threshold
return best_threshold, best_gain
def calculate_var(dataset: np.ndarray):
y_ = dataset[:, -1].reshape(-1)
var = np.var(y_)
return var
def calculate_var_gain(dataset, l, r):
var_y = calculate_var(dataset)
var_gain = var_y - len(l) / len(dataset) * calculate_var(l) - len(r) / len(dataset) * calculate_var(r)
return var_gain
def split_dataset(X: np.ndarray, f_idx: int, threshold: float):
L = X[:, f_idx] < threshold
R = ~L
return X[L], X[R]
def mean_y(dataset):
y_ = dataset[:, -1]
return np.mean(y_)
def build_tree(dataset: np.ndarray, f_idx_list: list, depth, max_depth, min_samples): # return DecisionNode 递归
# 怎么判断depth
class_list = [data[-1] for data in dataset] # 类别 dataset 为空了,
n, m = dataset.shape
k = int(math.log(m, 2)) + 1
if n < min_samples:
return DecisionNode(None, None, value=mean_y(dataset))
elif depth > max_depth:
return DecisionNode(None, None, value=mean_y(dataset))
# 全属于同一类别
elif class_list.count(class_list[0]) == len(class_list):
return DecisionNode(None, None, value=mean_y(dataset))
else:
# 找到使增益最大的属性
best_gain = -math. inf
best_threshold = None
best_f_idx = None
# 选取部分属性进行最优划分
f_idx_list_random = list(np.random.choice(m-1, size=k, replace=False))
for i in f_idx_list_random:
threshold, gain = find_best_threshold(dataset, i)
if gain > best_gain: # 如果增益大于最大增益,则更换最大增益和最大阈值
best_gain = gain
best_threshold = threshold
best_f_idx = i
# 创建分支
L, R = split_dataset(dataset, best_f_idx, best_threshold)
if len(L) == 0:
depth += 1
L_tree = DecisionNode(None, None, mean_y(dataset)) # 叶子节点
else:
depth += 1
L_tree = build_tree(L, f_idx_list, depth, max_depth, min_samples) # return DecisionNode
if len(R) == 0:
R_tree = DecisionNode(None, None, mean_y(dataset)) # 叶子节点
else:
R_tree = build_tree(R, f_idx_list, depth, max_depth, min_samples) # return DecisionNode
return DecisionNode(best_f_idx, best_threshold, value=None, L=L_tree, R=R_tree)
def predict_one(model: DecisionNode, data):
if model.value is not None:
return model.value
else:
feature_one = data[model.f_idx]
branch = None
if feature_one >= model.threshold:
branch = model.R # 走右边
else:
branch = model.L # 走左边
return predict_one(branch, data)
# 有放回随机采样
def random_sample(dataset):
n, _ = dataset.shape
sub_data = np.copy(dataset)
random_data_idx = np.random.choice(n, size=n, replace=True) # 0~(n-1) 产生n个 有放回采样
sub_data = sub_data[random_data_idx]
return sub_data[:, 0:-1], sub_data[:, -1]
class Random_forest(object):
def __init__(self, min_samples, max_depth):
self.min_samples = min_samples # 节点样本数量少于 min_samples, 叶子节点
self.max_depth = max_depth # 最大深度
def fit(self, X: np.ndarray, y: np.ndarray) -> None:
dataset_in = np.c_[X, y]
f_idx_list = [i for i in range(X.shape[1])]
depth = 0
self.my_tree = build_tree(dataset_in, f_idx_list, depth, self.max_depth, self.min_samples)
def predict(self, X: np.ndarray) -> np.ndarray: # 递归 how?
predict_list = []
for data in X:
predict_list.append(predict_one(self.my_tree, data))
return np.array(predict_list)
if __name__ == "__main__":
X, y = datasets.load_diabetes(return_X_y=True)
y_predict_list = []
r2_score_list = []
tree_number = []
MAE_list = []
MAPE_list = []
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
print(y_test.shape) # 89*1
dataset = np.c_[X_train, y_train]
np.seterr(divide='ignore', invalid='ignore')
T = 100
for i in range(T):
X_train_samples, y_train_samples = random_sample(dataset)
m = Random_forest(min_samples=5, max_depth=20)
m.fit(X_train_samples, y_train_samples)
y_predict = m.predict(X_test)
y_predict_list.append(y_predict) # 二维数组
print("epoc", i+1, " done")
y_ = np.mean(y_predict_list, axis=0) # 当前的预测值
score = r2_score(y_test, y_)
r2_score_list.append(score)
tree_number.append((i + 1))
errors = abs(y_ - y_test)
MAE_list.append(np.mean(errors)) # 平均绝对误差
mape = 100 * (errors / y_test)
MAPE_list.append(np.mean(mape)) # 平均绝对百分比误差
#
# print("r2_score_list", r2_score_list)
plt.plot(tree_number[5:-1], r2_score_list[5:-1])
plt.title('r2_score')
plt.xlabel('tree number')
plt.ylabel('r2_score')
plt.show()
# print("MAE_list", MAE_list)
#
# print("MAPE_list", MAPE_list)
plt.plot(tree_number, MAPE_list)
plt.xlabel('tree number')
plt.ylabel('MAPE %')
plt.title("MAPE: Mean Absolute Percentage Error")
plt.show()
y_result = np.mean(y_predict_list, axis=0) # 最终结果
print("r2_score:", r2_score(y_test, y_result))
errors1 = abs(y_result - y_test) # 平均绝对误差
print('Mean Absolute Error:', np.round(np.mean(errors1), 2), 'degrees.')
mape = 100 * (errors1 / y_test) # 平均绝对百分比误差
print('MAPE:', np.round(np.mean(mape), 2), '%.')
# accuracy = 100 - np.mean(mape)
# print('Accuracy:', round(accuracy, 2), '%.')
# ---------------------------画图------------------------------
plt.figure(figsize=(20, 5))
plt.plot([i for i in range(y_test.shape[0])], y_test, color='red', alpha=0.8, label="y_test")
plt.plot([i for i in range(y_test.shape[0])], y_result, color='blue', alpha=0.8, label="y_result")
plt.legend(loc="upper right")
plt.title("My Random forest")
plt.show()
# ----------------------------------sklearn--------------------------------
regressor = RandomForestRegressor(n_estimators=100, min_samples_leaf=5)
regressor.fit(X_train, y_train) # 拟合模型
y_pred = regressor.predict(X_test)
print('sklearn score:{}'.format(r2_score(y_test, y_pred))) # 显示训练结果与测试结果的拟合优度
errors = abs(y_pred - y_test)
# Print out the mean absolute error (mae)
print('Mean Absolute Error:', np.round(np.mean(errors), 2), 'degrees.')
mape = 100 * (errors / y_test)
accuracy = 100 - np.mean(mape)
print('Accuracy:', round(accuracy, 2), '%.')
# ---------------------------画图------------------------------
plt.figure(figsize=(20, 5))
plt.plot([i for i in range(y_test.shape[0])], y_test, color='red', alpha=0.8, label="y_test")
plt.plot([i for i in range(y_test.shape[0])], y_pred, color='blue', alpha=0.8, label="y_pred")
plt.legend(loc="upper right")
plt.title("sklearn RandomForestRegressor")
plt.show()