数据分析的步骤

数据分析可分为数据采集、数据挖掘、数据可视化三个步骤。

但在完成上面三个步骤之前,还有一个基本的东西需要完成:明确数据分析的目标。

如果数据分析的目标不清晰,数据不能够用来解决问题,那么数据就没有任何价值。所以数据分析的完整步骤应该是:明确数据分析目的——数据采集——数据整理(清洗、变换、分类等)——数据挖掘(建模)——数据可视化——数据更迭。

image-20201108093634021

数据分析常用算法

国际权威的学术组织 ICDM (the IEEE International Conference on Data Mining)评选出了十大经典的算法。

算法 常用方法
分类算法 C4.5,朴素贝叶斯(Naive Bayes),SVM,KNN,Adaboost,CART
聚类算法 K-Means,EM
关联分析 Apriori
连接分析 PageRank

用户画像建模

获客、粘客、留客

数据变换的常用方法

为什么要进行数据变换?把数据变换成统一的标准,方便后续围绕数据进行计算。

常用的数据变换方法有:

  • 数据平滑:去除数据中的噪声,将连续数据离散化。这里可以采用分箱、聚类和回归的方式进行数据平滑;
  • 数据聚集:对数据进行汇总,在 SQL 中有一些聚集函数可以供我们操作,比如 Max() 反馈某个字段的数值最大值,Sum() 返回某个字段的数值总和;
  • 数据概化:将数据由较低的概念抽象成为较高的概念,减少数据复杂度,即用更高的概念替代更低的概念;
  • 数据规范化:使属性数据按比例缩放,这样就将原来的数值映射到一个新的特定区域中。常用的方法有最小—最大规范化、Z—score 规范化、按小数定标规范化等,我会在后面给你讲到这些方法的使用;
  • 属性构造:构造出新的属性并添加到属性集中。这里会用到特征工程的知识,因为通过属性与属性的连接构造新的属性,其实就是特征工程。比如说,数据表中统计每个人的英语、语文和数学成绩,你可以构造一个“总和”这个属性,来作为新属性。这样“总和”这个属性就可以用到后续的数据挖掘计算中。

常用的规范方法:

  • min-max:将数据归一化到[0,1]区间。新数值 =(原数值 - 极小值)/(极大值 - 极小值)
  • z-score:将数据规范到0均值,1方差的标准正态分布上,减少老师说的百分制80和500分制80的数据值差异问题。新数值 =(原数值 - 均值)/ 标准差
  • 小数定标规范化:将数据转化为[-1,1]区间中。

python做数据分析常见扩展库

Numpy:详见一文学懂NumPy基础知识1

Scipy:

Matplotlib:

Pandas:详见Pandas基础快速入门

StatsModels:

Scikit-Learn:

Keras:

Gensim:

image-20201109193405641

数据分析案例

航空公司客户价值分析

家用电器用户行为与事件识别

电子商务网站用户行为分析与服务推荐

电商产品评论数据情感分析

财政收入影响因素及预测模型

参考资料

数据分析实战45讲|极课时间

《python数据分析与挖掘实战》张良均等著

Chage Log

20201109 增加python做数据分析常见扩展库

20201108 创建初版

每年,政府机构、研究机构、企业主体会发布各种各样的榜单,诸如中国企业500强、世界企业500强、XX创新20强、XX前100强。这类榜单评选标准及评选利益机制我们无从得知,很多评选的榜单,也没啥价值。

但,对于权威机构发布的榜单,还是值得看一下,特别是像信息流通慢的行业。诺,最近农民日报社组织评定的2020中国农业企业500强发布了,这个榜单是以企业营业收入来划分的 。

下面我尝试对这个榜单进行解读,希望大家有所收获。

第一,每类企业都有适合生存的土壤

山东、江苏、四川、吉林、安徽和福建6个省份,上榜的企业占71%。其中又以山东、江苏、四川三大省表现最突出,三个大省共有273家企业上榜,占总上榜企业的54.6%。山东上榜企业最多,达到151家,遥遥领先江苏(61家)、四川(61家)90家!

山东上榜的企业包括饲料、肥料生产销售、食品加工。四川上榜比较有特色的是各种休闲零食品牌及酒业,包括泸州老窖、千禾味业、吉香居等。江苏上榜的农产品贸易企业居多。

举一个运用,假如你要去找货,并不是一家一家的去找,而是要按照产业带去找。

image.png

第二,各地上榜企业实力不一

上榜企业多,并不是企业营业额就多,利润就高,你会看到有的行业营业收入高得离谱,但利润率也低得离谱,比如沃尔玛,这取决于性质。

企业入围的门槛是5.1亿元,营业收入最高的企业达2340元,差不多相差458倍。

所有企业总营业收入为2.64万亿,相比整个农业市场,对总营收的贡献还是有限的。

上榜企业数最多的前7个省份,贡献总营收的60.36%。四川和江苏同为61家企业上榜,但四川所有企业(10.04%)对总营收的贡献高于江苏(7.64%)。

从企业结构可以发现,四川上榜的企业大多是休闲零食、酒业等,而江苏上榜的企业以贸易为主,造成营收上的差别。福建因为有一家巨无霸企业(象屿股份)的存在,对总营收的贡献排名前三。

image.png

第三、年营业收入超过5亿的已经属于行业佼佼者了

