一个专业的数据分析,他的定位应该是一个“谋士”,所谓谋士,应该运筹帷幄,决胜千里,不出五尺书堂,便知天下大势。
我们现在已经从IT(Information Technology)时代进入了DT(Data Technology)时代。我们有能力低成本的收集和存储大量的数据,从而衍生出数据分析这个行业。
数据分析最重要的作用是从数据里面寻求真正有价值的信息,并帮助我们作出合理的决策。
为了更好的了解数据分析师这个岗位,本节课我们将以某招聘网站的2017年数据分析师职位数据为基础,进行数据分析。
一、数据基本情况
我们先了解一下数据的基本信息:
因为csv文件中带有中文字符而产生字符编码错误,造成读取文件错误,在这个时候,我们可以尝试将pd.read_csv()函数的encoding参数设置为"gbk"。
%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
# 导入数据
path = r'C:\Users\lin-a\Desktop\data\analyse_spider.csv'
data = pd.read_csv(path,encoding='GBK')
# 查看数据基本情况
print(data.shape)
data.head()
(6876, 14)
city | companyId | companySize | businessZones | firstType | secondType | education | industryField | positionId | positionAdvantage | positionName | positionLables | salary | workYear | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 上海 | 8581 | 2000人以上 | ['张江'] | 技术 | 数据开发 | 硕士 | 移动互联网 | 2537336 | 知名平台 | 数据分析师 | ['分析师', '数据分析', '数据挖掘', '数据'] | 7k-9k | 应届毕业生 |
1 | 上海 | 23177 | 500-2000人 | ['五里桥', '打浦桥', '制造局路'] | 技术 | 数据开发 | 本科 | 金融 | 2427485 | 挑战机会,团队好,与大牛合作,工作环境好 | 数据分析师-CR2017-SH2909 | ['分析师', '数据分析', '数据挖掘', '数据'] | 10k-15k | 应届毕业生 |
2 | 上海 | 57561 | 50-150人 | ['打浦桥'] | 设计 | 数据分析 | 本科 | 移动互联网 | 2511252 | 时间自由,领导nic | 数据分析师 | ['分析师', '数据分析', '数据'] | 4k-6k | 应届毕业生 |
3 | 上海 | 7502 | 150-500人 | ['龙华', '上海体育场', '万体馆'] | 市场与销售 | 数据分析 | 本科 | 企业服务,数据服务 | 2427530 | 五险一金 绩效奖金 带薪年假 节日福利 | 大数据业务分析师【数云校招】 | ['商业', '分析师', '大数据', '数据'] | 6k-8k | 应届毕业生 |
4 | 上海 | 130876 | 15-50人 | ['上海影城', '新华路', '虹桥'] | 技术 | 软件开发 | 本科 | 其他 | 2245819 | 在大牛下指导 | BI开发/数据分析师 | ['分析师', '数据分析', '数据', 'BI'] | 2k-3k | 应届毕业生 |
数据共包含14列,先看一下每一列的含义:
- city:城市
- companyId:公司ID
- companySize:公司规模
- CbusinessZones:公司所在商圈
- firstType:职位所属一级类目
- secondType:职业所属二级类目
- education:学历要求
- industryField:公司所属领域
- positionId:职位ID
- positionAdvantage:职位福利
- positionName:职位名称
- positionLables:职位标签
- salary:薪水
- workYear:工作年限要求
查看数据的具体情况:
# 查看数据具体情况
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6876 entries, 0 to 6875
Data columns (total 14 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 city 6876 non-null object
1 companyId 6876 non-null int64
2 companySize 6876 non-null object
3 businessZones 4853 non-null object
4 firstType 6869 non-null object
5 secondType 6870 non-null object
6 education 6876 non-null object
7 industryField 6876 non-null object
8 positionId 6876 non-null int64
9 positionAdvantage 6876 non-null object
10 positionName 6876 non-null object
11 positionLables 6844 non-null object
12 salary 6876 non-null object
13 workYear 6876 non-null object
dtypes: int64(2), object(12)
memory usage: 752.2+ KB
二、数据分析目标
数据分析的大忌是不知道分析方向和目的,拿着一堆数据不知所措。一切数据分析都是以业务为核心目的,而不是以数据为目的。
所以,我们应该先定分析的目标,然后再处理数据。
我们本案例的目标很简单,就是根据该数据,分析影响薪资的因素:
- 地区对数据分析师的薪酬的影响;
- 学历对数据分析师的薪酬的影响;
- 工作年限对数据分析师的薪酬的影响。
三、数据清洗
缺失值
数据的缺失值在很大程度上会影响数据的分析结果,如果某一个字段缺失值超过一半的时候,我们就可以将这个字段删除了,因为缺失过多就没有业务意义了。
注意:并不是,只要含有有缺失值的时候,我们就要将数据删除,如果数据量比较少、缺失值不多,并且对我们的分析指标没有实际影响时,我们就可以将其保留。
# 查看数据具体情况
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6876 entries, 0 to 6875
Data columns (total 14 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 city 6876 non-null object
1 companyId 6876 non-null int64
2 companySize 6876 non-null object
3 businessZones 4853 non-null object
4 firstType 6869 non-null object
5 secondType 6870 non-null object
6 education 6876 non-null object
7 industryField 6876 non-null object
8 positionId 6876 non-null int64
9 positionAdvantage 6876 non-null object
10 positionName 6876 non-null object
11 positionLables 6844 non-null object
12 salary 6876 non-null object
13 workYear 6876 non-null object
dtypes: int64(2), object(12)
memory usage: 752.2+ KB
通过结果我们可以看出:一共有6876个数据,其中businessZones、firstType、secondType,positionLables都存在为空的情况。companyId和positionId为数字,其他都是字符串。
从数量上可以看出,businessZones列的数据缺失量比较大,需要将该列数据删除。
其他三列的缺失值的总数量为45,并不会影响整体分析效果,我们可以删除这45条数据。
%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
# 导入数据
path = r'C:\Users\lin-a\Desktop\data\analyse_spider.csv'
data = pd.read_csv(path,encoding='GBK')
# 删除缺失值的数据列businessZones
data.drop(columns='businessZones',axis=1,inplace=True)
# 同时删除缺失值的行
data.dropna(inplace=True)
data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 6837 entries, 0 to 6875
Data columns (total 13 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 city 6837 non-null object
1 companyId 6837 non-null int64
2 companySize 6837 non-null object
3 firstType 6837 non-null object
4 secondType 6837 non-null object
5 education 6837 non-null object
6 industryField 6837 non-null object
7 positionId 6837 non-null int64
8 positionAdvantage 6837 non-null object
9 positionName 6837 non-null object
10 positionLables 6837 non-null object
11 salary 6837 non-null object
12 workYear 6837 non-null object
dtypes: int64(2), object(11)
memory usage: 747.8+ KB
处理完空值之后,数据还剩6837条,13列。
重复值
处理完空值以后,我们还需要注意另外一个会影响我们分析结果的因素,就是重复值。
我们来看一下计算一下重复的数据,并将其删除。
使用data.duplicated()方法判断每一行是否重复,然后使用data.duplicated()[data.duplicated()==True]取出重复行,最后使用len()计算重复的数据。
%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
# 导入数据
path = r'C:\Users\lin-a\Desktop\data\analyse_spider.csv'
data = pd.read_csv(path,encoding='GBK')
# 删除缺失值的数据列businessZones
data.drop(columns='businessZones',axis=1,inplace=True)
# 同时删除缺失值的行
data.dropna(inplace=True)
# 计算重复的数据数量
print(len(data.duplicated()[data.duplicated()==True]))
# 删除重复数据
data.drop_duplicates(inplace=True)
data.info()
1830
<class 'pandas.core.frame.DataFrame'>
Int64Index: 5007 entries, 0 to 6766
Data columns (total 13 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 city 5007 non-null object
1 companyId 5007 non-null int64
2 companySize 5007 non-null object
3 firstType 5007 non-null object
4 secondType 5007 non-null object
5 education 5007 non-null object
6 industryField 5007 non-null object
7 positionId 5007 non-null int64
8 positionAdvantage 5007 non-null object
9 positionName 5007 non-null object
10 positionLables 5007 non-null object
11 salary 5007 non-null object
12 workYear 5007 non-null object
dtypes: int64(2), object(11)
memory usage: 547.6+ KB
共有1830条重复的数据,使用data.drop_duplicates()删除后,还剩5007条数据。
数据的缺失值和重复值,是我们在分析之前必须要做,因为,他们的存在会很大程度上影响我们的分析结果。
四、整理和数据分析
我们的第一个任务是薪酬分布情况,所以我们先来整理这个数据。
薪资字段格式基本分为15k-25k和15k以上这两种,并且都是字符串。
如果我们只想要薪资下限数据或者薪资上限数据时,怎么办呢?
最好的方式就将salary薪资字段按照最高薪水和最低薪水拆成两列,并且薪水的话如果用几K表示,直接用于计算,所以将k去掉。
这里我们可以使用pandas中的apply方法,针对薪酬这一列数据进行操作,结果如下图。
# 定义拆分的行数
def split_salary(salary,method):
# 获取“-”的索引值
position = salary.upper().find('-')
if position != -1:# salary值是15k-25k的样式
low_salary = salary[:position-1]
high_salary = salary[position+1:len(salary)-1]
else:# salary值是15k以上的样式
low_salary = salary[:salary.upper().find('K')]
high_salary = low_salary
# 根据参数用以判断返回的值
if method == 'low':
return low_salary
if method == 'high':
return high_salary
if method == 'avg':
return (int(low_salary)+int(high_salary))/2
# 赋值
data['low_salary'] = data.salary.apply(split_salary,method='low')
data['high_salary'] = data.salary.apply(split_salary,method='high')
data['avg_salary'] = data.salary.apply(split_salary,method='avg')
data.head()
city | companyId | companySize | businessZones | firstType | secondType | education | industryField | positionId | positionAdvantage | positionName | positionLables | salary | workYear | low_salary | high_salary | avg_salary | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 上海 | 8581 | 2000人以上 | ['张江'] | 技术 | 数据开发 | 硕士 | 移动互联网 | 2537336 | 知名平台 | 数据分析师 | ['分析师', '数据分析', '数据挖掘', '数据'] | 7k-9k | 应届毕业生 | 7 | 9 | 8.0 |
1 | 上海 | 23177 | 500-2000人 | ['五里桥', '打浦桥', '制造局路'] | 技术 | 数据开发 | 本科 | 金融 | 2427485 | 挑战机会,团队好,与大牛合作,工作环境好 | 数据分析师-CR2017-SH2909 | ['分析师', '数据分析', '数据挖掘', '数据'] | 10k-15k | 应届毕业生 | 10 | 15 | 12.5 |
2 | 上海 | 57561 | 50-150人 | ['打浦桥'] | 设计 | 数据分析 | 本科 | 移动互联网 | 2511252 | 时间自由,领导nic | 数据分析师 | ['分析师', '数据分析', '数据'] | 4k-6k | 应届毕业生 | 4 | 6 | 5.0 |
3 | 上海 | 7502 | 150-500人 | ['龙华', '上海体育场', '万体馆'] | 市场与销售 | 数据分析 | 本科 | 企业服务,数据服务 | 2427530 | 五险一金 绩效奖金 带薪年假 节日福利 | 大数据业务分析师【数云校招】 | ['商业', '分析师', '大数据', '数据'] | 6k-8k | 应届毕业生 | 6 | 8 | 7.0 |
4 | 上海 | 130876 | 15-50人 | ['上海影城', '新华路', '虹桥'] | 技术 | 软件开发 | 本科 | 其他 | 2245819 | 在大牛下指导 | BI开发/数据分析师 | ['分析师', '数据分析', '数据', 'BI'] | 2k-3k | 应届毕业生 | 2 | 3 | 2.5 |
-
第一步,我们自定义了一个函数split_salary()函数,salary参数是使用apply函数必须要传的参数,其实就是data.salary的值。
-
第二步,使用salary.upper().find(’-’)判断salary值是15k-25k的形式还是15k以上形式,如果结果是-1,表示是15k以上形式,反之是15k-25k形式。为了避免k的大小写,我们用upper函数将k都转换为K,然后以K作为截取。
-
第三步,在split_salary函数增加了新的参数用以判断返回low_salary还是high_salary或者是avg_salary。
分列除了采取以上的find()函数外,还可以使用split()函数,如下所示:
import pandas as pd
df = pd.DataFrame(data={'序号':[1,2,3,4],
'待遇':['12K','12K-15K','20-22k','20k以上']})
df2 = df['待遇'].str.split('-',expand=True)
df2
0 | 1 | |
---|---|---|
0 | 12K | None |
1 | 12K | 15K |
2 | 20 | 22k |
3 | 20k以上 | None |
df
序号 | 待遇 | |
---|---|---|
0 | 1 | 12K |
1 | 2 | 12K-15K |
2 | 3 | 20-22k |
3 | 4 | 20k以上 |
到此,我们完成了数据整理部分,接着我们看看数据分析师的薪酬情况。
五、绘制图表
%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib import font_manager
import seaborn as sns
# 定义中文字体
my_font = font_manager.FontProperties(fname=r'C:\Users\lin-a\Desktop\Python数据分析\经典黑体简.TTF')
sns.set(style='darkgrid')
plt.figure(figsize=(10,8),dpi=80)
plt.hist(data['avg_salary'],width=5)
plt.xlabel('薪酬区间',fontproperties=my_font)
plt.ylabel('数量',fontproperties=my_font)
plt.title('数据分析师薪酬分布图',fontproperties=my_font)
plt.show()
接着我们按照城市来观察不同城市对薪酬的影响:
图表中绘制了数据分析师薪资的分布,可以看出薪资的大部分在10k-30k之间,10k-20k这个范围最多。
%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib import font_manager
import seaborn as sns
my_font = font_manager.FontProperties(fname=r'C:\Users\lin-a\Desktop\Python数据分析\经典黑体简.TTF')
plt.figure(figsize=(20,8),dpi=80)
sns.set(style='darkgrid')
groups = data.groupby(by='city')
xticks = []
for group_name,group_df in groups:
xticks.append(group_name)
plt.bar(group_name,group_df.avg_salary.mean())
plt.xticks(xticks,fontproperties=my_font)
plt.title('不同城市薪酬分布',fontproperties=my_font)
plt.ylabel('薪酬水平',fontproperties=my_font)
plt.show()
代码中我们用city进行分组,然后分别绘制了每个城市的平均薪资。
从图表中我们看出,北京的数据分析师薪资高于其他城市,上海和深圳稍次,广州甚至不如杭州和苏州。
接下来,我们再看看不同学历对薪资的影响。
我们同样按学历进行分组,然后对比不同学历的平均薪资。
%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib import font_manager
my_font = font_manager.FontProperties(fname=r'C:\Users\lin-a\Desktop\Python数据分析\经典黑体简.TTF')
plt.figure(figsize=(6,4),dpi=80)
sns.set(style='darkgrid')
groups = data.groupby(by='education')
xticks = []
for group_name,group_df in groups:
xticks.append(group_name)
plt.bar(group_name,group_df.avg_salary.mean())
plt.xticks(xticks,fontproperties=my_font)
plt.title('不同学历水平薪酬分布',fontproperties=my_font)
plt.ylabel('薪酬水平',fontproperties=my_font)
plt.show()
代码中我们用city进行分组,然后分别绘制了不同学历的平均薪资。
从图表中我们看出,博士薪资最高,硕士和本科基本持平,大专学历稍有弱势。
最后,我们再看看不同工作年限对薪资的影响。
我们同样按工作年年限进行分组,然后对比不同年限的平均薪资。
%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib import font_manager
my_font = font_manager.FontProperties(fname=r'C:\Users\lin-a\Desktop\Python数据分析\经典黑体简.TTF')
plt.figure(figsize=(6,4),dpi=80)
sns.set(style='darkgrid')
groups = data.groupby(by='workYear')
xticks = []
for group_name,group_df in groups:
xticks.append(group_name)
plt.bar(group_name,group_df.avg_salary.mean())
plt.xticks(xticks,fontproperties=my_font)
plt.title('不同工作年限薪酬分布',fontproperties=my_font)
plt.ylabel('薪酬水平',fontproperties=my_font)
plt.show()
薪资我们就简单的分析到这里,我们简单的归纳一下我们数据展现的结果:
- 数据分析师的薪资的平均数是17k,最大薪资在75k,大部分分析师薪资在10k-20k之间。
- 北京的数据分析师薪资高于其他城市,上海和深圳稍次,杭州和苏州已经超过广州。
- 薪资最高的是博士,硕士和本科的薪资基本持平,大专学历稍有弱势。
- 工作年限越长,薪资就越高。
根据上面数据展现的结果可以得到这样的结论:北上广深依然是我们高薪就业地,同时工作年限和学历都是都与薪资成线性增长趋势。
- 2019年全年的天气数据,完成如下需求: 1. 2019年北京哪个月的气温波动最大? 2. 2019年各种空气质量的占比是多少?
%matplotlib inline
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# 导入数据
data = pd.read_