楼主: 时光人
3386 24

[网帖精选] Python数据清洗 [推广有奖]

  • 3关注
  • 34粉丝

院士

23%

还不是VIP/贵宾

-

威望
1
论坛币
26907 个
通用积分
428.9260
学术水平
95 点
热心指数
109 点
信用等级
91 点
经验
39960 点
帖子
1629
精华
3
在线时间
579 小时
注册时间
2019-2-25
最后登录
2023-4-26

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

CDA网校:数据科学、人工智能从业者的在线大学。

数据科学(Python/R/Julia)数据分析、机器学习、深度学习

包含:类型转换和冗余数据删除,缺失值识别与处理内容

数据分析过程中最头疼也是工作量最大的部分算是探索和清洗了——探索的目的是了解数据,了解数据背后隐藏的规律;洗的目的则是为了让干净的数据进入分析或建模的下一个环节。小编将通过三篇文章,详细讲解工作中常规的数据清洗方法,包括数据类型的转换,重复数据的处理,缺失值的处理以及异常数据的识别和处理。这是Python数据清洗系列的第一篇文章,主要分享的内容包括——数据类型的转换and冗余数据的识别和处理.

        数据类型的判断和转换

        如下表所示,为某公司用户的个人信息和交易数据,涉及的字段为用户id、性别、年龄、受教育水平、交易金额和交易日期。从表面上看,似乎没有看出数据背后可能存在的问题,那接下来就将其读入到Python中,并通过探索的方式发现数据中的问题。

        

        读取数据,以及查看数据规模、查看数据中各变量的数据类型的代码如下:

  1. # 导入第三方包
  2. import pandas as pd

  3. # 读入外部数据
  4. data3 = pd.read_excel(io=r'C:\Users\Administrator\Desktop\datas\data3.xlsx')
  5. # 查看数据的规模
  6. data3.shape
  7. out:
  8. (3000, 6)

  9. # 查看表中各变量的数据类型
  10. # data3.dtypes
复制代码

out:

        表中各变量的数据类型如表下表所示:

        


        上述代码利用shape“方法”返回了数据集的规模,即该数据包含3000行6列;通过dtypes“方法”则返回了数据集中各变量的数据类型——除id变量和age变量为数值型,其余变量均为字符型。直观上能够感受到一点问题,即数据类型不对,例如用户id应该为字符型,消费金额custom_amt为数值型,订单日期为日期型。如果发现数据类型不对,如何借助于Python工具实现数据类型的转换呢?可参照如下代码的实现。

  1. # 数值型转字符型
  2. data3['id'] = data3['id'].astype(str)
  3. # 字符型转数值型
  4. data3['custom_amt'] = data3['custom_amt'].str[1:].astype(float)
  5. # 字符型转日期型
  6. data3['order_date'] = pd.to_datetime(data3['order_date'], format = '%Y年%m月%d日')

  7. # 重新查看数据集的各变量类型
  8. data3.dtypes
复制代码

out:

        这些数据经过处理后,各个字段的数据类型如下表所示:

        


        如上结果所示,三个变量全都转换成了各自所期望的数据类型。astype“方法”用于数据类型的强制转换,可选择的常用转换类型包括str(表示字符型)、float(表示浮点型)和int(表示整型)。由于消费金额custom_amt变量中的值包含人民币符号“¥”,所以在数据类型转换之前必须将其删除(通过字符串的切片方法删除,[1:]表示从字符串的第二个元素开始截断)。对于字符转日期问题,推荐使用更加灵活的to_datetime函数,因为它在format参数的调节下,可以识别任意格式的字符型日期值。

        需要注意的是,Python中的函数有两种表现形式,一种是常规理解下的函数(语法为func(parameters),如to_datetime函数),另一种则是“方法”(语法为obj.func(parameters),如dtypes和astype“方法”)。两者的区别在于 “方法”是针对特定对象的函数(即该“方法”只能用在某个固定类型的对象上),而函数并没有这方面的限制。

        基于如上类型的转换结果,最后浏览一下数据的展现形式:

# 预览数据的前5行data3.head()

        


        冗余数据的判断和处理

        如上过程是对数据中各变量类型的判断和转换,除此还需要监控表中是否存在“脏”数据,如冗余的重复观测和缺失值等。可以通过duplicated“方法”进行 “脏”数据的识别和处理。仍然对上边的data3数据为例进行操作,具体代码如下所示。

  1. # 判断数据中是否存在重复观测
  2. data3.duplicated().any()

  3. out:
  4. False