入围企业营业收入在1000亿以上的共2家,500-1000亿元的共9家,营收在100-499亿元的企业共38家,营收在50-100亿(不含)的企业42家,营收在10-50亿(不含)的224家,营收在10亿(不含)以下的企业184家。

image.png

营业收入超过100亿的共47家,占比还不到10%,要想营收超过100亿并非一件容易的事情。国家提出“培育一批产值超百亿元、千亿元优势特色产业集群”,从单个企业来看,这并非易事,但我国农产品加工行业每年营业收入有几十万亿,众多小企业集合起来去实现,是完全可能的。

继续回来看上榜企业营业收入的分布,81.6%的企业营业收入在50亿以下,10-50亿(不含)的企业营业收入在44.8%,10亿以下的占36.8%。整个市场以中小企业为主,很多农业领域新三板挂牌的公司,年营业收入1-2个亿的一抓一大把。

产业结构决定了企业的状态,农业行业地域性很强,边际成本减少和边际收益递增速度,远远不如互联网行业。

第四、上榜企业结构明显,食品加工行业将持续集中

食品企业上榜最多,公司名字里面含有食品的企业有111家,比如温氏食品、龙大食品、三全食品、洽洽食品。

肉制品加工企业和休闲食品加工企业上榜最多。肉制品方面,比如温氏食品、牧原食品、龙大食品,得益于中国人特别爱吃猪肉,50%的猪肉都是中国人消费的,养殖/屠宰方面上市的企业也非常多。

米业也一样,仅从含米的公司统计,就有15家公司上榜,再算上农产品贸易,企业数量就更多了。

第五、选择比努力重要

做事之前,选择正确的方向,远比努力更重要。同一个产业,在不同地方做得到的结果会不一样,同样产业的不同方向,付出同样的努力,获得的结果也不一样。

上榜的中国农业500强,绝大部分企业在90年代就成立了,经过20多年的发展,成为各自领域及行业的佼佼者。

优势资源向头部企业集中将会越来越明显,过去的发展可以理解为一路狂奔,后面的发展则需要考虑运用新的技术升级,考虑消费群体的变化。农业企业出现百年企业的概率更大,欧美很多百年的企业比如农化巨头孟山都、1962年成立的PIC、1936年成立的史密斯菲尔德食品公司等。行业的特点是,发展缓慢,但是稳定,进入该行业,注定难以赚到快钱,一上来全产业链,死得也很快。

其次,在农产品加工、贸易、流通及终端品牌上会有越来越多大而强的企业出现。随着人均收入的增加,消费的食品重点会从芋类、谷类等淀粉质食品逐渐转向畜禽等高蛋白食品。但对食品的消费量不会随着收入的增加而无限增加,当人均GDP超过1万美元时,对增加食品消费的欲望逐渐趋近于零。这意味着,整个行业的价值增长点转移到研发、产品加工及终端销售环节。

数据可视化可以直观的展示数据之间的关系,但数据可视化最重要的不是你展示的工具和做的图多么漂亮,而是紧紧围绕核心目的,把你想表达的内容传递给目标人群。

所以,数据可视化具体呈现形式,取决于你的目的。

数据可视化工具

类别 工具 适用范围
商业智能分析 Tableau 适合BI工程师、数据分析师
PowerBI 配合excel使用
FineBI 中国帆软出品,国内使用更友好,企业级BI
可视化大屏类 DataV
FineRepor 可以数据大屏和可视化报表
前端可视化组件
(前端工程师适用) Canvas 适用于位图,可用于绘制比较复杂的动画
SVG 可缩放矢量图形,经常用于图标和图表上,任意缩放不会失真
WebGL 3D 绘图协议,可在网页浏览器中呈现 3D 画面技术
编程语言 python常用的 Matplotlib、Seaborn、 Bokeh、Plotly、Pyecharts、Mapbox 和 Geoplotlib,其中适用频率最高的Matplotlib 和 Seaborn
R语言 Graphics 以及工具包 ggplot2、ggmap、timevis 和 plotly

工具使用建议:

如果目标是成为数据挖掘工程师或算法工程师,最重要的是了解和使用python数据可视化工具。

推荐使用Tableau—使用范围广。

使用微图、DataV—成本低,上手快。

散点图

用来反映两个变量之间的关系

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  

|

import numpy as np  
import pandas as pd  
import matplotlib.pyplot as plt  
  
# 数据准备  
N = 1000  
x = np.random.randn(N)  
y = np.random.randn(N)  
  
# 用Matplotlib画散点图  
plt.scatter(x, y,marker='x')  
plt.show()  
  

—|—

折线图

用来反映随时间变化后的关系

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  

|

import pandas as pd  
import matplotlib.pyplot as plt  
  
# 数据准备  
x = [2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019]  
y = [5, 3, 6, 20, 17, 16, 19, 30, 32, 35]  
  
# 使用Matplotlib画折线图  
plt.plot(x, y)  
plt.show()  
  

—|—

直方图

反映变量的数值分布

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  

|

import numpy as np  
import pandas as pd  
import matplotlib.pyplot as plt  
  
# 数据准备  
a = np.random.randn(100)  
s = pd.Series(a)  
  
# 用Matplotlib画直方图  
plt.hist(s) #默认为10个直方图plt.hist(x, bins=10)  
plt.show()  
  

—|—

条形图

反映各阶段数值出现的频率

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  

|

import numpy as np  
import pandas as pd  
import matplotlib.pyplot as plt  
  
