[关闭]
@coder-pig 2018-04-23T06:43:57.000000Z 字数 17449 阅读 1481

Python数据分析:拉钩Python岗位行情分析

写书


相信经过前面的学习,你已经能熟练运用Python来编写爬虫,完成绝大部分的
网站的数据爬取。但是Python并不仅限于爬虫,无所不能的"胶水语言"Python
利用各种库还能做出更多酷酷的事情。比如:数据分析,Web开发,微信机器人,
图形化应用程序,自动化测试等。本章会通过一个个的实战项目让读者体会到
Python的无所不能。


一.Python数据分析可视化:拉勾网Python岗位行情

数据分析可视化是指把采集到的大量数据转换成图表的形式,更直观的向用户展示数据间
的联系以及变化情况,从而降低用户的阅读与时间成本,更快地得出结论。

本章涉及到以下知识点


1.1 数据爬取

打开拉钩首页,https://www.lagou.com 进去选择全国站,搜索栏输入 Python,点击搜索

滚动到底部可以看到,页数只有30页:

点击下一页几次,发现页面并没有全部刷新,猜测是Ajax动态加载数据,
Chrome浏览器打开开发者工具进行抓包分析,勾XHR过滤,刷新网页

点击Preview选项卡查看具体的Json内容,发现第一个就是所需的数据

点开列表中的中的一个,这些就是可以采集的字段

知道拿哪里的数据,接下来就是模拟请求了,点击Header选项卡,

先是请求头,因为没登陆就可以访问了,Cookies就不用传了,其他都带上,
接着是Post提交的表单数据:

{ first:true,pn:2,kd:Python }

first是否第一次加载,pn参数是页码,kd是搜索关键词,爬取的时候只需修改页码,
其他两个参数不用动,接着编写一波代码爬取想要的数据,这里直接利用pandas库,
创建一个DataFrame对象,然后调用to_csv()函数把所有数据写入到csv文件中。、
这里还需判断是否为首页,是首页的话,设置下表头。

  1. # Ajax加载url
  2. ajax_url = "https://www.lagou.com/jobs/positionAjax.json?"
  3. # url拼接参数
  4. request_params = {'needAddtionalResult': 'false'}
  5. # post提交参数
  6. form_data = {'first': 'false', 'pn': '1', 'kd': 'Python'}
  7. # 获得页数的正则
  8. page_pattern = re.compile('"totalCount":(\d*),', re.S)
  9. # csv表头
  10. csv_headers = [
  11. '公司id', '城市', '职位名称', '工作年限', '学历', '职位性质', '薪资',
  12. '融资状态', '行业领域', '招聘岗位id', '公司优势', '公司规模',
  13. '公司标签', '所在区域', '技能标签', '公司经度', '公司纬度', '公司全名'
  14. ]
  15. # 模拟请求头
  16. ajax_headers = {
  17. 'Accept': 'application/json, text/javascript, */*; q=0.01',
  18. 'Accept-Encoding': 'gzip, deflate, br',
  19. 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
  20. 'Connection': 'keep-alive',
  21. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  22. 'Host': 'www.lagou.com ',
  23. 'Origin': 'https://www.lagou.com ',
  24. 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36',
  25. 'X-Anit-Forge-Code': '0',
  26. 'X-Anit-Forge-Token': 'None',
  27. 'X-Requested-With': 'XMLHttpRequest',
  28. 'Referer': 'https://www.lagou.com/jobs/list_android?labelWords=&fromSearch=true&suginput='
  29. }
  30. # 获取每页招聘信息
  31. def fetch_data(page):
  32. fetch_url = ajax_url + urllib.parse.urlencode(request_params)
  33. global max_page
  34. while True:
  35. try:
  36. form_data['pn'] = page
  37. print("抓取第:" + str(page) + "页!")
  38. # 随缘休息5-15s,避免因为访问过于频繁被封ip
  39. time.sleep(random.randint(5, 15))
  40. resp = requests.post(url=fetch_url, data=form_data, headers=ajax_headers)
  41. if resp.status_code == 200:
  42. if page == 1:
  43. max_page = int(int(page_pattern.search(resp.text).group(1)) / 15)
  44. print("总共有:" + str(max_page) + "页")
  45. data_json = resp.json()['content']['positionResult']['result']
  46. data_list = []
  47. for data in data_json:
  48. data_list.append((data['companyId'],
  49. data['city'],
  50. html.unescape(data['positionName']),
  51. data['workYear'],
  52. data['education'],
  53. data['jobNature'],
  54. data['salary'],
  55. data['financeStage'],
  56. data['industryField'],
  57. data['positionId'],
  58. html.unescape(data['positionAdvantage']),
  59. data['companySize'],
  60. data['companyLabelList'],
  61. data['district'],
  62. html.unescape(data['positionLables']),
  63. data['longitude'],
  64. data['latitude'],
  65. html.unescape(data['companyFullName'])))
  66. result = pd.DataFrame(data_list)
  67. if page == 1:
  68. result.to_csv(result_save_file, header=csv_headers, index=False, mode='a+')
  69. else:
  70. result.to_csv(result_save_file, header=False, index=False, mode='a+')
  71. return None
  72. except Exception as e:
  73. print(e)