复制代码

        如上结果返回的是False,说明该数据集中并不存在重复观测。假如读者利用如上的代码在数据集中发现了重复观测,可以使用drop_duplicates“方法”将冗余信息删除。

        需要说明的是,在使用duplicated“方法”对数据行作重复性判断时,会返回一个与原数据行数相同的序列(如果数据行没有重复,则对应False,否则对应True),为了得到最终的判断结果,需要再使用any“方法”(即序列中只要存在一个True,则返回True)。

        duplicated“方法”和drop_duplicates“方法”都有一个非常重要的参数,就是subset。默认情况下不设置该参数时,表示对数据的所有列进行重复性判断;如果需要按指定的变量做数据的重复性判断时,就可以使用该参数指定具体的变量列表。举例如下:


  1. # 构造数据
  2. df = pd.DataFrame(dict(name = ['张三','李四','王二','张三','赵五','丁一','王二'],
  3. gender = ['男','男','女','男','女','女','男'],
  4. age = [29,25,27,29,21,22,27],
  5. income = [15600,14000,18500,15600,10500,18000,13000],
  6. edu = ['本科','本科','硕士','本科','大专','本科','硕士']))
  7. # 查看数据
  8. df
复制代码

        


        目测有两条数据完全一样,就是用户张三,如果直接使用drop_duplicates“方法”,而不做任何参数的修改时,将会删除第二次出现的用户张三。代码如下:

  1. # 默认情况下,对数据的所有变量进行判断
  2. df.drop_duplicates()
复制代码

        


        假设在数据清洗中,用户的姓名和年龄相同就认为是重复数据,那么该如何基于这两个变量进行重复值的删除呢?此时就需要使用subset参数了,代码如下:

  1. df.drop_duplicates(subset=['name','age'])
复制代码

        


        需要注意的是,使用drop_duplicates“方法”删除重复数据,并不能直接影响到原始数据,即原始数据中还是存在重复观测的。如需使drop_duplicates“方法”的删除功能作用在原始数据中,必须将inplace参数设置为True。




关注“AIU人工智能”公众号,回复“白皮书”获取数据分析、大数据、人工智能行业白皮书及更多精选学习资料!


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝


回帖推荐

145xyz 发表于13楼  查看完整内容

很实用的信息

peyzf 发表于25楼  查看完整内容

学习一下

lhsin 发表于21楼  查看完整内容

感谢分享

chunxilu 发表于11楼  查看完整内容

好文章,我收藏了。

东方祥 发表于7楼  查看完整内容

模型和算法只是逼近这个上限

东方祥 发表于6楼  查看完整内容

数据和特征决定了机器学习的上限

东方祥 发表于4楼  查看完整内容

了解数据,了解数据背后隐藏的规律

老寒腿不寒i 发表于3楼  查看完整内容

谢谢你的分享
已有 3 人评分经验 论坛币 学术水平 热心指数 信用等级 收起 理由
yunnandlg + 100 精彩帖子
chunxilu + 1 + 1 + 1 + 1 精彩帖子
cheetahfly + 100 精彩帖子

总评分: 经验 + 200  论坛币 + 1  学术水平 + 1  热心指数 + 1  信用等级 + 1   查看全部评分

沙发
时光人 学生认证  发表于 2019-12-4 09:26:57 |只看作者 |坛友微信交流群

缺失值的识别                 

判断一个数据集是否存在缺失观测,通常从两个方面入手,一个是变量的角度,即判断每个变量中是否包含缺失值;另一个是数据行的角度,即判断每行数据中是否包含缺失值。关于缺失值的判断可以使用isnull方法。下面使用isnull方法对data3数据(数据可至中---下载)进行判断,统计输出的结果如下表所示。         

  1. # 判断各变量中是否存在缺失值
  2. data3.isnull().any(axis = 0)
  3. # 各变量中缺失值的数量
  4. data3.isnull().sum(axis = 0)
  5. # 各变量中缺失值的比例
  6. data3.isnull().sum(axis = 0)/data3.shape[0]
复制代码


如上结果所示,数据集data3中有三个变量存在缺失值,即gender、age和edu,它们的缺失数量分别为136、100和1,927,缺失比例分别为4.53%、3.33%和64.23%。         

需要说明的是,判断数据是否为缺失值NaN,可以使用isnull“方法”,它会返回与原数据行列数相同的矩阵,并且矩阵的元素为bool类型的值,为了得到每一列的判断结果,仍然需要any“方法”(且设置“方法”内的axis参数为0);统计各变量的缺失值个数可以在isnull的基础上使用sum“方法”(同样需要设置axis参数为0);计算缺失比例就是在缺失数量的基础上除以总的样本量(shape方法返回数据集的行数和列数,[0]表示取出对应的数据行数)。