# 数据准备  
x = ['Cat1', 'Cat2', 'Cat3', 'Cat4', 'Cat5']  
y = [5, 4, 8, 12, 7]  
  
# 用Matplotlib画条形图  
plt.bar(x, y) # plt.bar(x, height) 函数,参数 x 代表位置,height代表y轴的高度  
plt.show()  
  

—|—

箱线图

包括最大值 (max)、最小值 (min)、中位数 (median) 和上下四分位数 (Q3, Q1)几个部分。

用于分析数据差距急离散程度。

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  

|

import numpy as np  
import pandas as pd  
import matplotlib.pyplot as plt  
  
# 数据准备  
# 生成10*4维度数据  
data=np.random.normal(size=(10,4))   
lables = ['A','B','C','D']  
  
# 用Matplotlib画箱线图  
plt.boxplot(data,labels=lables) # 使用 plt.boxplot(x, labels=None),x代表数据,labels添加数据标签  
plt.show()  
  

—|—

饼图

用于表示各部分与分部分的比例。

1  
2  
3  
4  
5  
6  
7  
8  
9  

|

import matplotlib.pyplot as plt  
  
# 数据准备  
nums = [25, 37, 33, 37, 6]  
labels = ['High-school','Bachelor','Master','Ph.d', 'Others']  
  
# 用Matplotlib画饼图  
plt.pie(x = nums, labels=labels) #使用plt.pie(x, labels=None)函数  
plt.show()  
  

—|—

热力图

直观的进行多元分析,不同颜色表示不同类别的数据。

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  

|

import matplotlib.pyplot as plt  
import seaborn as sns # 一般使用seaborn模块  
  
# 数据准备  
flights = sns.load_dataset("flights")  
data=flights.pivot('year','month','passengers')  
  
# 用Seaborn画热力图  
sns.heatmap(data) # 使用sns.heatmap(data),其中data表示数据  
plt.show()  
  

—|—

蜘蛛图

显示多维变量对整体的影响程度

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  

|

import numpy as np  
import matplotlib.pyplot as plt  
import seaborn as sns  
from matplotlib.font_manager import FontProperties    
  
# 数据准备  
labels=np.array([u"推进","KDA",u"生存",u"团战",u"发育",u"输出"])  
stats=[83, 61, 95, 67, 76, 88]  
# 画图数据准备,角度、状态值  
angles=np.linspace(0, 2*np.pi, len(labels), endpoint=False)  
stats=np.concatenate((stats,[stats[0]]))  
angles=np.concatenate((angles,[angles[0]]))  
# 用Matplotlib画蜘蛛图  
fig = plt.figure()  
ax = fig.add_subplot(111, polar=True)     
ax.plot(angles, stats, 'o-', linewidth=2)  
ax.fill(angles, stats, alpha=0.25)  
# 设置中文字体  
font = FontProperties(fname=r"C:\Windows\Fonts\simhei.ttf", size=14)    
ax.set_thetagrids(angles * 180/np.pi, labels, FontProperties=font)  
plt.show()  
  

—|—

二元变量间的关系

可以使用 Seaborn呈现散点图、核密度图、Hexbin图、直方图呈现。

sns.jointplot(x, y, data=None, kind) , kind 表示不同的视图类型:“kind=‘scatter’”代表散点图,“kind=‘kde’”代表核密度图,“kind=‘hex’ ”代表 Hexbin 表示对直方图的二维模拟。

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  

|

import matplotlib.pyplot as plt  
import seaborn as sns  
  
# 数据准备  
tips = sns.load_dataset("tips") # tips为Seaborn中自带的数据集  
print(tips.head(10))  
  
# 用Seaborn画二元变量分布图(散点图,核密度图,Hexbin图)  
sns.jointplot(x="total_bill", y="tip", data=tips, kind='scatter')  
sns.jointplot(x="total_bill", y="tip", data=tips, kind='kde')  
sns.jointplot(x="total_bill", y="tip", data=tips, kind='hex')  
plt.show()  
  

—|—

参考资料

《数据分析实战45讲》|极课时间

ChangeLog

2020907 数据可视化初版

常见的数据来源

类别 解释 例子
开放数据源 重要是行业数据库,政府公开的各类数据 国家统计局、wind、巨潮资讯网
爬虫爬取的数据 通过爬虫取得的数据 豆瓣、社交网站、电商网站、图片网站
传感器采集 通过传感器采集到的数据
日志采集 应用埋点采集到的数据

爬取数据的工具

火车采集器。 可以做抓取工具,也可以做数据清洗、数据分析、数据挖掘和可视化等工作。

八爪鱼。 可以实现自动云采集。

集搜客。 缺点是没有云采集功能,所有爬虫都是在用户自己电脑上跑的。

爬虫的操作流程

爬虫模拟我们日常获取网页信息的流程,通过计算机程序自动化爬取内容。

包括三个阶段:

  • 打开网页。工具为Requests ,数据包括 HTML 页面以及 JSON 数据。
  • 爬取数据。针对HTML页面使用XPath 提取数据,针对JSON数据使用JSON 库进行解析。
  • 保存数据。可以使用Pandas 保存数据,导出为CSV 文件。

三个阶段解析

Requests

Requests有两种访问方式,Get和Post。

其中Get把参数包含在链接中。

1  

|

r = requests.get('http://www.douban.com')  
  

—|—