注意

在爬取文本信息的时候会遇到&nbsp和&amp这类HTML里的转义字符,需要调用html模块的
unescape()函数对此进行转义,对应函数escape(),比如上面爬取的文本有些如果不进行
转义的话,会出现写入结果错位的情况!

接着运行程序把数据写入到csv文件中

打开csv文件可以看到总共爬取到了1746条数据,数据有了,接下来就是准备开始
数据分析可视化了,在此之前我们先要简单了解下数据分析的两个常用库numpy与pandas。


1.2 numpy库基本了解


1.2.1 numpy简介

numpy库 科学计算的基础库,提供了一个多维数组对象(ndarray)和各种派生对象(如Masked arrays和矩阵),
以及各种加速数组操作的例程,包括数学、逻辑、图形变换、排序、选择、io、离散傅立叶变换、
基础线性代数、基础统计,随机模拟等等。

概念看上去很复杂,目前我们只需了解ndarray一些常用的基本函数的使用就够了,
如果有兴趣了解更多可移步到:https://docs.scipy.org/doc/numpy-dev/user/index.html
进行更深入的学习。

1.2.2 numpy安装

可以通过pip命令:pip install numpy
或者Anaconda库进行安装:conda install numpy
安装完后可以进入python测试下:import numpy,没有报错说明安装成功。

1.2.3 ndarray数组

ndarray是一个多维的数组对象,和Python自带的列表,元组等元素最大的区别
后者里元素的数据类型可以是不一样的,比如一个列表里可能放着整型,字符串,
而ndarray里的元素的数据类型必须是相同的!最简单的可以通过numpy提供的
array函数来生成一个ndarray数组,传入一个列表或者元组即可创建。接着演示
下如何生成ndarray的多种方法以及几个常用属性。

  1. import numpy as np
  2. print("1.生成一个一维数组:\n %s" % np.array([1, 2]))
  3. print("2.生成一个二维数组:\n %s" % np.array([[1, 2], [3, 4]]))
  4. print("3.生成一个元素初始值都为0的,4行3列矩阵:\n %s" % np.zeros((4, 3)))
  5. print("4.生成一个元素初始值都为1的,3行4列矩阵:\n %s" % np.ones((3, 4)))
  6. print("5.创建一个空数组,元素为随机值:\n %s" % np.empty([2, 3], dtype=int))
  7. a1 = np.arange(0, 30, 2)
  8. print("6.生成一个等间隔数字的数组:\n %s" % a1)
  9. a2 = a1.reshape(3, 5)
  10. print("7.转换数组的维度,比如把一维的转为3行5列的数组:\n %s" % a2)
  11. # ndarray常用属性
  12. print("8.a1的维度: %d \t a2的维度:%d" % (a1.ndim, a2.ndim))
  13. print("9.a1的行列数:%s \t a2的行列数:%s" % (a1.shape, a2.shape))
  14. print("10.a1的元素个数:%d \t a2的元素个数:%d" % (a1.size, a2.size))
  15. print("11.a1的元素数据类型:%s 数据类型大小:%s" % (a1.dtype, a1.itemsize))