读者可能对代码中的“axis=0”感到困惑,它代表了什么?为什么是0?是否还可以写其他值?下面通过图表的形式来说明axis参数的用法:         

   


假设上图为学生的考试成绩表,如果直接对成绩表中的分数进行加和操作,得到的是所有学生的分数总和(很显然没有什么意义),如果按学生分别计算总分,将是上图从左到右的转换。该转换的特征是列数发生了变化(可以是列数减少,也可以是列数增多),类似于在水平方向上受了外部的压力或拉力,这样的外力就理解为轴axis为1的效果(便于理解,可以想象为飞机在有动力的情况下,可以保持水平飞行状态)。                        

                             


同样对于如上的学生成绩表,如果直接对成绩表中的分数计算平均值,得到的是所有学生的平均分数(很显然也没有什么意义),如果按学科分别计算平均分,将是上图中从上到下的转换。该转换的特征是行数发生了变化(可以是行数减少,也可以是行数增多),类似于在垂直方向上受了外部的挤压或拉伸,这样的外力就理解为轴axis为0的效果(便于理解,可以想象为飞机在没有动力的情况下,呈下降趋势)。                                         

如上是关于变量方面的缺失值判断过程,还可以利用下方的代码识别数据行的缺失值分布情况:                                 

# 判断数据行中是否存在缺失值

如上结果所示,返回True值,说明data3中的数据行存在缺失值。代码中使用了两次any“方法”,第一次用于判断每一行对应的True(即行内有缺失值)或False值(即行内没有缺失值);第二次则用于综合判断所有数据行中是否包含缺失值。同理,进一步还可以判断缺失行的具体数量和占比,代码如下:                                         

  1. # 缺失观测的行数
  2. data3.isnull().any(axis = 1).sum()
  3. # 缺失观测的比例
  4. data3.isnull().any(axis = 1).sum()/data3.shape[0]
复制代码

                                       


如上结果所示,3000行的数据集中有2024行存在缺失值,缺失行的比例约67.47%。不管是变量角度的缺失值判断,还是数据行角度的缺失值判断,一旦发现缺失值,都需要对其作相应的处理,否则一定程度上都会影响数据分析或挖掘的准确性。                                                         

缺失值的处理办法                                                

通常对于缺失值的处理,最常用的方法无外乎删除法、替换法和插补法。删除法是指将缺失值所在的观测行删除(前提是缺失行的比例非常低,如5%以内),或者删除缺失值所对应的变量(前提是该变量中包含的缺失值比例非常高,如70%左右);替换法是指直接利用缺失变量的均值、中位数或众数替换该变量中的缺失值,其好处是缺失值的处理速度快,弊端是易产生有偏估计,导致缺失值替换的准确性下降;插补法则是利用有监督的机器学习方法(如回归模型、树模型、网络模型等)对缺失值作预测,其优势在于预测的准确性高,缺点是需要大量的计算,导致缺失值的处理速度大打折扣。下面将选择删除法、替换法和插补法对缺失值进行处理,代码如下:                                                         

  1. # 删除字段 -- 如删除缺失率非常高的edu变量
  2. data3.drop(labels = 'edu', axis = 1, inplace=True)
  3. # 数据预览
  4. data3.head()
复制代码

                                                      


如上结果所示,表中的edu变量已被成功删除。对于字段的删除可以选择drop“方法”,其中labels参数用于指定需要删除的变量名称,如果是多个变量,则需要将这些变量名称写在一对中括号内(如['var1','var2','var3']);删除变量一定要设置axis参数为1,因为变量个数发生了变化(所以,借助于axis参数也可以删除观测行啦);inplace则表示是否原地修改,即是否直接将原表中的字段进行删除,这里设置为True,如果设置为False,则将删除变量的预览效果输出来,而非真正改变原始数据。                                                                        


  1. # 删除观测,-- 如删除age变量中所对应的缺失观测
  2. data3_new = data3.drop(labels = data3.index[data3['age'].isnull()],

  3. axis = 0)
  4. # 查看数据的规模
  5. data3_new.shapeout:(2900, 5)
复制代码

如上结果所示,利用drop“方法”实现了数据行的删除,但必须将axis参数设置为0,而此时的labels参数则需要指定待删除的行编号。这里的行编号是借助于index“方法”(用于返回原始数据的行编号)和isnull“方法”(用于判断数据是否为缺失状态,如果是缺失则返回True)实现的,其逻辑就是将True对应的行编号取出来,传递给labels参数。                                                                 