Post通过request body传递参数。

1  

|

r = requests.post('http://xxx.com', data = {'key', 'value'})  
  

—|—

data的数据结构是字典,通过key 和 value 对数据储存。

动态数据需要通过XHR发出HTTP请求。

Xpath

XPath 是 XML 的路径语言,帮助定位位置。

使用Xpath解析规则

在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。

表达式 描述
node 选取此节点的所有子节点
/ 从根节点选取
// 选取所有的当前节点,不考虑位置
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性
或,两个节点的合并
text() 当前路径下的文版内容

下面用这个网站上的例子举例:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  

|

<?xml version="1.0" encoding="ISO-8859-1"?>  
  
<bookstore>  
  
<book>  
  <title lang="eng">Harry Potter</title>  
  <price>29.99</price>  
</book>  
  
<book>  
  <title lang="eng">Learning XML</title>  
  <price>39.95</price>  
</book>  
  
</bookstore>  
  

—|—

路径表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position()<3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang=’eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

xpath(’//@id’) 选取所有的 id 属性;

xpath(’//book[@id]’) 选取所有拥有名为 id 的属性的 book 元素;

xpath(’//book[@id=“abc”]’) 选取所有 book 元素,且这些 book 元素拥有 id= “abc”的属性;

xpath(’//book/title | //book/price’) 选取 book 元素的所有 title 和 price 元素。

定位到所有列表项目,需要使用lxml,下面代码为定位到HTML所有列表函数。

1  
2  
3  

|

from lxml import etree  
html = etree.HTML(html)  
result = html.xpath('//li')  
  

—|—

JSON

Json.dumps():将python对象转换成ISON对象。

Json.load():将python对象转换成JSON对象。

1  
2  
3  
4  
5  
6  
7  

|

import json  
  
jsonData = '{"a":1,"b":2,"c":3,"d":4,"e":5}';  
  
input = json.loads(jsonData)  
  
print(input)  
  

—|—

输出结果为:

1  

|

{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}  
  

—|—

项目实战:爬取葛优相关图片

步骤一:打开网页

打开豆瓣图片,输入关键词葛优

image-20200901195719609

步骤二:选择图片

在搜索结果中,可以看到网页是动态的(即往下滑可以看到更多的图片),动态数据需要通过XHR发出HTTP请求,此处需要知道JSON。

我们先来寻找XHR结构,方法是通过:1)谷歌浏览器右键单击检查;2)选择Network;3)选择XHR;4)刷新页面。从图片中可以看到共有1724张葛优相关的图片。

image-20200901200213885

从上图最下面的方框中可以看到JSON。可以看到数据被放到images里面,每张图片通过字典形式储存,元数据包含author、height、id、src、title、width等信息,有了这些信息,我们便可以提取需要的数据。

在看一下图片的组成,limit:20,最大可以显示20张,第一张图片从0开始,我们便可以写个for循环实现所有的下载。

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  

|

images: [{src: "https://img3.doubanio.com/view/photo/photo/public/p399074242.jpg", author: "饭",…},…]  
0: {src: "https://img3.doubanio.com/view/photo/photo/public/p399074242.jpg", author: "饭",…}  
author: "饭"  
height: 600  
id: "399074242"  
src: "https://img3.doubanio.com/view/photo/photo/public/p399074242.jpg"  
title: "葛优"  
url: "https://www.douban.com/link2/?url=http%3A%2F%2Fwww.douban.com%2Fphotos%2Fphoto%2F399074242%2F&query=%E8%91%9B%E4%BC%98&cat_id=1025&type=search"  
width: 414  
limit: 20  
more: true  
total: 1724  
  

—|—

提取需要的信息

找到了网页及所需要的信息,接下里就是提取所需要的数据,并且进行储存。

完整代码如下:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  

|

# -*- coding:utf-8 -*-  
import requests  
import json  
query = '葛优'  
  
# 下载图片  
def download(src, id):  
  dir = './' + str(id) + '.jpg'  
  try:  
    pic = requests.get(src, timeout=10)  
    fp = open(dir, 'wb')  
    fp.write(pic.content)  
    fp.close()  
  except requests.exceptions.ConnectionError:  
    print('图片无法下载')  
              
# for 循环 请求全部的 url  
for i in range(0, 1723, 20):  
  url = 'https://www.douban.com/j/search_photo?q='+query+'&limit=20&start='+str(i)  
  html = requests.get(url).text    # 得到返回结果  
  response = json.loads(html, encoding='utf-8') # 将 JSON 格式转换成 Python 对象  
  for image in response['images']:  
    print(image['src']) # 查看当前下载的图片网址  
    download(image['src'], image['id']) # 下载一张图片  
  

—|—

参考资料

Xpath教程

ChangeLog

20201029 补充Xpath案例,仍然出现错误Expecting value: line 1 column 1 (char 0)

20200901 爬虫代码运行错误

1.初识Pandas

Pandas 是“Python的核心数据分析支持库,提供了快速、灵活、明确的数据结构,旨在简单、直观地处理关系型、标记型数据”,主要数据结构是 Series(一维数据)与 DataFrame(二维数据),这两种数据结构可以处理金融、统计、社会科学、工程等领域里的大多数典型用例。

2.数据结构

2.1 Series数据结构

1  
2  
3  
4  
5  
6  
7  
8  
9  

|

import numpy as np  
import pandas as pd  
  