运行结果

  1. 1.生成一个一维数组:
  2. [1 2]
  3. 2.生成一个二维数组:
  4. [[1 2]
  5. [3 4]]
  6. 3.生成一个元素初始值都为0的,43列矩阵:
  7. [[0. 0. 0.]
  8. [0. 0. 0.]
  9. [0. 0. 0.]
  10. [0. 0. 0.]]
  11. 4.生成一个元素初始值都为1的,34列矩阵:
  12. [[1. 1. 1. 1.]
  13. [1. 1. 1. 1.]
  14. [1. 1. 1. 1.]]
  15. 5.创建一个空数组,元素为随机值:
  16. [[ 0 1072693248 0]
  17. [1072693248 0 1072693248]]
  18. 6.生成一个等间隔数字的数组:
  19. [ 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28]
  20. 7.转换数组的维度,比如把一维的转为35列的数组,和元数组是内存共享的:
  21. [[ 0 2 4 6 8]
  22. [10 12 14 16 18]
  23. [20 22 24 26 28]]
  24. 8.a1的维度: 1 a2的维度:2
  25. 9.a1的行列数:(15,) a2的行列数:(3, 5)
  26. 10.a1的元素个数:15 a2的元素个数:15
  27. 11.a1的元素数据类型:int32 数据类型大小:4

1.2.4 ndarray数组的常见操作

  1. import numpy as np
  2. # 1.访问数组
  3. a1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
  4. print("访问第一行: %s" % a1[0])
  5. a1[0] = 2 # 修改数组中元素的值
  6. print("访问第一列: %s" % a1[:, 0])
  7. print("访问前两行:\n {}".format(a1[:2]))
  8. print("访问前两列:\n {}".format(a1[:, :2]))
  9. print("访问第二行第三列:{}".format(a1[1][9]))
  10. # 2.通过take函数访问数组(axis参数代表轴),put函数快速修改元素值
  11. a2 = np.array([1, 2, 3, 4, 5])
  12. print("take函数访问第二个元素:%s" % a2.take(1))
  13. a3 = np.array([0, 2, 4])
  14. print("take函数参数列表索引元素:%s" % a2.take(a3))
  15. print("take函数访问某个轴的元素:%s" % a1.take(1, axis=1))
  16. a4 = np.array([6, 8, 9])
  17. a2.put([0, 2, 4], a4)
  18. print("put函数快速修改特定索引元素的值:%s" % a2)
  19. # 3.通过比较符访问元素
  20. print("通过比较符索引满足条件的元素:%s" % a1[a1 > 3])
  21. # 4.遍历数组
  22. print("一维数组遍历:")
  23. for i in a2:
  24. print(i, end=" ")
  25. print("\n二维数组遍历:")
  26. for i in a1:
  27. print(i, end=" ")
  28. print("\n还可以这样遍历:")
  29. for (i, j, k) in a1:
  30. print("%s - %s - %s" % (i, j, k))
  31. # 5.insert插入元素(参数依次为:数组,插入轴的标号,插入值,axis=0插入行,=1插入列)
  32. a5 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
  33. a5 = np.insert(a5, 0, [6, 6, 6], axis=0)
  34. print("insert函数插入元素到第一行:\n %s " % a5)
  35. # 6.delete删除元素(参数依次为数组,删除轴的标号,axis同上)
  36. a5 = np.delete(a5, 0, axis=1)
  37. print("delete函数删除第一列元素:\n %s" % a5)
  38. # 7.copy深拷贝一个数组,直接赋值是浅拷贝
  39. a6 = a5.copy()
  40. a7 = a5
  41. print("copy后的数组是否与原数组指向同一对象:%s" % (a6 is a5))
  42. print("赋值的数组是否与原数组指向同一对象:%s" % (a7 is a5))
  43. # 8.二维数组转一维数组,二维数组数组合并
  44. a8 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
  45. print("二维数组 => 一维数组:%s" % a8.flatten())
  46. a9 = np.array([[1, 2, 3], [4, 5, 6]])
  47. a10 = np.array([[7, 8], [9, 10]])
  48. print("两个二维数组合并 => 一个二维数组:\n{}".format(np.concatenate((a9, a10), axis=1)))
  49. # 9.数学计算(乘法是对应元素想成,叉乘用.dot()函数)
  50. a11 = np.array([[1, 2], [3, 4]])
  51. a12 = np.array([[5, 6], [7, 8]])
  52. print("数组相加:\n%s" % (a11 + a12))
  53. print("数组相减:\n%s" % (a11 - a12))
  54. print("数组相乘:\n%s" % (a11 * a12))
  55. print("数组相除:\n%s" % (a11 / a12))
  56. print("数组叉乘:\n%s" % (a11.dot(a12)))
  57. # 10.其他
  58. a12 = np.array([1, 2, 3, 4])
  59. print("newaxis增加维度:\n %s" % a12[:, np.newaxis])
  60. print("tile函数重复数组(重复列数,重复次数):\n %s" % np.tile(a12, [2, 2]))
  61. print("vstack函数按列堆叠:\n %s" % np.vstack([a12, a12]))
  62. print("hstack函数按行堆叠:\n %s" % np.hstack([a12, a12]))
  63. a13 = np.array([1, 4, 8, 2, 44, 77, -2, 1, 4])
  64. a13.sort()
  65. print("sort函数排序:\n %s" % a13)
  66. print("unique函数去重:\n {}".format(np.unique(a13)))