如果变量的缺失比例非常大,或者缺失行的比例非常小时,使用删除法是一个不错的选择,反之,将会丢失大量的数据信息而得不偿失。接下来讲解如何使用替换法处理缺失值,代码如下:                                                                        


  1. # 替换法处理缺失值
  2. data3.fillna(value = {'gender': data3['gender'].mode()[0],

  3. # 使用性别的众数替换缺失性别
  4. 'age':data3['age'].mean()

  5. # 使用年龄的平均值替换缺失年龄
  6. }, inplace = True # 原地修改数据 )

  7. # 再次查看各变量的缺失比例
  8. data3.isnull().sum(axis = 0)
复制代码

                                                                              


如上结果所示,采用替换法后,原始数据中的变量不再含有缺失值。缺失值的填充使用的是fillna“方法”,其中value参数可以通过字典的形式对不同的变量指定不同的值。需要强调的是,如果计算某个变量的众数,一定要使用索引技术,例如代码中的[0],表示取出众数序列中的第一个(我们知道,众数是指出现频次最高的值,假设一个变量中有多个值共享最高频次,那么Python将会把这些值以序列的形式存储起来,故取出指定的众数值,必须使用索引)。                                                                                         

正如前文所说,虽然替换法思想简单、效率高效,但是其替换的值往往不具有很高的准确性,于是出现了插补方法。该方法需要使用机器学习算法,不妨以KNN算法为例,对Titanic数据集中的Age变量做插补法完成缺失值的处理。代码如下:                                                                                 


  1. # 读取数据
  2. titanic = pd.read_csv('Titanic.csv')
  3. # 删除缺失严重的Cabin变量
  4. titanic.drop(labels='Cabin', axis = 1,

  5. inplace=True)
  6. # 根据Embarked变量,删除对应的缺失行
  7. titanic.dropna(subset=['Embarked'], inplace=True)

  8. # 删除无关紧要的变量(这些变量对后面预测年龄没有太多的帮助)

  9. titanic.drop(labels=['PassengerId','Name','Ticket','Embarked'], axis = 1, inplace=True)

  10. # 将字符型的性别变量映射为数值变量
  11. titanic.Sex = titanic.Sex.map({'male':1, 'female':0})

  12. # 将数据拆分为两组,一是年龄缺失组,二是年龄非缺失组,后续基于非缺失值构建KNN模型,再对缺失组做预测

  13. nomissing = titanic.loc[~titanic.Age.isnull(),]missing = titanic.loc[titanic.Age.isnull(),]

  14. # 导入机器学习的第三方包
  15. from sklearn import neighbors

  16. # 提取出所有的自变量
  17. X = nomissing.columns[nomissing.columns != 'Age']

  18. # 构建模型
  19. knn = neighbors.KNeighborsRegressor()

  20. # 模型拟合
  21. knn.fit(nomissing[X], nomissing.Age)

  22. # 年龄预测
  23. pred_age = knn.predict(missing[X])
复制代码

使用道具

藤椅
老寒腿不寒i 发表于 2019-12-4 10:21:11 来自手机 |只看作者 |坛友微信交流群
时光人 发表于 2019-12-4 09:26
CDA网校:数据科学、人工智能从业者的在线大学。[/backcolor ...
谢谢你的分享

使用道具

板凳
东方祥 企业认证  发表于 2019-12-4 11:25:10 |只看作者 |坛友微信交流群
了解数据,了解数据背后隐藏的规律

使用道具

报纸
gudure 学生认证  发表于 2019-12-4 11:25:46 |只看作者 |坛友微信交流群

使用道具

地板
东方祥 企业认证  发表于 2019-12-4 11:26:10 |只看作者 |坛友微信交流群
数据和特征决定了机器学习的上限

使用道具

7
东方祥 企业认证  发表于 2019-12-4 11:26:18 |只看作者 |坛友微信交流群
模型和算法只是逼近这个上限

使用道具

8
雨季不在了 学生认证  发表于 2019-12-4 22:48:17 |只看作者 |坛友微信交流群

使用道具

9
zoomivy 发表于 2019-12-5 07:47:26 |只看作者 |坛友微信交流群
谢谢分享

使用道具

10
Terry950901 在职认证  发表于 2019-12-5 08:52:05 |只看作者 |坛友微信交流群
感谢分享~

使用道具

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-4-26 10:22