s = pd.Series([1, 3, 5, np.nan, 6, 8])  
  
print(s)  
  
d = pd.Series([1, 3, 5, 7], index=['a', '1', 'c', 3])  
print(d)  
  

—|—

输出结果为:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  

|

0    1.0  
1    3.0  
2    5.0  
3    NaN  
4    6.0  
5    8.0  
dtype: float64  
    
a    1  
1    3  
c    5  
3    7  
dtype: int64  
  

—|—

数据结构为Series([1, 3, 5, 6], index=[‘a’, ‘b’, ‘c’, ‘d’])。index默认结构为0、1、2、3……

从上面的运行结果可以看出,index后面的文本型结构’a’,必须加引号,否则会报错,而数字是否加引号虽不影响,单加不加引号,数据类型完全不同。

除了采用index外,还可以采用字典形式,如下:

1  
2  
3  
4  
5  
6  
7  
8  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
d = {'a':1, 'b':2, 'c':3, 'd':4}  
  
x1 = Series(d)  
  
print(x1)  
  

—|—

输出结果为:

1  
2  
3  
4  
5  

|

a    1  
b    2  
c    3  
d    4  
dtype: int64  
  

—|—

2.2 DataFrame 数据结构

DataFrame可以理解为两个Series构成的数组结构,在语法上完全相同。

1  
2  
3  
4  
5  
6  
7  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
data = {'列1':[1, 2, 3, 4], '列2':[5, 6, 7, 8], '列3':[0, 9, 6, 8]}  
df2 = DataFrame(data, index=['one', 'two', 'three', 'four'], columns=['列1', '列2', '列3'])  
  
print(df2)  
  

—|—

输出结果为:

1  
2  
3  
4  
5  

|

       列1  列2  列3  
one     1   5   0  
two     2   6   9  
three   3   7   6  
four    4   8   8  
  

—|—

2.3 导入和导出

Pandas 可以从xlsx, csv中导入数据,也可以输出数据为xlsx, csv。

1  
2  
3  
4  
5  

|

# 写入csv  
df.to_csv('foo.csv')  
  
# 读取csv  
pd.read_csv('foo.csv')  
  

—|—

3.数据清洗

3.1 删除

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
data = {'列1':[1, 2, 3, 4], '列2':[5, 6, 7, 8], '列3':[0, 9, 6, 8]}  
df2 = DataFrame(data, index=['one', 'two', 'three', 'four'], columns=['列1', '列2', '列3'])  
  
# 数据删除使用drop()  
df2 = df2.drop(columns=['列1'])  
df2 = df2.drop(index=['one'])  
  
print(df2)  
  

—|—

3.2 去除重复的值

1  

|

df = df.drop_duplicates() #去除重复行  
  

—|—

3.3 重命名

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
data = {'列1':[1, 2, 3, 4], '列2':[5, 6, 7, 8], '列3':[0, 9, 6, 8]}  
df2 = DataFrame(data, index=['one', 'two', 'three', 'four'], columns=['列1', '列2', '列3'])  
  
# 重命名使用rename(columns=new_names, inplace=True) 函数  
df2.rename(index={'one':'第1', 'two':'第2'}, inplace=True)  
  
print(df2)  
  

—|—

3.4 格式相关

使用astype转换格式

1  
2  
3  
4  
5  
6  
7  
8  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
data = {'列1':[1, 2, 3, 4], '列2':[5, 6, 7, 8], '列3':[0, 9, 6, 8]}  
df2 = DataFrame(data, index=['one', 'two', 'three', 'four'], columns=['列1', '列2', '列3'])  
  
df2['列1'].astype('str')  
df2['列1'].astype(np.int64)  
  

—|—

去除数据之间的空格strip

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
data = {'列1':[1, 2, 3, 4], '列2':[5, 6, 7, 8], '列3':[0, 9, 6, 8]}  
df2 = DataFrame(data, index=['one', 'two', 'three', 'four'], columns=['列1', '列2', '列3'])  
  
# 删除左右两边的空格  
df2['one'] = df2['one'].map(str.strip)  
  
# 删除左边的空格  
df2['one'] = df2['one'].map(str.lstrip)  
  
# 删除右边的空格  
df2['one'] = df2['one'].map.(str.rstrip)  
  
# 删除特殊的字符  
df2['one']=df2['one'].str.strip('$')  
  

—|—

大小写转换

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
data = {'chinese':[1, 2, 3, 4], 'math':[5, 6, 7, 8], 'English':[0, 9, 6, 8]}  
df2 = DataFrame(data, index=['one', 'two', 'three', 'four'], columns=['chinese', 'math', 'English'])  
  
# 全部大写  
df2.columns = df2.columns.str.upper()  
  
# 全部小写  
df2.columns = df2.columns.str.lower()  
  
# 首字母大写  
df2.columns = df2.columns.str.title()  
  
print(df2)  
  

—|—

1  
2  
3  
4  
5  
6  
7  
8  

|

# 下面这两行代码也可以一行代码  
data = {'chinese':[1, 2, 3, 4], 'math':[5, 6, 7, 8], 'English':[0, 9, 6, 8]}  
df2 = DataFrame(data, index=['one', 'two', 'three', 'four'], columns=['chinese', 'math', 'English'])  
  
  
df2 = pd.DataFrame({'chinese':[1, 2, 3, 4],   
                     'math':[5, 6, 7, 8],  
                    'English':[0, 9, 6, 8]},index=['one', 'two', 'three', 'four'] )  
  

