小白学数据分析——数据清洗
数据分析中的数据清洗
数据清洗的自我理解
数据分析的过程中,在进行具体的数据处理、分析和可视化之前,要对数据进行数据的清洗,数据清洗在我的理解就是把数据中的“脏东西”处理掉。这些需要进行处理的数据大概分成一下几种:缺失值、重复值、异常值和数据类型有误的数据。
在我看来数据清洗步骤如下:
【Tips】
1.数据清洗时优先进行缺失值、异常值和数据类型转换的操作,最后进行重复值的处理。
2.在对缺失值、异常值进行处理时要根据业务的需求进行处理,这些处理并不是一成不变的,常见填充有:统计值填充(常用的统计值有均值、中位数、众数)、前/后值填充(一般使用在前后数据存在关联,比如数据是按照时间进行记录的)、零值填充。
3.在数据清洗之前最为重要的对数据表的的查看,要了解表的结构和发现需要处理的值,这样才能将数据清洗彻底。
4.数据量的大小也关系着数据的处理方式。如果总数据量较大,而异常的数据(包括缺失值和异常值)的量较少时可以选择直接删除处理,因为这并不太会影响到最终的分析结果;但是如果总数据量较小,则每个数据都可能影响这分析的结果,这时候就需要费心思去对数据进行处理(可能需要通过其他的关联表去找到想过数据进行填充)
5.在导入数据表后,一般需要将所有列一个个的都进行清洗,来保证数据处理的彻底,有些数据可能在看起来时正常的可以使用的,实则在进行处理时可能会出现问题(比如某列数据在查看时是看起来是数值但其实这列数据的类型却是字符串,这就会导致在进行数值操作无法使用)。
案例学习
(案例以数据清洗为主)
Google play store的app数据分析
数据的初步查看(确定导入数据的字段)
使用文本文档或Excel打开csv文件对文件进行初步的查看,其表的列属性如下:App,Category,Rating,Reviews,Size,Installs,Type,Price,Content Rating,Genres,Last Updated,
Current Ver,Android Ver
分析的字段如下:App,Category,Rating,Reviews,Size,Installs,Type(app名称、app类型、评分、评论数、软件大小、安装数量、收费类型)
数据的导入和查看
代码
# 导包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 数据导入
df = pd.read_csv("./csv/googleplaystore.csv",usecols=(0,1,2,3,4,5,6))
# 数据查看
print(df.head(1))
print(df.shape)
print(df.count())
print(df.describe())
【结果】
App Category Rating
0 Photo Editor & Candy Camera & Grid & ScrapBook ART_AND_DESIGN 4.1
Reviews Size Installs Type
0 159 19M 10,000+ Free
(10841, 7)
App 10841
Category 10841
Rating 9367
Reviews 10841
Size 10841
Installs 10841
Type 10840
dtype: int64
Rating
count 9367.000000
mean 4.193338
std 0.537431
min 1.000000
25% 4.000000
50% 4.300000
75% 4.500000
max 19.000000
【分析】
1.第一个输出结果说明了表的结构,说明我们在导入数据时所选的列都正常的导入了。
2.第二个输出结果说明表的形状,表中一共有10841条记录,每条记录有7个字段。
3.第三个输出结果说明每个字段中非缺失值的个数,说明数据中Rating和Type中存在缺失值,需要进行处理。
4.第四个输出结果说明这些字段中只有Rating字段是数值类型的数据,其他数据要进行数值计算操作前需要进行类型转换。
数据清洗
Category的处理
原则上在处理数据时应该从第一列开始逐个检查并处理,但是对于App这列需要进行的去重的处理,在现实的情况中app的名称是可以相同的,只有表中的所有的内容全部相同才进行重复值删除操作,所以这一步放在所有数据处理完成后再进行数据的删除。先对Category这列进行处理。
数据查看
代码
# 对类型进行查看
df['Category'].value_counts(dropna=False)
【结果】
FAMILY 1972
GAME 1144
TOOLS 843
MEDICAL 463
BUSINESS 460
PRODUCTIVITY 424
PERSONALIZATION 392
COMMUNICATION 387
SPORTS 384
LIFESTYLE 382
FINANCE 366
HEALTH_AND_FITNESS 341
PHOTOGRAPHY 335
SOCIAL 295
NEWS_AND_MAGAZINES 283
SHOPPING 260
TRAVEL_AND_LOCAL 258
DATING 234
BOOKS_AND_REFERENCE 231
VIDEO_PLAYERS 175
EDUCATION 156
ENTERTAINMENT 149
MAPS_AND_NAVIGATION 137
FOOD_AND_DRINK 127
HOUSE_AND_HOME 88
AUTO_AND_VEHICLES 85
LIBRARIES_AND_DEMO 85
WEATHER 82
ART_AND_DESIGN 65
EVENTS 64
PARENTING 60
COMICS 60
BEAUTY 53
1.9 1
Name: Category, dtype: int64
【分析】结果中由单词组成的结果应该都是合理,但是有一条结果为1.9的数据有些异常,所以需要这条记录查找出来看看其产生异常的原因。
异常数据查看
代码
df[df['Category'] == '1.9']
【结果】
App Category Rating Reviews Size Installs Type
10472 Life Made WI-Fi Touchscreen Photo Frame 1.9 19.0 3.0M 1,000+ Free 0
【分析】经过查看可能是因为数据填充错位导致,因为数据量较大而这个异常数据只有一条,所以直接进行数据删除的处理。
异常数据处理
代码
df.drop(index=10472,inplace=True)
df[df['Category'] == '1.9']
【结果】
【分析】再次查看该条记录发现记录已经删除,完成了对Category的清理。
Rating的处理
数据查看
代码
# 对评分进行查看
df.Rating.value_counts(dropna=False)
【结果】
NaN 1474
4.4 1109
4.3 1076
4.5 1038
4.2 952
4.6 823
4.1 708
4.0 568
4.7 499
3.9 386
3.8 303
5.0 274
3.7 239
4.8 234
3.6 174
3.5 163
3.4 128
3.3 102
4.9 87
3.0 83
3.1 69
3.2 64
2.9 45
2.8 42
2.7 25
2.6 25
2.5 21
2.3 20
2.4 19
1.0 16
2.2 14
1.9 13
2.0 12
1.7 8
1.8 8
2.1 8
1.6 4
1.5 3
1.4 3
1.2 1
Name: Rating, dtype: int64
【分析】在结果中1474个数据为缺失数据,所以需要进行数据的填充处理,但是使用什么方式进行填充呢?在我看来最好是使用同一类别软件的均值进行填充。
填充数据准备
【1】计算每种分类的评分均值
代码
# 获取每种类别app的评分的均值
df_category = df.groupby('Category').mean()
df_category.head()
【结果】
【2】获取Rating为缺失值的数据
代码
# 获取rating为空的数据
df_rating_isnull = df[pd.isnull(df['Rating'])]
df_rating_isnull.head()
【结果】
异常数据处理
【处理方式】使用缺失数据的索引定位数据表中Rating为空的值,并使用计算的均值表中的数据进行填充
代码
# 使用行索引对rating为空的值填充
for i in df_rating_isnull.index:
df.loc[i,'Rating']=df_category.loc[df.loc[i,'Category'],'Rating']
# 查看填充后结果
print(df.loc[23,])
df.Rating.value_counts(dropna=False)
【结果】
App Mcqueen Coloring pages
Category ART_AND_DESIGN
Rating 4.35806
Reviews 61
Size 7.0M
Installs 100,000+
Type Free
Name: 23, dtype: object
4.400000 1109
4.300000 1076
4.500000 1038
4.200000 952
4.600000 823
4.100000 708
…
2.100000 8
1.800000 8
1.700000 8
4.244000 7
1.600000 4
4.358065 3
1.500000 3
1.400000 3
4.155172 2
4.389032 1
1.200000 1
Name: Rating, Length: 71, dtype: int64
【分析】通过处理后,原本第一个Rating为缺失值的数据(索引为23)的Rating已经被填充了;通过查看整列的情况已经不在含有缺失值NaN了。
Reviews的处理
数据查看
代码
# 对reviews检查
df.Reviews.value_counts(dropna=False)
【结果】
0 596
1 272
2 214
3 175
4 137
5 108
6 97
7 90
8 74
9 65
10 64
…
2059 1
315390 1
69013 1
271908 1
4831125 1
1336246 1
124970 1
5427 1
122498 1
9663 1
Name: Reviews, Length: 6001, dtype: int64
数据类型查看
代码
print(type(df.loc[0,'Reviews']))
df_Reviews_isnum = df['Reviews'].str.isnumeric()
print(df_Reviews_isnum.value_counts())
【结果】
<class ‘str’>
True 10840
Name: Reviews, dtype: int64
【分析】对数据进行数据类型的判断,Reviews中的数据是字符串类型,但按照其数据运算的角度这列数据因该是数值类型的,所以需要进行数据类型的转换。
数据处理
代码
df['Reviews'] = df['Reviews'].astype('i8')
df.describe()
【结果】
【分析】Reviews数据列转换成了数值类型,通过describe函数可以查看其常用的统计值。
Size的处理
数据查看
代码
# 对size进行查看和处理
df.Size.value_counts(dropna=False)
【结果】
Varies with device 1695
11M 198
12M 196
14M 194
13M 191
15M 184
17M 160
19M 154
26M 149
16M 149
…
173k 1
862k 1
122k 1
144k 1
778k 1
475k 1
154k 1
775k 1
44k 1
695k 1
Name: Size, Length: 461, dtype: int64
【分析】在数据中存在两种问题:1.为了对数据计算操作,所以需要对数据中的M和k进行处理,处理成统一的单位方便比较计算。2.数据中还有字符串,需要将字符串先设置为NaN(NaN在后续统计计算时不会参与运算,如果设置为0则会影响统计值的计算)之后在使用数据均值进行填充。
异常数据处理
【处理步骤】
1.将数据中M替换成e+6,k替换成e+3,将数据中的字符串替换成NaN。
代码
replace_dict= {'M':'e+6','k':'e+3'}
df['Size'] = df['Size'].str.replace('M','e+6')
df['Size'] = df['Size'].str.replace('k','e+3')
df['Size'] = df['Size'].replace('Varies with device',np.NaN)
df.Size.value_counts(dropna=False)
【结果】
NaN 1695
11e+6 198
12e+6 196
14e+6 194
13e+6 191
15e+6 184
17e+6 160
19e+6 154
16e+6 149
26e+6 149
…
951e+3 1
34e+3 1
353e+3 1
717e+3 1
24e+3 1
642e+3 1
953e+3 1
27e+3 1
1020e+3 1
317e+3 1
Name: Size, Length: 461, dtype: int64
2.将数据中数值形式的字符串转换成数值类型的数据。
代码
df['Size'] = df['Size'].astype('f8')
df.Size.value_counts(dropna=False)
【结果】
NaN 1695
11000000.0 198
12000000.0 196
14000000.0 194
13000000.0 191
15000000.0 184
17000000.0 160
19000000.0 154
26000000.0 149
16000000.0 149
…
421000.0 1
629000.0 1
460000.0 1
280000.0 1
237000.0 1
190000.0 1
55000.0 1
253000.0 1
511000.0 1
322000.0 1
Name: Size, Length: 460, dtype: int64
3.使用数据的均值填充数据中的缺失数据。
代码
# 平均数充值
df['Size'].fillna(value=df['Size'].mean(),inplace=True)
df.Size.value_counts(dropna=False)
【结果】
2.151653e+07 1695
1.100000e+07 198
1.200000e+07 196
1.400000e+07 194
1.300000e+07 191
1.500000e+07 184
1.700000e+07 160
1.900000e+07 154
2.600000e+07 149
1.600000e+07 149
…
2.530000e+05 1
9.130000e+05 1
5.110000e+05 1
8.090000e+05 1
9.400000e+05 1
5.440000e+05 1
4.290000e+05 1
9.700000e+04 1
4.120000e+05 1
8.110000e+05 1
Name: Size, Length: 460, dtype: int64
处理后数据查看
代码
df.describe()
【结果】
Installs的处理
数据查看
代码
df['Installs'].value_counts()
【结果】
【分析】数据在直观看来是容易理解的,但是数据中的,和+计算机在处理的时候却识别不出来,所以需要将数据中的这些符号进行处理并且将数据转换成数值类型。
异常数据处理
代码
# 对安装数量进行清洗,只需要去掉,和+即可
df['Installs'] = df['Installs'].str.replace(',','')
df['Installs'] = df['Installs'].str.replace('+','')
df['Installs'] = df['Installs'].astype('i8')
df.describe()
【结果】
Type的处理
数据查看
代码
# 对Type检查
df.Type.value_counts(dropna=False)
【结果】
Free 10039
Paid 800
NaN 1
Name: Type, dtype: int64
【分析】数据中存在NaN,所以要对缺失值进行处理
异常数据查看
代码
df[pd.isnull(df['Type'])]
【结果】
App Category Rating Reviews Size Installs Type
9148 Command & Conquer: Rivals FAMILY 4.192272 0 2.151653e+07 0 NaN
【分析】在这条数据中其中下载量Installs和Reviews均是0,说明这款软件就没有人使用过,并且只有这一条记录,所以可以使用删除进行清洗。
异常数据处理
代码
df.drop(index=9148,inplace=True)
df[df['App'] == 'Command & Conquer: Rivals']
【结果】
数据处理后查看数据
代码
df.Type.value_counts(dropna=False)
【结果】
Free 10039
Paid 800
Name: Type, dtype: int64
重复数据的处理
重复数据查看
代码
df[df.duplicated()]
【结果】
【分析】这里一共有485条重复的数据,这些数据所有字段都一样,相同的数据没有额外的价值,所以直接进行删除的方式清洗。
重复数据处理
代码
# 删除重复值
df.drop(df[df.duplicated()].index,inplace=True)
df[df.duplicated()]
【结果】
清理后数据再查看
代码
# 数据再查看
df.describe()
df.head(10)
【结果】
数据处理和分析
(该案例以数据清洗为主,则对数据处理和分析进行简单的操作)
【1】app商店中免费和付费应用的占比情况
代码
df_groupby_type = df.groupby('Type').count()['Installs']
print(df_groupby_type )
df_groupby_type.plot(kind='pie')
plt.show()
【结果】
Type
Free 9589
Paid 765
Name: Installs, dtype: int64
【分析】在app商店中免费的应用占比较大,免费的app还是市场的主流。
【2】app商店中的各类app的下载量分析
代码
# 数据处理
df_category_install = df.groupby('Category').mean().sort_values('Installs',ascending=True)['Installs']
# 获取统计数据
category = df_category_install.index
install_amount = df_category_install.values
# 绘图
plt.figure(figsize=(20, 16), dpi=100)
rects = plt.barh(range(len(category)), [float(i) for i in install_amount], height=0.8, color='blue')
plt.yticks(range(len(category)), category)
for rect in rects:
width = rect.get_width() + 0.8
plt.text(width, rect.get_y() + 0.8 / 2, str(width), va='center')
plt.show()
【结果】
【分析】在app商店中平均下载量位于前三名的是:娱乐类、社会类和视频类的应用软件。
【3】分析app商店中应用的评论比率
评论比率:评论人数和下载人数的比例(以均值计算)——组合分组(使用付费情况和软件分类共同分析)
代码
# 获取分组数据
df_TyCa = df.groupby(['Type','Category']).mean()
# 数据的计算
df_TyCa_port = (df_TyCa['Reviews'] / df_TyCa['Installs']).sort_values(ascending=False)
# 对前20进行显示
print(df_TyCa_port[:20])
#对前10进行绘图
df_TyCa_port[:10].plot(kind='pie')
【结果】
【分析】在所有的软件中收费的评论安装比较高,即付费软件的用户的评论率价高;其中付费的应用中家庭类、视频播放类、天气类软件的评论率位于前三;在免费的软件中喜剧/动漫类的软件评论率较高
总结
数据清洗是数据处理和分析的基础,只有把数据清洗的准确,才能做出尽可能准确的分析。
希望大佬们对我这个小白的学习记录进行批评与指正,哈哈????!
上一篇: 数据分析之清洗和整理
下一篇: UDF、UDAF、UDTF