运行结果:

  1. 访问第一行: [1 2 3]
  2. 访问第一列: [2 4 7]
  3. 访问前两行:
  4. [[2 2 2]
  5. [4 5 6]]
  6. 访问前两列:
  7. [[2 2]
  8. [4 5]
  9. [7 8]]
  10. 访问第二行第三列:6
  11. take函数访问第二个元素:2
  12. take函数参数列表索引元素:[1 3 5]
  13. take函数访问某个轴的元素:[2 5 8]
  14. put函数快速修改特定索引元素的值:[6 2 8 4 9]
  15. 通过比较符索引满足条件的元素:[4 5 6 7 8 9]
  16. 一维数组遍历:
  17. 6 2 8 4 9
  18. 二维数组遍历:
  19. [2 2 2] [4 5 6] [7 8 9]
  20. 还可以这样遍历:
  21. 2 - 2 - 2
  22. 4 - 5 - 6
  23. 7 - 8 - 9
  24. insert函数插入元素到第一行:
  25. [[6 6 6]
  26. [1 2 3]
  27. [4 5 6]
  28. [7 8 9]]
  29. delete函数删除第一列元素:
  30. [[6 6]
  31. [2 3]
  32. [5 6]
  33. [8 9]]
  34. copy后的数组是否与原数组指向同一对象:False
  35. 赋值的数组是否与原数组指向同一对象:True
  36. 二维数组 => 一维数组:[1 2 3 4 5 6 7 8 9]
  37. 两个二维数组合并 => 一个二维数组:
  38. [[ 1 2 3 7 8]
  39. [ 4 5 6 9 10]]
  40. 数组相加:
  41. [[ 6 8]
  42. [10 12]]
  43. 数组相减:
  44. [[-4 -4]
  45. [-4 -4]]
  46. 数组相乘:
  47. [[ 5 12]
  48. [21 32]]
  49. 数组相除:
  50. [[ 0.2 0.33333333]
  51. [ 0.42857143 0.5 ]]
  52. 数组叉乘:
  53. [[19 22]
  54. [43 50]]
  55. newaxis增加维度:
  56. [[1]
  57. [10]
  58. [3]
  59. [11]]
  60. tile函数重复数组(重复列数,重复次数):
  61. [[1 2 3 4 1 2 3 4]
  62. [1 2 3 4 1 2 3 4]]
  63. vstack函数按列堆叠:
  64. [[1 2 3 4]
  65. [1 2 3 4]]
  66. hstack函数按行堆叠:
  67. [1 2 3 4 1 2 3 4]
  68. sort函数排序:
  69. [-2 1 1 2 4 4 8 44 77]
  70. unique函数去重:
  71. [-2 1 2 4 8 44 77]

1.3 pandas库基本了解


1.3.1 pandas简介

提供了快速便捷处理结构化数据的大量数据结构和函数,有两种数据
常见的数据结构,分别为:Series (一维的标签化数组对象)和 DataFrame (面向列的二维表结构)
同样是讲述库的基本使用,想深入了解pandas可移步到官网:
十分钟上手pandashttp://pandas.pydata.org/pandas-docs/stable/10min.html
更多内容http://pandas.pydata.org/pandas-docs/stable/cookbook.html#cookbook
pandas库安装:pip install pandas


1.3.2 Series与DataFrame简介

Series是一维的标签化数组对象,和Python自带的列表类似,每个元素由索引与值构成,
数组中的值为相同的数据类型。

注意:np.nan用来标示空缺数据