—|—

查找空值

查找空值使用

1  

|

df.isnull()  
  

—|—

3.5 apply 函数对数据进行清洗

@todo

4.数据分析

Pandas常用的统计函数用法和NumPy类似(资料来源极课时间|数据分析实战45讲),如下:

img

使用describe()函数可以输出所有的统计指标

1  
2  
3  
4  
5  
6  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
df1 = DataFrame({'name':['ZhangFei', 'GuanYu', 'a', 'b', 'c'], 'data1':range(5)})  
  
print(df1.describe())  
  

—|—

输出结果如下:

1  
2  
3  
4  
5  
6  
7  
8  
9  

|

   data1  
count  5.000000  
mean   2.000000  
std    1.581139  
min    0.000000  
25%    1.000000  
50%    2.000000  
75%    3.000000  
max    4.000000  
  

—|—

5.数据表合并

比如下面两个数据表需要合并,使用的是merge()函数。

1  
2  

|

df1 = DataFrame({'name':['One', 'two', 'a', 'b', 'c'], 'data1':range(5)})  
df2 = DataFrame({'name':['one', 'Two', 'A', 'B', 'C'], 'data2':range(5)})  
  

—|—

5.1 基于指定列进行连接

1  
2  
3  
4  
5  
6  
7  
8  
9  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
df1 = DataFrame({'name':['One', 'Two', 'a', 'b', 'c'], 'data1':range(5)})  
df2 = DataFrame({'name':['One', 'Two', 'A', 'B', 'C'], 'data2':range(5)})  
  
df3 = pd.merge(df1, df2, on='name')  
  
print(df3)  
  

—|—

输出结果

1  
2  
3  

|

name  data1  data2  
0  One      0      0  
1  Two      1      1  
  

—|—

5.2 inner内链接

相当于求两个DataFrame的交集。

1  
2  
3  
4  
5  
6  
7  
8  
9  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
df1 = DataFrame({'name':['One', 'Two', 'a', 'b', 'c'], 'data1':range(5)})  
df2 = DataFrame({'name':['One', 'Two', 'A', 'B', 'C'], 'data2':range(5)})  
  
df3 = pd.merge(df1, df2, how='inner')  
  
print(df3)  
  

—|—

输出结果为

1  
2  
3  

|

  name  data1  data2  
0  One      0      0  
1  Two      1      1  
  

—|—

5.3 outer外链接

相当于求两个 DataFrame 的并集

1  
2  
3  
4  
5  
6  
7  
8  
9  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
df1 = DataFrame({'name':['One', 'Two', 'a', 'b', 'c'], 'data1':range(5)})  
df2 = DataFrame({'name':['One', 'Two', 'A', 'B', 'C'], 'data2':range(5)})  
  
df3 = pd.merge(df1, df2, how='outer')  
  
print(df3)  
  

—|—

输出结果为:

1  
2  
3  
4  
5  
6  
7  
8  
9  

|

 name  data1  data2  
0  One    0.0    0.0  
1  Two    1.0    1.0  
2    a    2.0    NaN  
3    b    3.0    NaN  
4    c    4.0    NaN  
5    A    NaN    2.0  
6    B    NaN    3.0  
7    C    NaN    4.0  
  

—|—

5.4 left左链接

第一个 DataFrame 为主进行的连接,第二个 DataFrame 作为补充

1  
2  
3  
4  
5  
6  
7  
8  
9  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
df1 = DataFrame({'name':['One', 'Two', 'a', 'b', 'c'], 'data1':range(5)})  
df2 = DataFrame({'name':['One', 'Two', 'A', 'B', 'C'], 'data2':range(5)})  
  
df3 = pd.merge(df1, df2, how='left')  
  
print(df3)  
  

—|—

输出结果为:

1  
2  
3  
4  
5  
6  

|

name  data1  data2  
0  One      0    0.0  
1  Two      1    1.0  
2    a      2    NaN  
3    b      3    NaN  
4    c      4    NaN  
  

—|—

5.5 right右链接

第二个 DataFrame 为主进行的连接,第一个 DataFrame 作为补充

1  
2  
3  
4  
5  
6  
7  
8  
9  

|

import pandas as pd  
from pandas import Series,DataFrame  
  
df1 = DataFrame({'name':['One', 'Two', 'a', 'b', 'c'], 'data1':range(5)})  
df2 = DataFrame({'name':['One', 'Two', 'A', 'B', 'C'], 'data2':range(5)})  
  
df3 = pd.merge(df1, df2, how='right')  
  
print(df3)  
  

—|—

输出结果为:

1  
2  
3  
4  
5  
6  

|

 name  data1  data2  
0  One    0.0      0  
1  Two    1.0      1  
2    A    NaN      2  
3    B    NaN      3  
4    C    NaN      4  
  

—|—

参考资料

Pandas中文网

极课时间|数据分析实战45讲-陈旸

ChangeLog

20201026 完成1-3.4

20201027 完成3.5-5

NumPy可以用来干什么?

在python里面已经有了列表list,为什么还要使用NumPy?

这和list与NumPy在数据储存和运算速度有关。提升内存和计算资源的利用效率。

NumPy最重要的知识包括:

  • ndarray(N-dimensional array object),解决多维数组问题,
  • ufunc(universal function object),解决对数组进行处理的函数。

