目录
一、数据准备
二、缺失值处理
三、清洗数据
四、聚类分析
五、结果评估与分析
一、数据准备
本次实验,是通过实验方法,练习数据清洗方法和聚类分类,使用工具包:
--- numpy
--- pandas
--- scikit learn
---matplotlib
数据表名Market Luxury Brands,数据大小为(48842,,15),数据结构如下:
数据下载地址:http://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data
背景:对用户数据分析,通过聚类方法找出哪些人口统计信息与人群收入高低有关联,针对关联的人口统计信息进行一些营销活动。
二、缺失值处理
通过上面可以看到,数据非常的脏乱,因此需要对数据进行一些清洗工作。但是开始工作前,我们需要了解我们的数据,字段的含义以及数据分布情况。
1、我们通过df = pd.read_csv(),将数据读进来之后,通过df.info可以查看,数据分布情况,
可以看到有部分数据存在缺失,因此后面需要考虑缺失值处理,而且特征名总出现奇怪的破折号,我们稍微对它处理一下,df.columns = df.columns.str.replace('-','') 。
2、字段的含义:
age: 年龄;
workclass:雇主的单位类型,如政府,军队,或私人;
fnlwgt: 人口普查员的ID,因此可以考虑去除
education:最高教育水平;
education_num:最高教育水平数字表示,和education重复了,可以去除其中一个。
marital:婚姻状态;
occupation: 工作类型
relationship:家庭关系;
race:种族
sex: 性别
capital_gain: 资本收益记录
capital_loss: 资本损失记录
hr_per_week: 一周工作时长
country:国籍
income:收入高低
因此,可以发现education_num和fnlwgt是可以去掉的。
3、缺失值情况占比
通过计算各个字段缺失情况如下:
可以发现,有四个字段有出现缺失值情况,workclass、occupation、native-country和income。其中workclass和occupation字段缺失情况一样的,我们需要进一步分析他们值的分布。
4、缺失值特征观察
因此对上面四个特征分别进行进一步的观察,尝试修复缺失值。
1)workclass和Occupation
我们先通过比较两个出现空值的情况是否相同,
(df.workclass.isnull() == df.occupation.isnull()).all()
结果得到false,并不完全相同,接下查看一下哪些地方的值出现了不同。
df.ix[((df.workclass.isnull().astype(int) + df.occupation.isnull().astype(int)) == 1),['workclass','occupation']]
是否是workclass出现Never-worked时,occupation出现为空,因此我们可以将workclass出现Never-worked的地方,对occupation进行空值填充。
df.ix[df.workclass == 'Never-worked',['occupation']] = 'None'
重新比较两个特征出现缺失值的位置时,返回结果为True。但是我们并不知道,workclass在其他地方出现空值的原因。接下来需要从数据中发现一定的规律。从workclass为空时,可以发现出现了很多的年轻人。
而且根据我们经验,工作类型缺失,是和年龄是存在一定关系,因为年龄太小或者退休,工作的都是为空的。因此顺着这条思路,接着往下分析。
将workclass为空和age对比分析
以及workclass非空和age的对比分析
通过对比,确实可以看到有大量的年轻人没有工作,应该是还没有毕业的学生群体在其中。因此基于分布,我们将任何年龄小于24岁,工作类型出现缺失值的填充Never-worked,职业确实为学生。
df.ix[under_24 & no_occuption,['workclass','occupation']] = ['Never-worked','Student']
接下来再观察工作类型出现缺失值和年龄的分布情况:
根据分布可以,看到大于60岁的缺失值表现比较突出。我们来验证猜测是否正确
将工作为空的年龄分布和工作非空的年龄分布进行比较。
age_with_work = df[df.workclass.notnull()].groupby('age').count().max(1)
age_without_work = df[df.workclass.isnull()].groupby('age').count().max(1)
先进行归一化处理
age_with_work = (age_with_work - age_with_work.mean()) / age_with_work.std()
age_without_work = (age_without_work - age_without_work.mean()) / age_without_work.std()
通过age_with_work-age_without_work观察结果。
结果似乎和我们的预想的完全差不多,年龄大于58岁的工作人群小未工作人群,但是年龄在78岁的位置出现了反转,年龄大于78岁的人群工作的占比然后更大。显然结果是有问题的,整个过程没有将年龄的分布考虑进来,因为可能存在一个其中一个年龄段分布极小的情况。
因此,我们查看年龄的分布情况:
果然70岁的年龄分布极小,导致比较不公平。因此将年龄考虑进来
age_with_work = df[df.workclass.notnull()].groupby('age').count().max(1) / df.age.value_counts()
age_without_work = df[df.workclass.isnull()].groupby('age').count().max(1) / df.age.value_counts()
age_with_work = (age_with_work - age_with_work.mean()) / age_with_work.std()
age_without_work = (age_without_work - age_without_work.mean()) / age_without_work.std()
在比较年龄与工作关系分布:
上面分布结果正确的验证了我们的之前的推断,年龄大于60岁,而且没有工作的是退休人群。因此对这部分人群进行缺失值处理。
df.ix[over_60 & no_occuption,['workclass','occupation']] = ['Retired','Retired']
再次观察缺失值分布情况:
相对分布比较均匀,属于正常情况,对于剩下部分进行Unknown填充。
df.ix[no_occuption, ['workclass','occupation']] = ['Unknown','Unknown']
2)Native Country
我们先对所属国家分布情况,进行观察,因为结果分布偏差大,我们取log10查看。
从分布看,数据在USA上存在严重的偏态行为,而且存在很多占比小的的城市,因此后面可以考虑对部分进行合并处理。
和之前方法一样,我们先对出现缺失值的数据进行进一步观察。
似乎没有之前workclass与age那样关系明显,只能通过比对,最后发现race在native country上表现有点不太一样。native country为空时的分布如下
非空的分布:
通过比较发现,Asian-Pac-islander在native country空和非空上表现出比较强的差异性。
我们可以进一步验证这个猜测,通过和之前一样的方法比较race在country为空和非空的分布。
虽然验证了我们的想法,但是似乎并不能帮助我们推测空值。因此对于空值做Unknown处理
df.loc[df['native-country'].isnull(),'native-country'] = 'Unknown'
3)Income
Income特征在本次分析中,算是最重要的特征了,找出高收入人群就靠它了。不过处理之前我还是先看一下我们的特征。
发现很多分类特征的数据类型的是object,而不是categorical data。并且对于categorical data 也需要 进一步向量化,因此接下来先清理一下数据集,对一些多类别的数据进行合并,在对income缺失值处理。
免责声明:本文系网络转载。版权归原作者所有。如涉及版权,请联系删除!