Series

  1. import pandas as pd
  2. import numpy as np
  3. s1 = pd.Series([1, 2, 3, np.nan, 5])
  4. print("1.通过列表创建Series对象:\n%s" % s1)
  5. s2 = pd.Series([1, 2, 3, np.nan, 5], index=['a', 'b', 'c', 'd', 'e'])
  6. print("2.通过列表创建Series对象(自定义索引):\n%s" % s2)
  7. print("3.通过索引获取元素:%s" % s2['a'])
  8. print("4.获得索引:%s" % s2.index)
  9. print("5.获得值:%s" % s2.values)
  10. print("6.和列表一样值支持分片的:\n{}".format(s2[0:2]))
  11. s3 = pd.Series(pd.date_range('2018.3.17', periods=6))
  12. print("7.利用date_range生成日期列表:\n%s" % s3)

运行结果

  1. 1.通过列表创建Series对象:
  2. 0 1.0
  3. 1 2.0
  4. 2 3.0
  5. 3 NaN
  6. 4 5.0
  7. dtype: float64
  8. 2.通过列表创建Series对象(自定义索引):
  9. a 1.0
  10. b 2.0
  11. c 3.0
  12. d NaN
  13. e 5.0
  14. dtype: float64
  15. 3.通过索引获取元素:1.0
  16. 4.获得索引:Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
  17. 5.获得值:[ 1. 2. 3. nan 5.]
  18. 6.和列表一样值支持分片的:
  19. a 1.0
  20. b 2.0
  21. dtype: float64
  22. 7.利用date_range生成日期列表:
  23. 0 2018-03-17
  24. 1 2018-03-18
  25. 2 2018-03-19
  26. 3 2018-03-20
  27. 4 2018-03-21
  28. 5 2018-03-22
  29. dtype: datetime64[ns]

DataFrame

面向列的二维表结构,类似于Excel表格,由行标签、列表索引与值三部分组成。

  1. # 1.创建DataFrame对象
  2. dict1 = {
  3. '学生': ["小红", "小绿", "小蓝", "小黄", "小黑", "小灰"],
  4. '性别': ["女", "男", "女", "男", "男", "女"],
  5. '年龄': np.random.randint(low=10, high=15, size=6),
  6. }
  7. d1 = pd.DataFrame(dict1)
  8. print("1.用相等长度的列表组成的字典对象生成:\n %s" % d1)
  9. d2 = pd.DataFrame(np.random.randint(low=60, high=100, size=(6, 3)),
  10. index=["小红", "小绿", "小蓝", "小黄", "小黑", "小灰"],
  11. columns=["语文", "数学", "英语"])
  12. print("2.通过二维数组生成DataFrame: \n %s" % d2)
  13. # 2.数据查看
  14. print("3.head函数查看顶部多行(默认5行):\n%s" % d2.head(3))
  15. print("4.tail函数查看底部多行(默认5行):\n%s" % d2.tail(2))
  16. print("5.index查看所有索引:%s" % d2.index)
  17. print("6.columns查看所有行标签:%s" % d2.columns)
  18. print("7.values查看所有值:\n%s" % d2.values)
  19. # 3.数据排序
  20. print("8.按索引排序(axis=0行索引,=1列索引排序,ascending=False降序排列):\n%s"
  21. % (d2.sort_index(axis=0, ascending=False)))
  22. print("9.按值进行排序:\n%s" % d2.sort_values(by="语文", ascending=False))
  23. # 4.数据选择
  24. print("9.选择一列或多列:\n{} {} ".format(d2['语文'], d2[['数学', '英语']]))
  25. print("10.数据切片:\n{}".format(d2[0:1]))
  26. print("11.条件过滤(过滤语文分数高于90的数据):\n{}".format(d2[d2.语文 > 90]))
  27. print("12.loc函数行索引切片获得指定列数据:\n{}".format(d2.loc['小红':'小蓝', ['数学', '英语']]))
  28. print("13.iloc函数行号切片获得指定列数据:\n{}".format(d2.iloc[4:6, 1:2]))
  29. # 5.求和,最大/小值,平均值,分组
  30. print("14.语文总分:{}".format(d2['语文'].sum()))
  31. print("15.语文平均分:{}".format(d2['语文'].mean()))
  32. print("16.数学最高分:{}".format(d2['数学'].max()))
  33. print("17.英语最低分:{}".format(d2['英语'].min()))
  34. # 6.数据输入输出(可以把数据保存到csv或excel中,也可以读取文件)
  35. d1.to_csv('student_1.csv')
  36. d3 = pd.read_csv('student_1.csv')
  37. print("18.读取csv文件中的数据:\n{}".format(d3))
  38. d2.to_excel('student_2.xlsx', sheet_name="Sheet1")
  39. d4 = pd.read_excel('student_2.xlsx', sheet_name="Sheet1")
  40. print(("19.读取excel文件中的数据:\n{}".format(d4)))