ndarray

array表示数据,ndarray代表多维数组。

创建数组

1  
2  
3  
4  
5  
6  
7  
8  

|

import numpy as np  
a = np.array([1, 2, 3])  
b = np.array([[1, 1, 2], [2, 3, 5], [3, 4, 5]])  
b[1, 1]=10  
print(a.shape)  
print(b.shape)  
print(a.dtype)  
print(b)  
  

—|—

输出结果为

1  
2  
3  
4  
5  
6  

|

(3,)  
(3, 3)  
int64  
[[ 1  1  2]  
 [ 2 10  5]  
 [ 3  4  5]]  
  

—|—

总结:

  • shape用于获取数组的大小;
  • dtype用于获取数组的属性;
  • b[1, 1]表示对数组进行修改,从零开始计数,上面代码把b中的每个数组看成一个整体,当成一个数。

结构数组

创建储存每个数字单元的表格。

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  

|

import numpy as np  
# 定义数组结构  
persontype = np.dtype({  
  'names':['name', 'age', 'chinese', 'math', 'English'],  
  'formats':['S32', 'i', 'i', 'i', 'f']})  
  
peoples = np.array([('A', 1, 2, 3, 4),   
                    ('B', 4, 6, 7, 8),  
                    ('C', 0, 8, 8, 5),  
                    ('D', 3, 7, 8, 1)],  
                   dtype = persontype)  
  
ages = peoples[:]['age']  
chineses = peoples[:]['chinese']  
maths = peoples[:]['math']  
Englishs = peoples[:]['English']  
  
# 计算平均值  
print(np.mean(ages))  
print(np.mean(chineses))  
print(np.mean(maths))  
print(np.mean(Englishs))  
  

—|—

输出结果为:

1  
2  
3  
4  

|

2.0  
5.75  
6.5  
4.5  
  

—|—

ufunc

universal function的缩写。

创建连续数组

1  
2  
3  
4  
5  
6  

|

import numpy as np  
x1 = np.arange(1, 11, 2)  
x2 = np.linspace(1, 9 ,5)  
  
print(x1)  
print(x2)  
  

—|—

输出结果为:

1  
2  

|

[1 3 5 7 9]  
[1. 3. 5. 7. 9.]  
  

—|—

arange是range的内置函数,arange(1, 11, 2)分别代表初始值、终值、步长

linspaces是linear space的缩写,代表线性等分向量。linespace(1, 9,5)分别代表初始值,重值(含),元素个数。

运算

基本运算

可以进行加、剪、乘、除、n次方,取余数等运算

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  

|

import numpy as np  
x1 = np.arange(1, 11, 2)  
x2 = np.linspace(1, 9 ,5)  
  
print(np.add(x1, x2))  
print(np.subtract(x1, x2))  
print(np.multiply(x1, x2))  
print(np.divide(x1, x2))  
print(np.power(x1, x2))  
print(np.remainder(x1, x2))  
  

—|—

输出结果为:

1  
2  
3  
4  
5  
6  
7  

|

[ 2.  6. 10. 14. 18.]  
[0. 0. 0. 0. 0.]  
[ 1.  9. 25. 49. 81.]  
[1. 1. 1. 1. 1.]  
[1.00000000e+00 2.70000000e+01 3.12500000e+03 8.23543000e+05  
 3.87420489e+08]  
[0. 0. 0. 0. 0.]  
  

—|—

在进行计算时,需要保证数组的秩相同,即每个列表的元素个数相同,方可进行运算。

统计学相关的运算

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  

|

# -*- coding:utf-8 -*-  
  
import numpy as np  
  
a = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])  
  
print(np.amin(a)) # 最小值  
print(np.amin(a, 0)) # 每一列中的的最小值  
print(np.amin(a, 1)) # 每一行中的最小值  
print(np.amax(a)) # 最大值  
print(np.amax(a, 0)) # 每一列中的最大值  
print(np.amax(a, 1)) # 每一行的最小值  
  
# 统计最大值与最小值之差  
print(np.ptp(a))  
print(np.ptp(a, 0))  
print(np.ptp(a, 1))  
  
# 求中位数与平均数  
print(np.median(a)) # 整体列表中位数  
print(np.median(a, axis=0)) # 求每一列的中位数  
print(np.median(a, axis=1)) # 求每一行的中位数  
print(np.mean(a)) # 求整体列表的平均数  
print(np.mean(a, axis=0)) # 求每一列的平均数  
print(np.mean(a, axis=1)) # 求每一行的平均数  
  
# 求加权平均数  
a = np.array([1, 2, 3, 4])  
wts = np.array([1, 2, 3, 4])  
print(np.average(a)) # 默认权重相同  
print(np.average(a, weights=wgt)) # 赋予不同权重 (1*1=2*2+3*3+4*4)/(1+2+3+4)  
  
# 求标准差方差  
print(np.std(a)) # 标注差  
print(np.var(a)) # 方差  
  

—|—

输出结果为:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  

|

1  
[1 2 3]  
[1 4 7]  
9  
[7 8 9]  
[3 6 9]  
  
8  
[6 6 6]  
[2 2 2]  
  
5.0  
[4. 5. 6.]  
[2. 5. 8.]  
5.0  
[4. 5. 6.]  
[2. 5. 8.]  
  
2.5  
3.0  
  
1.118033988749895  
1.25  
  

