机器学习手册-(数据整理)(三)

写作前言:

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

目录

1.创建数据帧

1.1 采用列表结构添加数据

1.2 采用字典结构添加数据

2.描述数据

2.1 查看数据集描述性统计量

2.2 计算列标签描述性统计量

2.3 根据值对行分组

2.4 数据排序

3.选择数据帧

3.1 根据索引选择行

3.2 根据条件语句选择行

3.3 根据行/列名删除行/列

3.4 删除重复行

3.5 合并数据帧

4.处理缺失值

4.1 指定缺失值

4.2 清除带缺失值的行数据

4.3 填充缺失值


在前章介绍完“加载数据”后,就开始我们的“数据整理”。

“数据整理”经常用于描述将原始数据转换成组织合理的、整洁的形式以供后面的使用。同时,“数据整理”是“数据预处理”里的一个关键步骤。

在整理数据中,我们用到的数据结构是数据帧,可通过第三方模块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"] # 指定列标签

计算最小值min()方法
计算最大值max()方法
计算总和sum()方法
计算平均值mean()方法
计算计数值count()方法
计算方差var()方法
计算标准差std()方法
计算峰态kurt()方法
计算偏态skew()方法
计算平均值标准误差sem()方法
计算众数mode()方法
计算中位数median()方法
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()方法部分参数说明:

leftDataFrame对象
rightDataFrame对象
on

标签或列表

要联接的字段名。必须在两个DataFrames中都找到。

how
left仅使用左框架中的关键帧
right仅使用右侧框架中的关键帧
outer使用两个帧的键的并集(默认)
inner使用两个帧中关键帧的交集

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
"""

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃掉鹅咩里啃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值