运行结果

  1. 1.用相等长度的列表组成的字典对象生成:
  2. 学生 年龄 性别
  3. 0 小红 10
  4. 1 小绿 10
  5. 2 小蓝 10
  6. 3 小黄 12
  7. 4 小黑 10
  8. 5 小灰 11
  9. 2.通过二维数组生成DataFrame:
  10. 语文 数学 英语
  11. 小红 96 96 77
  12. 小绿 95 67 93
  13. 小蓝 98 69 98
  14. 小黄 65 81 94
  15. 小黑 74 98 64
  16. 小灰 96 72 96
  17. 3.head函数查看顶部多行(默认5行):
  18. 语文 数学 英语
  19. 小红 96 96 77
  20. 小绿 95 67 93
  21. 小蓝 98 69 98
  22. 4.tail函数查看底部多行(默认5行):
  23. 语文 数学 英语
  24. 小黑 74 98 64
  25. 小灰 96 72 96
  26. 5.index查看所有索引:Index(['小红', '小绿', '小蓝', '小黄', '小黑', '小灰'], dtype='object')
  27. 6.columns查看所有行标签:Index(['语文', '数学', '英语'], dtype='object')
  28. 7.values查看所有值:
  29. [[96 96 77]
  30. [95 67 93]
  31. [98 69 98]
  32. [65 81 94]
  33. [74 98 64]
  34. [96 72 96]]
  35. 8.按索引排序(axis=0行索引,=1列索引排序,ascending=False降序排列):
  36. 语文 数学 英语
  37. 小黑 74 98 64
  38. 小黄 65 81 94
  39. 小蓝 98 69 98
  40. 小绿 95 67 93
  41. 小红 96 96 77
  42. 小灰 96 72 96
  43. 9.按值进行排序:
  44. 语文 数学 英语
  45. 小蓝 98 69 98
  46. 小红 96 96 77
  47. 小灰 96 72 96
  48. 小绿 95 67 93
  49. 小黑 74 98 64
  50. 小黄 65 81 94
  51. 9.选择一列或多列:
  52. 小红 96
  53. 小绿 95
  54. 小蓝 98
  55. 小黄 65
  56. 小黑 74
  57. 小灰 96
  58. Name: 语文, dtype: int64 数学 英语
  59. 小红 96 77
  60. 小绿 67 93
  61. 小蓝 69 98
  62. 小黄 81 94
  63. 小黑 98 64
  64. 小灰 72 96
  65. 10.数据切片:
  66. 语文 数学 英语
  67. 小红 96 96 77
  68. 11.条件过滤(过滤语文分数高于90的数据):
  69. 语文 数学 英语
  70. 小红 96 96 77
  71. 小绿 95 67 93
  72. 小蓝 98 69 98
  73. 小灰 96 72 96
  74. 12.loc函数行索引切片获得指定列数据:
  75. 数学 英语
  76. 小红 96 77
  77. 小绿 67 93
  78. 小蓝 69 98
  79. 13.iloc函数行号切片获得指定列数据:
  80. 数学
  81. 小黑 98
  82. 小灰 72
  83. 14.语文总分:524
  84. 15.语文平均分:87.33333333333333
  85. 16.数学最高分:98
  86. 17.英语最低分:64
  87. 18.读取csv文件中的数据:
  88. Unnamed: 0 学生 年龄 性别
  89. 0 0 小红 10
  90. 1 1 小绿 10
  91. 2 2 小蓝 10
  92. 3 3 小黄 12
  93. 4 4 小黑 10
  94. 5 5 小灰 11
  95. 19.读取excel文件中的数据:
  96. 语文 数学 英语
  97. 小红 96 96 77
  98. 小绿 95 67 93
  99. 小蓝 98 69 98
  100. 小黄 65 81 94
  101. 小黑 74 98 64
  102. 小灰 96 72 96

1.4 matplotlib进行数据可视化

1.4.1 matplotlib简介

matplotlib是一个用于2D图表绘制的Python库。用法也很简单,可以
轻易地绘制出各种图表本节会用到几个常用的图形:直方图,饼图,条形图;
官方文档中还有各种各样的图以及Demo示例:

有兴趣可移步到:
Matplotlib入门教程https://pythonprogramming.net/matplotlib-intro-tutorial/
Matplotlib绘制各种图形Demo示例https://matplotlib.org/gallery.html#lines_bars_and_markers
推荐通过pip命令行进行安装:pip install matplotlib

1.4.2 matplotlib中文乱码问题

使用matplotlib进行图表绘制,第一个遇到的问题就是中文乱码问题,如图

解决方法如下

1.编写如下代码获得matplotlib库配置相关的路径:

  1. import matplotlib
  2. print(matplotlib.matplotlib_fname())

接着会获得一个对应的路径,比如我的电脑是:
/usr/local/lib/python3.4/dist-packages/matplotlib/mpl-data/matplotlibrc

2.下载一个文中的ttf字体文件(任意),然后把文件拷贝到这个路径下,双击安装;
3.接着修改matplotlibrc配置文件,找到如下三行,去掉注释,进行修改:

  1. 199行:font.family : sans-serif
  2. 210行:font.serif : 中文字体名称, DejaVu Serif, Bitstream
  3. 330行:axes.unicode_minus : False

4.删除.cache/matplotlib缓存文件,重新运行即可。

1.4.3 matplotlib绘制显示不全

如图,在绘制的时候可能会出现显示不全的情况,需要进行设置,

顺道介绍下下面7个菜单按钮的,依次是:

重置回主视图,上一步视图,下一步视图,拖拽页面,
局部放大,设置,保存成图片

点击设置,会出现如图所示对话框:

拖拉调整下,直到差不多显示完全

记录下这些参数,在绘制图形之前,需要代码设置下:

  1. plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
  2. bottom=0.17, top=0.84)

1.4.4 matplotlib生成图表并进行分析

先调用pd.read_csv()函数读取一开始爬取数据存放的csv文件,接着开始针对不同的列进行数据分析,

1.公司规模(饼图)

  1. plt.figure(1)
  2. data['公司规模'].value_counts().plot(kind='pie', autopct='%1.1f%%',
  3. explode=np.linspace(0, 0.5, 6))
  4. plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
  5. bottom=0.17, top=0.84)
  6. plt.savefig(pic_save_path + 'result_1.jpg')
  7. plt.close(1)

招Python的公司规模都比较平均,中小型公司(15-500人)占比达81% 。

2.公司融资状态(饼图)

  1. plt.figure(2)
  2. data['融资状态'].value_counts().plot(kind='pie', autopct='%1.1f%%')
  3. plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
  4. bottom=0.17, top=0.84)
  5. plt.savefig(pic_save_path + 'result_2.jpg')
  6. plt.close(2)

3.公司城市分布(饼图)

  1. plt.figure(3)
  2. data['城市'].value_counts().plot(kind='pie', autopct='%1.1f%%')
  3. plt.subplots_adjust(left=0.31, right=0.74, wspace=0.20, hspace=0.20,
  4. bottom=0.26, top=0.84)
  5. plt.savefig(pic_save_path + 'result_3.jpg')
  6. plt.close(3)

招Python开发排名前几的城市依次为:
北京,上海,深圳,广州,杭州,成都,武汉,西安,南京,厦门

4.要求工作经验(直方图+饼图)

  1. plt.figure(4)
  2. data['工作年限'].value_counts().plot(kind='barh', rot=0)
  3. plt.title("工作经验直方图")
  4. plt.xlabel("年限/年")
  5. plt.ylabel("公司/个")
  6. plt.savefig(pic_save_path + 'result_4.jpg')
  7. plt.close(4)
  8. # 饼图
  9. plt.figure(5)
  10. data['工作年限'].value_counts().plot(kind='pie', autopct='%1.1f%%', explode=np.linspace(0, 0.75, 6))
  11. plt.title("工作经验饼图")
  12. plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
  13. bottom=0.17, top=0.84)
  14. plt.savefig(pic_save_path + 'result_5.jpg')
  15. plt.close(5)

工作1-3年与3-5年的Python工程师依旧比较抢手。

5.学历要求(饼图)

  1. plt.figure(6)
  2. data['学历'].value_counts().plot(kind='pie', autopct='%1.1f%%', explode=(0, 0.1, 0.2,0.3))
  3. plt.title("学历饼图")
  4. plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
  5. bottom=0.17, top=0.84)
  6. plt.savefig(pic_save_path + 'result_6.jpg')
  7. plt.close(6)