—|—

从行列式角度理解,axis=0表示列,axis=1表示行。

NumPy进行排序

排序在数据分析中使用频率很高,一般排序语句结构为:

1  

|

sort(a, axis=-1, kind=‘quicksort’, order=None)  
  

—|—

默认情况下axis=-1,表示对内部列表分别排序。当axis=None时,表示把所有数字按照一个列表排序。

Kind包含三种结构:quicksort、mergesort、heapsort ,分别代表快速排序、合并排序、堆排序。默认情况下,使用的是quicksort排序。

1  
2  
3  
4  
5  
6  
7  
8  

|

import numpy as np  
  
a = np.array([[14, 55, 9], [45, 56, 87], [90, 3, 45]])  
  
print(np.sort(a))  
print(np.sort(a, axis=None))  
print(np.sort(a, axis=0))  
print(np.sort(a, axis=1))  
  

—|—

输出结果为:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  

|

[[ 9 14 55]  
 [45 56 87]  
 [ 3 45 90]]  
[ 3  9 14 45 45 55 56 87 90]  
[[14  3  9]  
 [45 55 45]  
 [90 56 87]]  
[[ 9 14 55]  
 [45 56 87]  
 [ 3 45 90]]  
  

—|—

参考资料

《数据分析实战45讲》-极课时间 陈旸

ChangeLog

20201025 完成基本内容

输入输出

1  
2  
3  
4  

|

name = input("What's is your name?")  
a = 1 + 1  
print('hello, %s' %name)  
print('a = %d' %a)  
  

—|—

输出结果为:

1  
2  
3  

|

What's your name?y  
hello,y  
a = 2  
  

—|—

判断语句

1  
2  
3  
4  
5  
6  
7  
8  

|

score = int(input("What's your score?"))  
if score>= 90:  
       print('Excellent')  
else:  
       if score < 60:  
           print('Fail')  
       else:  
           print('Good Job')  
  

—|—

循环语句:for … in

1  
2  
3  
4  

|

sum = 0  
for number in range(11):  
    sum = sum + number  
print(sum)  
  

—|—

输出结果为;

1  

|

55  
  

—|—

循环语句: while

1  
2  
3  
4  
5  
6  
7  

|

sum = 1  
number = 2  
while number <=100:  
  sum = sum + number  
  number = number + 1  
print(sum)  
print(number)  
  

—|—

输出结果为:

1  
2  

|

5050  
101  
  

—|—

数据类型:列表、元组、字典、集合

列表[]

1  
2  
3  
4  
5  
6  
7  

|

lists = ['a','b','c']  
lists.append('d')  
print(lists)  
print(len(lists))  
lists.insert(0,'mm')  
lists.pop()  
print(lists)  
  

—|—

输出结果为:

1  
2  
3  

|

['a', 'b', 'c', 'd']  
4  
['nm', 'a', 'b', 'c']  
  

—|—

增:append() 在尾部添加元素、使用 insert() 在列表中插入元素

删:使用 pop() 删除尾部的元素

查:len() 函数获得 lists 中元素的个数

元组 (tuple)

1  
2  
3  
4  

|

tuples = ('tupleA','tupleB')  
print(tuples[0])  
print(tuples[1])  
print(tuples[-1])  
  

—|—

输出结果为:

1  
2  
3  

|

tupleA  
tupleB  
tupleB  
  

—|—

元组和列表相同,但是初始化后不能够增加和删除元素,上面程序表示的是元素的查找。

字典 {dictionary}

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  

|

# -*- coding: utf-8 -*-  
#定义一个dictionary  
score = {'guanyu':95,'zhangfei':96}  
#添加一个元素  
score['zhaoyun'] = 98  
print(score)  
  
#删除一个元素  
score.pop('zhangfei')  
print(score)  
  
#查看key是否存在  
print('guanyu' in score)  
  
#查看一个key对应的值  
print(score.get('guanyu'))  
print(score.get('yase',99))  
  

—|—

输出结果为:

1  
2  
3  
4  
5  

|

{'guanyu': 95, 'zhangfei': 96, 'zhaoyun': 98}  
{'guanyu': 95, 'zhaoyun': 98}  
True  
95  
99  
  

—|—

增:score[‘zhaoyun’] = 98

删:score.pop()

查:是否存在用print(‘guanyu’ in score)、对应值用print(score.get(‘guanyu’))

集合:set

1  
2  
3  
4  
5  
6  
7  
8  

|

s = set(['a', 'b', 'c'])  
# 增加某个元素  
s.add('d')  
# 移除某个元素  
s.remove('b')  
print(s)  
# 查找某个元素  
print('c' in s)  
  

—|—

输出结果为:

1  
2  

|

{'d', 'a', 'c'}  
True  
  

—|—

集合和字典类似,但在增删查语法上有所区别:

增: add

删:remove

查:使用 in

函数:def

1  
2  
3  

|

def addone(score):  
   return score + 1  
print(addone(99))  
  

—|—

输出结果为:

1  

|

100  
  

—|—

注释

使用# -*- coding: utf-8 -*-,单行注释使用#,多行注释可以使用三个单引号’’’ ‘’’。

引用模块 / 包:import

引用直接使用import module_name调动即可,import本质上是路径的搜索。

针对package,可以采用from … import …,这实际是从一个目录中引用模块

参考资料

《数据分析实战45讲》-极课时间 陈旸

0%