写作前言:
1.本文章的写作顺序和Chris Albon[美]《Python机器学习手册-从数据预处理到深度学习》(Machine Learning with Python Cookbook)相似。但是我会添加自己的想法和总结,并简化内容。如有侵权,请及时联系我删除文章。至此,由衷感谢该书提供指导。
2.文章篇幅比较大,文章分为以下章节:
-- 1. 向量、矩阵和数组
-- 2. 加载数据
-- 3. 数据整理
-- 4. 处理数值型数据
-- 5. 处理分类数据
-- 6. 处理文本
-- 7. 处理日期和时间
-- 8. 图像处理
-- 9. 使用特征提取进行特征降维
-- 10. 使用特征选择进行降维
-- 11. 模型评估
-- 12. 模型选择
-- 13. 线性回归
-- 14. 树和森林
-- 15. KNN
-- 16. 逻辑回归
-- 17. 支持向量机
-- 18. 朴素贝叶斯
-- 19. 聚类
-- 20. 神经网络
3.文章归纳了在机器学习中所常遇见的方法,只上应用实例。如果想要查询方法的参数以及更多的使用方法,请读者前往官方查询。
4.基于笔者能力有限以及写作文章篇幅过大,写作未免有疏漏错误,还请读者大胆提出来,笔者愿意接受读者的批评指正。
5.所有代码的运行环境基于所需模块的版本详细:
- python 3.8.8
- numpy 1.22.4
- scikit-learn 1.2.2
- pandas 1.3.5
- matplotlib 3.3.4
目录
在前章介绍完“加载数据”后,就开始我们的“数据整理”。
“数据整理”经常用于描述将原始数据转换成组织合理的、整洁的形式以供后面的使用。同时,“数据整理”是“数据预处理”里的一个关键步骤。
在整理数据中,我们用到的数据结构是数据帧,可通过第三方模块pandas来实现。数据帧呈表格形状的,让数据分析者使用起来非常的直观和方便。数据帧的结构图如下(来源菜鸟教程):
本章所使用来自菜鸟教程提供的nba.csv的数据集:
1.创建数据帧
创建数据帧 | 实例化类pd.DataFrame() | |
01 | 采用列表结构添加数据 | dataframe = pd.DataFrame() # 先实例化帧对象 dataframe["columns_label_name"]=[v1,v2,..vn] |
data = [[v01,...,v0n],[v11,...,v1n],...] dataframe = pd.DataFrame(data,columns=[...]) # 后实例化帧对象 | ||
02 | 采用字典结构添加数据 | data = {"k1":[v1,v2,...],...} dataframe = pd.DataFrame(data) # 后实例化帧对象 |
1.1 采用列表结构添加数据
第一种是DataFrame指定列标签来使用列表结构添加数据。最后的结果是:所提供的数据是按列方向去排的。
import pandas as pd
""" 创建一个数据帧 """
# 创建数据帧对象
dataframe = pd.DataFrame()
# 创建列数据
dataframe["Name"] = ["Ethan","Winters","Amazon"]
dataframe["Age"] = [18,19,20]
# 查看数据帧
print(dataframe)
# >>>
"""
Name Age
0 Ethan 18
1 Winters 19
2 Amazon 20
"""
第二种是创建DataFrame对象时,一并传递参数列表结构数据和列标签来创建数据的。最后的结果是:所提供的数据是按行方向去排的。
import pandas as pd
""" 创建一个数据帧 """
# 创建行数据
data = [["Ethan",18],["Winters",19],["Amazon",20]]
# 创建数据帧对象
dataframe = pd.DataFrame(data=data,columns=["Name","Age"])
# 查看数据帧
print(dataframe)
# >>>
"""
Name Age
0 Ethan 18
1 Winters 19
2 Amazon 20
"""
1.2 采用字典结构添加数据
由于字典具有键值对的性质。采用字典结构形式添加数据时,键key会转换为数据帧的列标签,值value会转换为数据帧的列数据,最后的结果是:所提供的数据是按列方向去排的。
import pandas as pd
""" 创建一个数据帧 """
# 创建数据
data = {
"Name":["Ethan","Winters","Amazon"],
"Age":[18,19,20]
}
# 创建数据帧对象
dataframe = pd.DataFrame(data=data)
# 查看数据帧
print(dataframe)
# >>>
"""
Name Age
0 Ethan 18
1 Winters 19
2 Amazon 20
"""
2.描述数据
01 | 查看数据集描述性统计量 | describe()方法 | ||||||||||||||||||||||||
02 | 计算列标签描述性统计量 | dataframe["columns_label_name"] # 指定列标签
| ||||||||||||||||||||||||
03 | 根据值对行分组 | groupby()方法 再引用描述性统计量方法 | ||||||||||||||||||||||||
04 | 数据排序 | sort_values()方法 |
2.1 查看数据集描述性统计量
import pandas as pd
""" 查看描述性统计量 """
# 获取数据
dataframe = pd.read_csv("nba.csv")
# 查看描述性统计量
print(dataframe.describe())
# >>>
"""
Number Age Weight Salary
count 457.000000 457.000000 457.000000 4.460000e+02
mean 17.678337 26.938731 221.522976 4.842684e+06
std 15.966090 4.404016 26.368343 5.229238e+06
min 0.000000 19.000000 161.000000 3.088800e+04
25% 5.000000 24.000000 200.000000 1.044792e+06
50% 13.000000 26.000000 220.000000 2.839073e+06
75% 25.000000 30.000000 240.000000 6.500000e+06
max 99.000000 40.000000 307.000000 2.500000e+07
"""
2.2 计算列标签描述性统计量
在2.1中以及归纳(部分)出每一列数字类型的数据的统计量。在获取最小值还是最大值等,只需要在数据帧中访问所需列标签的值并引用对应的方法即可。
import pandas as pd
# 获取数据
dataframe = pd.read_csv("nba.csv")
""" 计算年龄的最小值 """
print(dataframe["Age"].min())
# >>>
"""
19.0
"""
""" 计算年龄的最大值 """
print(dataframe["Age"].max())
# >>>
"""
40.0
"""
""" 计算年龄的总和 """
print(dataframe["Age"].sum())
# >>>
"""
12311.0
"""
""" 计算年龄的平均值 """
print(dataframe["Age"].mean())
# >>>
"""
26.938730853391686
"""
""" 计算年龄的计数值 """
print(dataframe["Age"].count())
# >>>
"""
457
"""
除了上述常用统计量之外,pandas还提供了计算方差(var)、标准差(std)、峰态(kurt)、偏态(skew)、平均值标准误差(sem)、众数(mode)、中位数(median)。
2.3 根据值对行分组
import pandas as pd
""" 根据值对行分组 """
# 获取数据
dataframe = pd.read_csv("nba.csv")
# 对"College"分组,分析每一列数字类型数据的平均值
dataframe = dataframe.groupby(["College"]).mean()
print(dataframe)
# >>>
"""
Number Age Weight Salary
College
Alabama 22.333333 29.000000 216.666667 1.421686e+06
Arizona 18.076923 27.384615 221.692308 3.325948e+06
Arizona State 16.000000 27.500000 235.000000 7.933941e+06
Arkansas 3.000000 27.333333 218.333333 2.713180e+06
Baylor 13.000000 25.000000 240.000000 9.813480e+05
... ... ... ... ...
Western Michigan 42.000000 25.000000 250.000000 8.450590e+05
Wichita State 11.000000 25.000000 210.000000 8.450590e+05
Wisconsin 28.200000 25.800000 220.600000 1.974492e+06
Wyoming 7.000000 23.000000 230.000000 1.155600e+06
Xavier 30.000000 35.000000 250.000000 1.499187e+06
"""
groupby()方法是根据一些共有的值来分组的,调用完这个方法之后,仍需要调用描述性统计量的方法,比如max()、mean()等方法。否则系统并不知道你想要返回什么数据。
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001BADDD01700>
当然,groupby()支持多次分组,因此我在参数列表中引用列表形式,如果想要选择多次分组,只需要在列表中添加列标签名即可。分组的优先级是按照列表的索引来的。如:
import pandas as pd
""" 根据值对行分组 """
# 获取数据
dataframe = pd.read_csv("nba.csv")
# 对"College"分组,再对"Position"分组,分析每一列数字类型数据的平均值
dataframe = dataframe.groupby(["College","Position"]).mean()
print(dataframe)
# >>>
"""
Number Age Weight Salary
College Position
Alabama PF 0.000000 25.0 227.000000 845059.0
PG 52.000000 33.0 198.000000 2100000.0
SF 15.000000 29.0 225.000000 1320000.0
Arizona C 27.000000 28.0 235.000000 4000000.0
PF 10.666667 26.0 238.333333 5454903.0
... ... ... ... ...
Wisconsin PF 28.000000 25.5 224.000000 780046.5
PG 34.000000 33.0 185.000000 4053446.0
SF 7.000000 22.0 230.000000 1646400.0
Wyoming PF 7.000000 23.0 230.000000 1155600.0
Xavier PF 30.000000 35.0 250.000000 1499187.0
"""
2.4 数据排序
sort_values()方法部分参数说明:
['column_name1', 'column_name2',...] | 选择需要排序的列 |
ascending | bool或bool列表,默认为True 如果为True,则按升序对值进行排序,否则按降序排序。 |
import pandas as pd
""" 数据排序 """
# 获取数据
dataframe = pd.read_csv("nba.csv")
# 对"Salary"进行升序排序,并对"Weight"降序排序
dataframe = dataframe.sort_values(["Salary","Weight"],ascending=[True, False])
print(dataframe)
# >>>
"""
Name ... Salary
32 Thanasis Antetokounmpo ... 30888.0
291 Orlando Johnson ... 55722.0
130 Phil Pressey ... 55722.0
135 Alan Williams ... 83397.0
175 Jordan McRae ... 111196.0
.. ... ... ...
269 Ray McCallum ... NaN
264 Jordan Farmar ... NaN
270 Xavier Munford ... NaN
350 Briante Weber ... NaN
457 NaN ... NaN
"""
在上述代码中,对Salary进行升序、对Height进行降序,它的数据将会变成什么样子的呢?
其实在选定多个列标签的参数时候,它会有一个优先级关系。同样的,它的优先级按照列表的索引来的。即当高优先级列比较完后,再比较次优先级列,并且次优先级列所排序后的数据不能影响高优先级列排序后的数据。因此,这种次优先级列排序的主体通常是在高优先级列排序完后存在具有相同数据的样本。如下图:
3.选择数据帧
01 | 根据索引选择行 | iloc方法 |
02 | 根据条件语句选择行 | dataframe[条件语句] |
03 | 根据行/列名删除行/列 | drop()方法 |
04 | 删除重复行 | drop_duplicates()方法 |
05 | 合并数据帧 | pd.merge()方法 |
3.1 根据索引选择行
import pandas as pd
""" 根据索引选择行 """
# 获取数据
dataframe = pd.read_csv("nba.csv")
# 选择到第四行为止的所有数据
print(dataframe.iloc[:4])
# >>>
"""
Name Team Number ... Weight College Salary
0 Avery Bradley Boston Celtics 0.0 ... 180.0 Texas 7730337.0
1 Jae Crowder Boston Celtics 99.0 ... 235.0 Marquette 6796117.0
2 John Holland Boston Celtics 30.0 ... 205.0 Boston University NaN
3 R.J. Hunter Boston Celtics 28.0 ... 185.0 Georgia State 1148640.0
"""
上述代码中采用的是引用iloc方法,那么iloc和loc的最主要区别是索引的方式。
iloc方法是使用整数位置进行索引,而loc方法是使用标签进行索引。
比如获取第一行第二列数据中,使用iloc方法则表示iloc[0,1],在loc方法则表示loc[0,"Second_Label"](在DataFrame中行标签名字主要是数字类型的索引)。
3.2 根据条件语句选择行
在pandas中,DataFrame提供了条件语句的嵌套。请看下述代码:
import pandas as pd
""" 根据条件语句选择行 """
# 获取数据
dataframe = pd.read_csv("nba.csv")
# 选择所有Team标签中符合"Boston Celtics"的行数据
dataframe = dataframe[dataframe["Team"] == "Boston Celtics"]
print(dataframe)
# >>>
"""
Name Team ... College Salary
0 Avery Bradley Boston Celtics ... Texas 7730337.0
1 Jae Crowder Boston Celtics ... Marquette 6796117.0
2 John Holland Boston Celtics ... Boston University NaN
3 R.J. Hunter Boston Celtics ... Georgia State 1148640.0
4 Jonas Jerebko Boston Celtics ... NaN 5000000.0
5 Amir Johnson Boston Celtics ... NaN 12000000.0
6 Jordan Mickey Boston Celtics ... LSU 1170960.0
7 Kelly Olynyk Boston Celtics ... Gonzaga 2165160.0
8 Terry Rozier Boston Celtics ... Louisville 1824360.0
9 Marcus Smart Boston Celtics ... Oklahoma State 3431040.0
10 Jared Sullinger Boston Celtics ... Ohio State 2569260.0
11 Isaiah Thomas Boston Celtics ... Washington 6912869.0
12 Evan Turner Boston Celtics ... Ohio State 3425510.0
13 James Young Boston Celtics ... Kentucky 1749840.0
14 Tyler Zeller Boston Celtics ... North Carolina 2616975.0
"""
在上述代码中,dataframe["Team"] == "Boston Celtics"就是一个条件语句。我们在它外面嵌套一层dataframe[]来告诉pandas:“选择数据帧中所有dataframe["Team"]的值为"Boston Celtics"的行数据”。
当然后面可根据与或非逻辑(与& 或| 非~)来制定多个条件语句。
必须注意的是:使用多个条件语句时,每个条件必须添加一对括号,以表示运算的优先级。
比如:
import pandas as pd
""" 根据条件语句选择行 """
# 获取数据
dataframe = pd.read_csv("nba.csv")
# 选择所有Team标签中符合"Boston Celtics"并且Age标签不是小于26岁的行数据
dataframe = dataframe[
(dataframe["Team"] == "Boston Celtics") & (~ (dataframe["Age"] < 26))
]
print(dataframe)
# >>>
"""
Name Team ... College Salary
2 John Holland Boston Celtics ... Boston University NaN
4 Jonas Jerebko Boston Celtics ... NaN 5000000.0
5 Amir Johnson Boston Celtics ... NaN 12000000.0
11 Isaiah Thomas Boston Celtics ... Washington 6912869.0
12 Evan Turner Boston Celtics ... Ohio State 3425510.0
14 Tyler Zeller Boston Celtics ... North Carolina 2616975.0
"""
3.3 根据行/列名删除行/列
对于根据行名或列名删除,最好的方式是使用drop()方法,并传入axis的参数。
在数据处理中,我们使用drop()方法更倾向于删除一些无用的特征,即一些列标签。而对于无用的行数据,即一些样本,我们则会更倾向于根据条件语句来选择。
import pandas as pd
""" 根据行/列名删除行/列 """
# 获取数据
dataframe = pd.read_csv("nba.csv")
# 删除"Name"列标签
dataframe = dataframe.drop(["Name"],axis=1)
print(dataframe)
# >>>
"""
Team Number Position ... Weight College Salary
0 Boston Celtics 0.0 PG ... 180.0 Texas 7730337.0
1 Boston Celtics 99.0 SF ... 235.0 Marquette 6796117.0
2 Boston Celtics 30.0 SG ... 205.0 Boston University NaN
3 Boston Celtics 28.0 SG ... 185.0 Georgia State 1148640.0
4 Boston Celtics 8.0 PF ... 231.0 NaN 5000000.0
.. ... ... ... ... ... ... ...
453 Utah Jazz 8.0 PG ... 203.0 Butler 2433333.0
454 Utah Jazz 25.0 PG ... 179.0 NaN 900000.0
455 Utah Jazz 21.0 C ... 256.0 NaN 2900000.0
456 Utah Jazz 24.0 C ... 231.0 Kansas 947276.0
457 NaN NaN NaN ... NaN NaN NaN
"""
当然,可以输入更多特定的“列标签名”来删除更多的列标签。只需要在列表中添加即可。对于只删除单个列标签,可以把中括号去掉,并不会影响结果。但为了这种规则,我们还是需要约定俗成,不去掉中括号最好。
3.4 删除重复行
import pandas as pd
""" 删除重复行 """
# 创建数据
data = {
"Name":["Ethan","Ethan","Amazon"],
"Age":[18,18,20]
}
# 创建数据帧对象
dataframe = pd.DataFrame(data=data)
# 删除重复行
dataframe = dataframe.drop_duplicates()
print(dataframe)
# >>>
"""
Name Age
0 Ethan 18
2 Amazon 20
"""
注意的是:drop_duplicates()方法默认只删除那些所有列都完美匹配的行。假设某一列标签都是唯一的,比如每个人身份证,我们想删除了“身份证”外的所有标签都完美匹配的行。很明显的是,光drop_duplicates()方法是不行的,我们需要引入参数subset。
subset参数是选择相应的列标签或标签序列,可选仅考虑某些列来标识重复项,默认情况下使用所有列。当我们填上所有标签除了“身份证”标签,那么就会删除所有除了“身份证”标签外所有相同的行。删除重复行后,drop_duplicates()默认保留的是最先出现的一行。
import pandas as pd
""" 删除重复行 """
# 创建数据
data = {
"Id":[1,2,3],
"Name":["Ethan","Ethan","Amazon"],
"Age":[18,18,20]
}
# 创建数据帧对象
dataframe = pd.DataFrame(data=data)
# 删除重复行
dataframe = dataframe.drop_duplicates(subset= ["Name","Age"])
print(dataframe)
# >>>
"""
Name Age
0 Ethan 18
2 Amazon 20
"""
3.5 合并数据帧
merge()方法部分参数说明:
left | DataFrame对象 | ||||||||
right | DataFrame对象 | ||||||||
on | 标签或列表 要联接的字段名。必须在两个DataFrames中都找到。 | ||||||||
how |
|
import pandas as pd
""" 合并数据帧 """
# 创建数据
data1 = {
"Id":[1,2,3,4],
"Name":["Ethan","Winters","SanFrancisco","LosAngeles"]
}
data2 = {
"Id":[1,2,3,4],
"Age":[18,20,22,24]
}
# 创建帧对象
dataframe1 = pd.DataFrame(data1)
dataframe2 = pd.DataFrame(data2)
# 指定"Id"列标签要合并,并并集合并两个数据帧
dataframe = pd.merge(dataframe1,dataframe2,on="Id",how="outer")
print(dataframe)
# >>>
"""
Id Name Age
0 1 Ethan 18
1 2 Winters 20
2 3 SanFrancisco 22
3 4 LosAngeles 24
"""
4.处理缺失值
01 | 指定缺失值 | 创建数据或引入数据时添加na_values参数 |
02 | 清除带缺失值的行数据 | dropna()方法 |
03 | 填充缺失值 | fillna()方法 |
4.1 指定缺失值
默认情况下,pandas除了空值之外还会把 NA、n/a 和 NaN 等当作空数据。但有时候可能用其他的值来代表缺失值,这些其他值在pandas看来并不是缺失值,而是一个真实存在的值。因此,我们可以在读取数据之前,对pandas表明哪一些是缺失值。
nba.csv(包括下文的nba.csv)是经过修改过的,只要了前20行,前10行都的"Height"列标签值都设置为"Nothing"。如图:
import pandas as pd
""" 指定缺失值 """
# 指定缺失值列表
missing_values = ["Nothing"]
# 获取数据并指定缺失值
dataframe = pd.read_csv("nba.csv",na_values = missing_values,encoding="gbk")
# 打印"Height"列标签中哪一些是空数据
judge = dataframe["Height"].isnull()
print(judge)
# >>>
"""
0 True
1 True
2 True
3 True
4 True
5 True
6 True
7 True
8 True
9 True
10 False
11 False
12 False
13 False
14 False
15 False
16 False
17 False
18 False
19 False
Name: Height, dtype: bool
"""
4.2 清除带缺失值的行数据
import pandas as pd
""" 清除带缺失值的行数据 """
# 指定缺失值列表
missing_values = ["Nothing"]
# 获取数据
dataframe = pd.read_csv("nba.csv",na_values=missing_values,encoding="gbk")
# 删除带有缺失值的行数据
dataframe = dataframe.dropna()
print(dataframe)
# >>>
"""
Name Team ... College Salary
10 Jared Sullinger Boston Celtics ... Ohio State 2569260
11 Isaiah Thomas Boston Celtics ... Washington 6912869
12 Evan Turner Boston Celtics ... Ohio State 3425510
13 James Young Boston Celtics ... Kentucky 1749840
14 Tyler Zeller Boston Celtics ... North Carolina 2616975
16 Markel Brown Brooklyn Nets ... Oklahoma State 845059
17 Wayne Ellington Brooklyn Nets ... North Carolina 1500000
18 Rondae Hollis-Jefferson Brooklyn Nets ... Arizona 1335480
19 Jarrett Jack Brooklyn Nets ... Georgia Tech 6300000
"""
4.3 填充缺失值
import pandas as pd
""" 填充缺失值 """
# 指定缺失值列表
missing_values = ["Nothing"]
# 获取数据
dataframe = pd.read_csv("nba.csv",na_values=missing_values,encoding="gbk")
# 获取"Height"这一列数据的中位数
med = dataframe["Height"].median()
# 用med代替掉"Height"的缺失值数据
dataframe["Height"].fillna(med, inplace = True)
print(dataframe["Height"])
# >>>
"""
0 184.5
1 184.5
2 184.5
3 184.5
4 184.5
5 184.5
6 184.5
7 184.5
8 184.5
9 184.5
10 180.0
11 181.0
12 182.0
13 183.0
14 184.0
15 185.0
16 186.0
17 187.0
18 188.0
19 189.0
Name: Height, dtype: float64
"""