接近七成半的公司需要本科学历以上!

6.薪资(条形图)

  1. plt.figure(7)
  2. salary = data['薪资'].str.split('-').str.get(0).str.replace('k|K|以上', "").value_counts()
  3. salary_index = list(salary.index)
  4. salary_index.sort(key=lambda x: int(x))
  5. final_salary = salary.reindex(salary_index)
  6. plt.title("薪资条形图")
  7. final_salary.plot(kind='bar', rot=0)
  8. plt.xlabel("薪资/K")
  9. plt.ylabel("公司/个")
  10. plt.savefig(pic_save_path + 'result_7.jpg')
  11. plt.close(7)

结合工作经验饼图分析,猜测1-3年初级Python开发者的薪资范围为:8-10k,
而3-5年的中级Python开发者的薪资范围为: 10-15k。


1.5 wordcloud绘制词云


1.5.1 wordcloud简介

上面这类有具体数值的数据,可以通过图表形式来表现,而除了这类数据
外还有一种,比如公司标签这一类数据

我们可以进行词频统计,即每个词语出现的次数,接着按照比例生成词云。
而生成词云可以利用wordcloud这个库,这里同样只介绍基础用法,更多
可移步到下述网址:

Github仓库https://github.com/amueller/word_cloud
官方博客https://amueller.github.io/word_cloud/

推荐通过pip命令行进行安装:pip install wordcloud

1.5.2 WordCloud构造函数与常用方法

构造函数

  1. def __init__(self, font_path=None, width=400, height=200, margin=2,
  2. ranks_only=None, prefer_horizontal=.9, mask=None, scale=1,
  3. color_func=None, max_words=200, min_font_size=4,
  4. stopwords=None, random_state=None, background_color='black',
  5. max_font_size=None, font_step=1, mode="RGB",
  6. relative_scaling=.5, regexp=None, collocations=True,
  7. colormap=None, normalize_plurals=True):

参数详解

常用的几个方法:


1.5.3 WordCloud绘制词云

看上面的字段和函数那么多,感觉wordcloud很难用,其实并不难,笔者
写个最简单的绘制方法,自己参照着上面按需进行扩展就好。

  1. # 生成词云文件(参数为词云字符串与文件名,default_font是一个ttf的字体文件)
  2. def make_wc(content, file_name):
  3. wc = WordCloud(font_path=default_font, background_color='white', margin=2,
  4. max_font_size=250,width=2000, height=2000,
  5. min_font_size=30, max_words=1000)
  6. wc.generate_from_frequencies(content)
  7. wc.to_file(file_name)

接着再需要绘制词云的地方调用该函数即可,比如这里生成行业领域词云:

  1. industry_field_list = []
  2. for industry_field in data['行业领域']:
  3. for field in str(industry_field).strip().replace(" ", ",").replace("、", ",").split(','):
  4. industry_field_list.append(field)
  5. counter = dict(Counter(industry_field_list))
  6. counter.pop('')
  7. make_wc(counter, pic_save_path + "wc_1.jpg")

招Python开发的公司大部分是移动互联网的,其次是数据服务。

2.公司标签

  1. tags_list = []
  2. for tags in data['公司标签']:
  3. for tag in tags.strip().replace("[", "").replace("]", "")\
  4. .replace("'", "").split(','):
  5. tags_list.append(tag)
  6. counter = dict(Counter(tags_list))
  7. counter.pop('')
  8. make_wc(counter, pic_save_path + "wc_2.jpg")

3.公司优势

  1. for advantage_field in data['公司优势']:
  2. for field in advantage_field.strip().replace(" ", ",")\
  3. .replace("、", ",").replace(",", ",").replace("+", ",").split(','):
  4. industry_field_list.append(field)
  5. counter = dict(Counter(industry_field_list))
  6. counter.pop('')
  7. counter.pop('移动互联网')
  8. make_wc(counter, pic_save_path + "wc_3.jpg")

4.技能标签

  1. skill_list = []
  2. for skills in data['技能标签']:
  3. for skill in skills.strip().replace("[", "").replace("]", "").replace("'", "").split(','):
  4. skill_list.append(skill)
  5. counter = dict(Counter(skill_list))
  6. counter.pop('')
  7. make_wc(counter, pic_save_path + "wc_4.jpg")


1.6 小结

有了这些图片后就可以自行做数据报告了,


添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注