0%

很多同学对Anaconda和Jupyter Notebook的安装与配置有疑惑,这里对课程中的选修:配置Anaconda和Jupyter Notebook作为一个补充。

Anaconda

安装

点击下载链接,先选择你的操作系统,然后选择Python 3.7 version版本下载。

Fu1fsg.png

安装过程中,记得这里的两个框,都勾选上。

Fu1Ids.png


常用软件

安装完Anaconda之后,Windows用户可以通过开始-所有程序找到Anaconda的文件夹,在文件夹下有三个程序是你经常会用到的,分别是:

Anaconda Prompt:这里就是Anaconda的控制台,你进行第三方包的管理编程环境的管理都是在这里进行。但是现阶段用不到。

Jupyter Notebook:使用非常非常频繁的web文档,在项目三和项目四中都会用到。

Spyder:python的IDE(集成开发环境),在项目二中会用到。

Fu3BlT.png

Jupter Notebook

notebook的使用技巧在教室内说得很详细了,这里只补充一点,那就是如何在你工作的文件夹下使用notebook。

1. 进入到工作文件夹

2.按住Shift键,然后右击,选择“在此处打开命令窗口”

Fu3LtI.png

3.输入jupyter notebook,回车

Fu3j9P.png

4.notebook即会在你的默认浏览器中弹出,目录即为该路径下的文件

注意:不要关掉弹出notebook的命令窗口,这是将notebook与你电脑内的python链接的纽带。

Fu89BQ.png

Spyder

我们将会在项目二中用到Spyder这个软件,这个软件也没什么操作难度,所以课程内没有讲解。

我在这里给大家具体讲一下吧。

打开

Windows用户依次点击开始-所有程序-Anaconda-Spyder即可。

界面

Fu8rCt.png

如上,我们可以把Spyder的界面划分为5个部分,分别为:

菜单栏:就是一些新建、打开、运行、终止等等操作,自行摸索

选择工作区:这里可以选择工作区路径

代码编辑区:这里就是你写代码的地方

程序变量/文件路径查看区:通过选择箭头标注的选项卡,可以显示代码中的变量,或者是当前路径下的文件

控制台:这里就是显示你代码运行结果的地方,如果代码运行卡住了,可以通过点该区域右上角的终止运行。

使用流程

先确定工作路径,然后新建脚本,开始编写代码、运行(快捷键F5)、调试。

做完项目二,大家就能熟练操作啦,不要担心~

概述

Mini-Batch Gradient Descent是介于batch gradient descent(BGD)和stochastic gradient descent(SGD)之间的一种线性回归优化算法,它是将数据分为多个小的数据集(batches),每个数据集具有大致相同的点数,然后在每个数据集中应用Absolute Trick或者是Square Trick算法,来更新回归系数。

它的运算速度比BSD快,比SGD慢;精度比BSD低,比SGD高。

代码

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)

def MSEStep(X, y, W, b, learn_rate = 0.001):
"""
This function implements the gradient descent step for squared error as a
performance metric.

Parameters
X : array of predictor features
y : array of outcome values
W : predictor feature coefficients
b : regression function intercept
learn_rate : learning rate

Returns
W_new : predictor feature coefficients following gradient descent step
b_new : intercept following gradient descent step
"""

# compute errors
# the squared trick formula
y_pred = np.matmul(X, W) + b #Attention:the order of X and W
error = y - y_pred
#y_pred is a 1-D array,so is the error

# compute steps
W_new = W + learn_rate * np.matmul(error, X) #Attention:the order of X and error
b_new = b + learn_rate * error.sum()
return (W_new, b_new)

def miniBatchGD(X, y, batch_size = 20, learn_rate = 0.005, num_iter = 25):
"""
This function performs mini-batch gradient descent on a given dataset.

Parameters
X : array of predictor features
y : array of outcome values
batch_size : how many data points will be sampled for each iteration
learn_rate : learning rate
num_iter : number of batches used

Returns
regression_coef : array of slopes and intercepts generated by gradient
descent procedure
"""
n_points = X.shape[0]
W = np.zeros(X.shape[1]) # coefficients
b = 0 # intercept

# run iterations
#hstack为水平堆叠函数 为什么要堆叠呢?
#类似zip,可以实现for W,b in regression_coef:print W,b来提取W和b
regression_coef = [np.hstack((W,b))]
for _ in range(num_iter):
#从0-100中随机选择batch_size个数,作为batch
batch = np.random.choice(range(n_points), batch_size)
#按照batch从X中选出数据
X_batch = X[batch,:]#为2-D矩阵
y_batch = y[batch]#为1-D数组
W, b = MSEStep(X_batch, y_batch, W, b, learn_rate)
regression_coef.append(np.hstack((W,b)))

return (regression_coef)

if __name__ == "__main__":
# perform gradient descent
data = np.loadtxt('data.csv', delimiter = ',')
X = data[:,:-1]#提取第一列,为2-D矩阵
y = data[:,-1]#提取第二列,为1-D数组
regression_coef = miniBatchGD(X, y)

# plot the results
plt.figure()
X_min = X.min()
X_max = X.max()
counter = len(regression_coef)
for W, b in regression_coef:
counter -= 1
#color为[R,G,B]的列表,范围都在0-1之间,[0,0,0]为黑色,[1,1,1]为白色
color = [1 - 0.92 ** counter for _ in range(3)]
#绘制一条点(X_min,X_min * W + b)与点(X_max, X_max * W + b)之间的一条直线
plt.plot([X_min, X_max],[X_min * W + b, X_max * W + b], color = color)
plt.scatter(X, y, zorder = 3)
plt.show()

结果

FldOgg.png

在结果中,颜色最浅的是最开始的回归线,最深的则为最终的回归线。

详解

理论知识参见Linear Regression 总结,这里只对代码中出现的新函数或新用法进行讲解。

numpy.matmul(a,b)

该函数用来计算两个arrays的乘积。

需要注意的是,由于a和b维度的不同,会使得函数的结果计算方式不同,一共三种:

  • 如果a和b都是2维的,则做普通矩阵乘法

    1
    2
    3
    a = [[1, 0], [0, 1]]
    b = [[4, 1], [2, 2]]
    np.matmul(a, b)
    1
    2
    3
    out:
    array([[4, 1],
    [2, 2]])
  • 如果a和b中有一个是大于2维的,则会将其理解为多个矩阵stack后的结果,进行计算时也会进行相应的拆分运算

    1
    2
    3
    a = np.arange(2*2*4).reshape((2,2,4))
    b = np.arange(2*2*4).reshape((2,4,2))
    np.matmul(a,b).shape
    1
    2
    out:
    (2, 2, 2)

    a被理解为2个2x4矩阵的stack

    1
    2
    3
    4
    5
    array([[[ 0,  1,  2,  3],
    [ 4, 5, 6, 7]],

    [[ 8, 9, 10, 11],
    [12, 13, 14, 15]]])

    b被理解为2个4x2矩阵的stack

    1
    2
    3
    4
    5
    6
    7
    8
    9
    array([[[ 0,  1],
    [ 2, 3],
    [ 4, 5],
    [ 6, 7]],

    [[ 8, 9],
    [10, 11],
    [12, 13],
    [14, 15]]])

    np.matmul(a,b)会将a中的两个矩阵与b中的两个矩阵对应相乘,每对相乘的结果都是一个2x2的矩阵,所以结果就是一个2x2x2的矩阵。

  • 如果a或b有一个是一维的,那么就会为该一维数组补充1列或1行,进而提升为二维矩阵,然后用非补充行或列去和另外一个二维矩阵进行运算,得到的结果再将补充的1去掉。(这个是最难理解的,可以多测试下,用代码结果理解

    1
    2
    3
    a = [[1, 0], [0, 1]]
    b = [1, 2]
    np.matmul(a, b)
    1
    2
    out:
    array([1, 2])

    a是一个2x2的矩阵,b是一个shape为(2,)的一维数组,那么matmul的计算步骤如下:

    • 计算中,矩阵a在前,数组b在后,所以需要让a的列数与升维之后b矩阵的行数相等
    • 所以,升维后b矩阵的shape应为(2,1),这个1添加到了列上
    • 进行矩阵乘法计算,得到shape为(2,1),这时候再将这个1去掉
    • 最终结果的shape为(2,),变为一维数组

    我们试着将a与b的顺序对调,看一下matmul是怎么计算的:

    • 对调后,数组b在前,矩阵a在后,需要将升维后b矩阵的列数与矩阵a的行数相等
    • 所以,升维后b矩阵的shape应该为(1,2),这个1添加到了行上
    • 进行矩阵乘法,得到的shape为(1,2),将这个1去掉
    • 最终结果的shape为(2,),变为一维数组

numpy.hstack()

我们先来看看numpy.stack()函数。

  • 函数用法为:numpy.stack(arrays,axis = 0)
  • 第一个参数为arrays,可以输入多维数组或者列表,也可以输入由多个一维数组或列表组成的元组
  • 第二个参数为axis,输入数字,决定了按照arrays的哪个维度进行stack。比如说,输入的arrays的shape为(3,4,3),那么axis = 0/1/2就分别对应arrays的组/行/列。

这个函数中的axis有些抽象,我们看具体示例:

  • 定义了一个列表

F1PSIS.png

结果的排版有点问题,为了方便后面对照,把结果对齐如下:

1
2
3
4
5
[
array([[0,1,2],[3,4,5]]),
array([[0,1,2],[3,4,5]]),
array([[0,1,2],[3,4,5]])
]
  • axis = 0,则按照第0个维度进行堆叠,即:

    F1PqFU.png

    结果为:

    F1PLYF.png

  • axis = 1,则按照第1个维度进行堆叠,即:

    F1Pvl9.png

    结果为:

    F1PzO1.png

  • axis = 2,则按照第二个维度进行堆叠,即:

    F13zdO.png

    结果为:

    1544074512445

    这个基本很少用到。

**numpy.hstack()**函数就是horizontal(水平)方向的堆叠,示例:

F18qAS.png

**numpy.vstack()**函数就是在垂直方向堆叠。

ndarray的切片

一维ndarray的切片方式和list无异,这里主要讲一下二维矩阵的切片方法。

  • 矩阵切片
1
2
a = np.arange(4*4).reshape(4,4)
print(a)
1
2
3
4
5
out:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
1
a[:,:-1]
1
2
3
4
5
out:
array([[ 0, 1, 2],
[ 4, 5, 6],
[ 8, 9, 10],
[12, 13, 14]])

这里可以看出,我们筛选了a矩阵中前三列的所有行,这是如何实现的呢?

切片的第一个元素:表示的是选择所有行,第二个元素:-1表示的是从第0列至最后一列(不包含),所以结果如上所示。

再看一个例子:

1
a[1:3,:]
1
2
3
out:
array([[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])

筛选的是第2-3行的所有列。

  • 一个常用的切片

以列的形式获取最后一列数据:

1
a[:,3:]
1
2
3
4
5
out:
array([[ 3],
[ 7],
[11],
[15]])

以一维数组的形式获取最后一列数据:

1
a[:,-1]
1
2
out:
array([ 3, 7, 11, 15])

上面两种方法经常会用到,前者的shape为(4,1),后者为(4,)。

matplotlib相关

  • color

    代码中涉及到的语句为:

    1
    color = [1 - 0.92 ** counter for _ in range(3)]

    matplotlib中的color可以输入RGB格式,即[R,G,B],这里值得注意的是它们的取值范围都在0到1之间,其中[0,0,0]为黑色,[1,1,1]为白色。

    在如上语句中,列表由三个相等的数值元素组成,保证了颜色为白-灰-黑,数值随着counter的减小,由1趋近于0,反映在可视化上就是颜色由白逐渐变黑。

    这真是一个画渐变过程的好方法呀!!!

  • plot([x_1,x_2],[y_1,y_2])

    这里就是两点式绘图,根据点(x_1,y_1)和点(x_2,y_2)画一条直线。

  • zorder

    也就是z-order,类似于PS里面的图层顺序,下面的图层会被上面的图层遮挡。

    参考Zorder Demo中队zorder的介绍,可以知道,zorder越大,图层越靠上,所以在上面的代码中,我们在scatter中设定zorder为3,也就是最上层,这样就可以保证渐变的回归线不会压在散点图上面了。

    F1JYiF.png

If you want your life to be a magnificent story, then begin by realising that you are the author.

本文就Udacity数据分析入门课程中的SQL入门(P1阶段)和SQL进阶(P3阶段)的知识点进行总结。SQL的主要功能不外乎增、删、改、查四个,对于数据分析师来说,只需要掌握就可以了。(因为增删改往往超出了数据分析师的职能范围)

注意:本文是总结性质的,只能提供复习或者速查的功能,讲解得不会很详细,若想学习,还是要在教室内逐章学习。

SQL简介

SQL是Structured Query Language的简写,也就是结构化查询语言。SQL 最受欢迎的功能是与数据库交互。

使用传统关系数据库与 SQL 交互有一些主要优点。最明显的 5 个优点是:

  • SQL 很容易理解。
  • 传统的数据库允许我们直接访问数据。
  • 传统的数据库可使我们审核和复制数据。
  • SQL 是一个可一次分析多个表的很好工具。
  • 相对于 Google Analytics 等仪表板工具,SQL 可使我们分析更复杂的问题。

为什么企业喜欢使用数据库

  1. 只有输入了需要输入的数据,以及只有某些用户能够将数据输入数据库,才能保证数据的完整性
  2. 可以快速访问数据 - SQL 可使我们从数据库中快速获取结果。 可以优化代码,快速获取结果。
  3. 可以很容易共享数据 - 多个人可以访问存储在数据库中的数据,所有访问数据库的用户获得的数据都是一样。

SQL 与 NoSQL

你可能听说过 NoSQL,它表示 Not only SQL(不仅仅是 SQL)。使用 NoSQL 的数据库时,你编写的数据交互代码会与本节课所介绍的方式有所不同。NoSQL 更适用于基于网络数据的环境,而不太适用于我们现在要介绍的基于电子表格的数据分析。最常用的 NoSQL 语言之一是 MongoDB

SQL入门

SQL书写规则

  • SQL语句不区分大小写,因此SELECT与select甚至是SeLect的效果是相同的,但是要对命令和变量进行区分,所以默认命令需要大写,其他内容如变量等则需要小写
  • 表和变量名中不要出现空格,可使用下划线_替代。
  • 查询语句中,使用单一空格隔开命令和变量
  • 为提高代码的可移植性,请在查询语句结尾添加一个分号

SQL中的注释

  • 行内注释

    使用两个连字符-,添加注释。

    1
    2
    SELECT col_name -- 这是一条注释
    FROM table_name;
  • 多行注释

    多行注释以/*起始,以*/结尾。

    1
    2
    3
    4
    /*SELECT col_name 
    FROM table_name;*/
    SELECT col_2
    FROM table_name;

检索数据(SELECT FROM LIMIT )

检索数据主要用的语句为:SELECT

检索单列

1
2
SELECT col_name
FROM table_name;

从table_name表中检索col_name列。

检索多列

1
2
SELECT col_1,col_2,col_3
FROM table_name;

从table_name表中检索col_1,col_2和col_3列。

检索所有列

1
2
SELECT *
FROM table_name;

使用通配符*,返回table_name表中的所有列;

检索某列中不同的值

1
2
SELECT DISTINCT col_1
FROM table_name;

检索col_1中具有唯一性的行,即唯一值。

限制检索的结果

使用LIMIT语句可以限制返回的行数。

1
2
3
SELECT col_1
FROM table_name
LIMIT 10;

返回前10行(即第0-第9行)。

也可以添加OFFSET语句,设置返回数据的起始行:

1
2
3
SELECT col_1
FROM table_name
LIMIT 10 OFFSET 5;

从第五行之后,返回十行数据(即第5-第14行)。

排序检索数据(ORDER BY)

  • ORDER BY 语句用于根据指定的单列或多列对结果集进行排序。

  • ORDER BY 语句默认按照升序对记录进行排序。(从小到大,从a到z)

  • 如果您希望按照降序对记录进行排序,可以使用 DESC 关键字。

  • 在指定一条ORDER BY子句时,应该保证它是SELECT语句中的最后一条子句。

按列排序

1
2
3
SELECT col_name
FROM table_name
ORDER BY col_name;

返回的数据会按照col_name列进行升序排序,这里col_name可以是单列也可以是多列,当然也可以使用非检索的列进行排序。

降序排序

1
2
3
SELECT col_1,col_2
FROM table_name
ORDER BY col_2 DESC,col_3;

返回的数据会按照col_2列降序,col_3列升序对col_1和col_2两列进行排序。

这里可以看出,DESC关键字的用法:只对跟在语句前面的变量有效。所以,想要对多列进行降序排序时,需要对每一列都指定DESC关键字。

过滤数据(WHERE)

  • WHERE子句应该在表名(即FROM子句)之后给出。

  • WHERE子句应在ORDER BY子句之前。

  • 在过滤条件中的value是区分大小写的。

使用方法

1
2
3
SELECT col_1
FROM table_1
WHERE col_1 运算符 value;

运算符

运算符 描述
= 等于
<> 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
BETWEEN…AND… 在指定的两值之间
IS NULL 为NULL值
AND 逻辑运算符:与
OR 逻辑运算符:或
IN 制定条件范围筛选,可以简化OR的工作
NOT 逻辑运算符:非

注意:

  • SQL的版本不同,可能导致某些运算符不同(如不等于可以用!=表示),具体要查阅数据库文档。
  • 在同时输入AND和OR时,SQL会优先处理AND语句,你可以使用小括号来进行分组操作。

用通配符进行过滤(LIKE)

通配符是用来匹配值的一部分的特殊字符,跟在LIKE关键字后面进行数据过滤

通配符 描述
% 表示任何字符出现任意次数
_ 表示任何字符出现一次
[] 指定一个字符集,它必须匹配该位置的一个字符
^ 在[]中使用,表示否定

示例:

1
2
3
4
SELECT col_1
FROM table_1
WHERE col_1 LIKE '_[^JM]%'
ORDER BY col_1;

如上筛选出的是,第二个字符为非J或M的数据。

创建计算字段

其实就是在检索数据的同时进行计算,并使用关键字AS将结果保存为某一列。

  • 数值类型的计算
1
2
3
SELECT prod_id,quantity,item_price,quantity*item_price AS expanded_price
FROM orderitems
WHERE order_num = 200008;

输出:

1
2
3
4
prod_id         quantity       item_price      expanded_price
--------------------------------------------------------------
RGAN01 5 4.9900 24.9500
BR03 5 11.9900 59.9500

这里实现的就是使用quantity*item_price创建一个名为expanded_price的计算字段,也就是一个新列。

同样适用于计算的操作符有+(加),-(减)和/(除)。

  • 字符类型的拼接
1
2
3
SELECT RTRIM(col_name) + '('+RTRIM(col_country)+')' AS col_title
FROM table_name
ORDER BY col_name;

输出:

1
2
3
4
5
col_title
------------------------
Bear Emporium(USA)
Bears R Us(USA)
Jouets et ours(France)

这里实现的就是将col_name列与col_country列进行了拼接,新列的名字叫做col_title。

RTRIM()函数是去掉右边的所有空格,LTRIM()是去掉左边的所有空格,TRIM()是去掉两边的所有空格。

使用别名

在上一节中我们使用AS来为变量设置别名,你可能也见过如下所示的语句:

1
SELECT col1 + col2 AS total, col3

当然没有 AS 的语句也可以实现使用别名:

1
FROM tablename t1

以及

1
SELECT col1 + col2 total, col3

将col1+col2的结果设置名为total的列。

代码总结

语句 使用方法 其他详细信息
SELECT SELECT Col1, Col2, … 提供你需要的列
FROM FROM Table 提供列所在的表格
LIMIT LIMIT 10 限制返回的行数
ORDER BY ORDER BY Col 根据列命令表格。与 DESC 一起使用。
WHERE WHERE Col > 5 用于过滤结果的一个条件语句
LIKE WHERE Col LIKE ‘%me%’ 仅提取出列文本中具有 ‘me’ 的行
IN WHERE Col IN (‘Y’, ‘N’) 仅过滤行对应的列为 ‘Y’ 或 ‘N’
NOT WHERE Col NOT IN (‘Y’, “N’) NOT 经常与 LIKEIN 一起使用。
AND WHERE Col1 > 5 AND Col2 < 3 过滤两个或多个条件必须为真的行
OR WHERE Col1 > 5 OR Col2 < 3 过滤一个条件必须为真的行
BETWEEN WHERE Col BETWEEN 3 AND 5 一般情况下,语法比使用 AND 简单一些

SQL进阶

链接表

基本链接(JOIN)

SQL最强大的功能之一就是能在数据查询的执行中进行表的链接(JOIN)。

在关系数据库中,将数据分解为多个表能更有效地存储,更方便地处理,但这些数据储存在多个表中,怎样用一条SELECT语句就检索出数据呢?那就要使用链接。

创建链接的方式很简单,如下便是使用WHERE创建链接:

1
2
3
SELECT col_1,col_2,col_3
FROM table_1,table_2
WHERE table_1.id = table2.id;

如上,col_1和col_2属于table_1表中,col_3属于table_2表中,而这两个表使用相同的id列进行匹配。这种方法被称为等值链接,也就是内链接,我们可以使用如下的语句,更直观地实现内连接:

1
2
3
SELECT col_1,col_2,col_3
FROM table_1 INNER JOIN table_2
ON table_1.id = table2.id;

当然你也可以使用别名,简化输入,并且标明各列与表的隶属关系:

1
2
3
SELECT t1.col_1,t1.col_2,t2.col_3
FROM table_1 t1 INNER JOIN table_2 t2
ON t1.id = t2.id;

如上代码同样适用于左链接、右链接和外链接:

  • LEFT JOIN - 用于获取 FROM 中的表格中的所有行,即使它们不存在于 JOIN 语句中。

  • RIGHT JOIN - 用于获取 JOIN 中的表格中的所有行,即使它们不存在于 FROM 语句中。

  • FULL JOIN: 只要其中一个表中存在匹配,就返回行。

自链接

自链接经常用于对子查询的简化,如下示例:

假如要给Jim同一公司的所有顾客发送一封邮件,需要你先筛选出Jim的公司,然后再根据该公司筛选出所有的顾客。使用子查询的方式如下:

1
2
3
4
5
SELECT cust_id,cust_name,cust_contact
FROM customers
WHERE cust_name = (SELECT cust_name
FROM customers
WHERE cust_contact = 'Jim')

如果改为自链接的方式如下:

1
2
3
4
SELECT c1.cust_id,c1.cust_name,c1.cust_contact
FROM customers c1,customers c2
WHERE c1.cust_name = c2.cust_name
AND c2.cust_name = 'Jim';

结果是一样的,但是使用自链接的处理速度比子查询要快得多。

组合查询(UNION)

UNION 操作符用于合并两个或多个 SELECT 语句的结果集,使用方法也很简单,只要在多条SELECT语句中添加UNION关键字即可。

多数情况下,组合相同表的多个查询所完成的任务与具有多个WHERE子句的一个查询是一样的。

注意:UNION 内部的 SELECT 语句必须拥有相同数量的列,列也必须拥有相似的数据类型。而且UNION返回的结果只会选取不同的值(即唯一值)。

使用UNION的场合情况:

  • 在一个查询中从不同的表返回结果;
  • 对一个表执行多个查询返回结果。

示例:如下三个语句的结果是一致的。

  • 原始语句
1
2
3
4
5
6
7
8
9
-- 查询一
SELECT cust_name,cust_email
FROM customers
WHERE cust_state IN ('str1','str2');

--查询二
SELECT cust_name,cust_email
FROM customers
WHERE cust_name = 'str3';
  • 使用UNION链接
1
2
3
4
5
6
7
8
SELECT cust_name,cust_email
FROM customers
WHERE cust_state IN ('str1','str2')
UNION
SELECT cust_name,cust_email
FROM customers
WHERE cust_name = 'str3'
ORDER BY cust_name;

在最后添加了ORDER BY对所有SELECT语句进行排序,这里只是为了示例在使用UNION时如何进行排序。

  • 使用WHERE
1
2
3
4
SELECT cust_name,cust_email
FROM customers
WHERE cust_state IN ('str1','str2')
OR cust_name = 'str3';

这里看起来使用UNION比WHERE更复杂,但对于较复杂的筛选条件,或者从多个表中检索数据时,使用UNION更简单一些。

  • UNION ALL 命令和 UNION 命令几乎是等效的,不过 UNION ALL 命令会列出所有的值。

SQL聚合

有时候我们只是需要获取数据的汇总信息,比如说行数啊、平均值啊这种,并不需要吧所有数据都检索出来,为此,SQL提供了专门的函数,这也是SQL最强大功能之一。

聚合函数

SQL的聚合函数如下所示:

函数 说明
AVG() 返回某列的均值
COUNT() 返回某列的行数
MAX() 返回某列的最大值
MIN() 返回某列的最小值
SUM() 返回某列的和

使用示例:

1
2
SELECT AVG(col_1) AS avg_col_1
FROM table_1;

注意:聚合函数都会忽略列中的NULL值,但是COUNT(*)也就是统计全部数据的行数时,不会忽略NULL值。

聚合不同值

当添加DISTINCT参数时,就可以只对不同值(也就是某列中的唯一值)进行函数操作。

使用示例:

1
2
SELECT AVG(DISTINCT col_1) AS avg_col_1
FROM table_1;

数据分组

创建分组(GROUP BY)

前面的函数操作都是基于整个表去进行的,那如果想要依据某列中的不同类别(比如说不同品牌 不同性别等等)进行分类统计时,就要用到数据分组,在SQL中数据分组是使用GROUP BY子句建立的。

在使用GROUP BY时需要注意的几点:

  • GROUP BY子句可以包含任意数量的列,因而可以对分组进行多重嵌套,类似于Pandas中的多重索引;
  • GROUP BY子句必须出现在WHERE子句之后,ORDER BY之前。

使用示例:

1
2
3
SELECT col_1,COUNT(*) AS num_col
FROM table_1
GROUP BY col_1;

以上即可实现按col_1列中的不同类目进行行数统计。

过滤分组(HAVING)

在SQL入门中我们学过WHERE,它是对行数据进行筛选过滤的,那么,如果我想对创建的分组数据进行筛选过滤呢?这时候,你就要用到HAVING子句了,它与WHERE的操作符一致,只是换了关键字而已。

使用示例:

1
2
3
4
SELECT col_1,COUNT(*) AS num_col
FROM table_1
GROUP BY col_1
HAVING COUNT(*) >= 2;

这里我们就筛选出了具有两个以上类别的分组。

注意:使用HAVING时应该结合GROUP BY子句。

时间序列的处理(DATE)

在SQL中有一套专门的内置函数,用来处理时间序列,那就是DATE函数。

SQL Date 数据类型

先了解一下在不同的数据库中的时间序列的表示。(了解即可)

MySQL 使用下列数据类型在数据库中存储日期或日期/时间值:

  • DATE - 格式:YYYY-MM-DD
  • DATETIME - 格式:YYYY-MM-DD HH:MM:SS
  • TIMESTAMP - 格式:YYYY-MM-DD HH:MM:SS
  • YEAR - 格式:YYYY 或 YY

SQL Server 使用下列数据类型在数据库中存储日期或日期/时间值:

  • DATE - 格式:YYYY-MM-DD
  • DATETIME - 格式:YYYY-MM-DD HH:MM:SS
  • SMALLDATETIME - 格式:YYYY-MM-DD HH:MM:SS
  • TIMESTAMP - 格式:唯一的数字

DATE_TRUNC函数

DATE_TRUNC 使你能够将日期截取到日期时间列的特定部分。常见的截取依据包括日期月份年份

语法:

1
DATE_TRUNC('datepart', timestamp)

其中datepart即为你的截取依据,后面的timestamp类型可以参考上面的Date数据类型。

我总结了一份SQL的datepart速查表放在了下面。

使用示例:

1
2
3
4
5
SELECT DATE_TRUNC('y',col_date) col_year
FROM table_1
GROUP BY 1
ORDER BY 1 DESC
LIMIT 10;

如上,我们将col_date列按照年(’y’)进行了分组,并按由大至小的顺序排序,取前10组数据。

DATE_PART函数

DATE_PART 可以用来获取日期的特定部分,如获取日期2018-10-6的月份,只会获得一个结果6,这是它与DATE_TRUNC的最大区别。

语法:

1
DATE_PART ('datepart', date或timestamp)

其中datepart即为你的截取依据,后面的timestamp类型可以参考上面的Date数据类型。

使用示例:

1
2
3
SELECT DATE_PART('y',col_date) col_year
FROM table_1
GROUP BY 1;

如上,我们筛选了col_date列的年份,并依据它做了分组。

想了解更多DATE函数,可以戳SQL日期和时间函数参考

datepart总结

如下给了很多的缩写,只记住最简单的即可。

日期部分或时间部分 缩写
世纪 c、cent、cents
十年 dec、decs
y、yr、yrs
季度 qtr、qtrs
mon、mons
w,与 DATE_TRUNC一起使用时将返回离时间戳最近的一个星期一的日期。
一周中的日 ( DATE_PART支持) dayofweek、dow、dw、weekday 返回 0–6 的整数(星期日是0,星期六是6)。
一年中的日 ( DATE_PART支持) dayofyear、doy、dy、yearday
d
小时 h、hr、hrs
分钟 m、min、mins
s、sec、secs
毫秒 ms、msec、msecs、msecond、mseconds、millisec、millisecs、millisecon

CASE语句

CASE语句其实就相当于python中的if语句,是用来做条件的。

需要注意的几点:

  • CASE 语句始终位于 SELECT 条件中。
  • CASE 必须包含以下几个部分:WHEN、THEN 和 END。ELSE 是可选组成部分,用来包含不符合上述任一 CASE 条件的情况。
  • 你可以在 WHEN 和 THEN 之间使用任何条件运算符编写任何条件语句(例如 WHERE),包括使用 AND 和 OR 连接多个条件语句。
  • 你可以再次包含多个 WHEN 语句以及 ELSE 语句,以便处理任何未处理的条件。

使用示例:

1
2
3
4
SELECT account_id, CASE WHEN standard_qty = 0 OR standard_qty IS NULL THEN 0
ELSE standard_amt_usd/standard_qty END AS unit_price
FROM orders
LIMIT 10;

如上,我们使用CASE WHEN.(条件一).THEN.(条件一的结果).ELSE.(其他不符合条件一的结果).END语句,设立的两个条件,即当standard_qty为0或者不存在时我们返回0,当standard_qty不为0时进行计算,并储存为新列unit_price。

子查询与临时表格

我们之前所涉及到的都是从数据库表中检索数据的单条语句,但当我们想要检索的数据并不能直接从数据库表中获取,而是需要从筛选后的表格中再度去查询时,就要用到子查询和临时表格了。

子查询与临时表格所完成的任务是一致的,只不过子查询是通过嵌套查询完成,而另一种是通过WITH创建临时表格进行查询。

构建子查询

构建子查询十分简单,只需将被查询的语句放在小括号里,进行嵌套即可,但在使用时一定要注意格式要清晰。

使用示例:

1
2
3
4
5
6
7
SELECT *
FROM (SELECT DATE_TRUNC('day',occurred_at) AS day,channel, COUNT(*) AS events
FROM web_events
GROUP BY 1,2
ORDER BY 3 DESC) sub
GROUP BY channel
ORDER BY 2 DESC;

如上,我们创建了一个子查询,放在小括号里,并将其命名为sub。在子查询中也注意到了各个子句上下对齐,这样条例更清晰。

临时表格(WITH)

这种方法,就是使用WITH将子查询的部分创建为一个临时表格,然后再进行查询即可。

我们还是使用上面子查询的例子,这次用临时表格的形式实现:

1
2
3
4
5
6
7
8
9
10
WITH sub AS(
SELECT DATE_TRUNC('day',occurred_at) AS day,channel, COUNT(*) AS events
FROM web_events
GROUP BY 1,2
ORDER BY 3 DESC)

SELECT *
FROM sub
GROUP BY channel
ORDER BY 2 DESC;

如上,我们将被嵌套的子查询单独拎出来,用WITH创建了一个临时表格,再之后又使用SELECT根据该表格进行查询。

SQL数据清理

这一节主要针对数据清理讲解了几个SQL中的常用函数,一般来说,也都是用在筛选阶段,更详尽的数据清理还是要放在python中去进行。

字符串函数

  • LEFT、RIGHT、LENGTH

LEFT和RIGHT相当于是字符串截取,LEFT 是从左侧起点开始,从特定列中的每行获取一定数量的字符,而RIGHT是从右侧。

LENGTH就是获取字符串的长度,相当于python中的len()。

语法:

1
2
3
LEFT(phone_number, 3) -- 返回从左侧数,前三个字符
RIGHT(phone_number, 8)
LENGTH(phone_number)
  • POSITIONSTRPOSSUBSTR

这三个函数都是与位置相关的函数。

POSITIONSTRPOS 可以获取某一字符在字符串中的位置,这个位置是从左开始计数,最左侧第一个字符位置为1,但他俩的语法稍有不同。

SUBSTR可以筛选出指定位置后指定数量的字符。

语法:

1
2
3
POSITION(',' IN city_state)
STRPOS(city_state, ‘,’) --跟上面的语句等价
SUBSTR(city_state,4,5) -- 返回city_state字符串中,以第4个字符开头的5个字符。
  • 字符串拼接(CONCAT)

顾名思义,就是将两个字符串进行拼接。

语法:

1
2
3
CONCAT(first_name, ' ', last_name) -- 结果为:first_name last_name
--或者你也可以使用双竖线来实现上述任务
first_name || ' ' || last_name

更改数据格式

  • TO_DATE函数

TO_DATE函数可以将某列转为DATE格式,主要是将单独的月份或者年份等等转换为SQL可以读懂的DATE类型数据。

语法:

1
2
TO_DATE(col_name,'datepart') 
TO_DATE('02 Oct 2001', 'DD Mon YYYY');

这里是将col_name这列按照datepart转化为DATE类型的数据,datepart可以参考之前的总结。

  • CAST函数

CAST函数是SQL中进行数据类型转换的函数,但经常用于将字符串类型转换为时间类型。

语法:

1
2
3
CAST(date_column AS DATE)
-- 你也可以写成这样
date_column::DATE

这里是将date_column转换为DATE格式的数据,其他时间相关的数据类型与样式对照可以参考上面写过的SQL Date数据类型,确保你想转换的数据样式与数据类型对应。

缺失值的处理

之前有提到过如何筛选出缺失值,即使用WHERE加上IS NULL或者IS NOT NULL

那么如何对缺失值进行处理呢?(其实这里可以直接无视,筛选出来后在python中再进行处理)

SQL中提供了一个替换NULL值的函数COALESCE

使用示例:

1
2
COALESCE(col_1,0) -- 将col_1中的NULL值替换为0
COALESCE(col_2,'no DATA') -- 将col_2中的NULL值替换为no DATA

总结

好啦,至此课程中的所有SQL知识点已经总结完了,并且也给大家做了适当的补充,希望大家能够用得上。未来的数据分析师之路,还要继续加油呀!

附:SELECT子句顺序

下表中列出了全文中涉及到的子句,在进行使用时,应严格遵循下表中从上至下的顺序。

子句 说明 是否必须使用
SELECT 要返回的列或表达式
FROM 用于检索数据的表 仅在从表中选择数据时使用
JOIN…ON… 用于链接表 仅在需要链接表时使用
WHERE 过滤行数据
GROUP BY 分组数据 仅在按组计算时使用
HAVING 过滤分组
ORDER BY 对输出进行排序
LIMIT 限制输出的行数

Better together . —— Udacity

Hi,同学们,经过前两周的学习,我们掌握了描述统计学基础、概率论基础、推论统计学中的置信区间、假设检验以及机器学习入门知识——回归,本章的内容偏理论性更多一些,需要更多得去实操来加强自己的理解能力,这周呢我们就来个实打实的项目来检验前两周的所学。项目为分析A/B测试结果,在开始项目前,请一定要把前面的几个小测试做了,这样做项目更好上手一些。大家加油!通过这个项目,就可以拿到入门的毕业证啦!!!

项目四(P4)阶段总共包含三周,在这三周内,我们要对统计学进行学习,掌握基础的描述统计学理论、基本的概率知识、二项分布和贝叶斯公式,并学会使用 Python 来实践;学习正态分布、抽样分布、置信区间以及假设检验的概念和计算方式;学习线性回归以及逻辑回归,在真实场景中应用,比如分析 A/B 测试结果,搭建简单的监督机器学习模型。可谓是时间紧任务重,但是也别怕,统计学的基础知识还是非常简单的,跟着课程内容一步步来,自己多做笔记多查资料,一定没问题的!

那么我们的课程安排:

时间 学习重点 对应课程
第1周 统计学基础 描述统计学 - 抽样分布与中心极限定理
第2周 统计学进阶 置信区间 - 逻辑回归
第3周 完成项目 项目:分析A/B测试结果

本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决:

饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧!

注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索!

本周目标

完成并通过项目四!

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom 项目四
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 本周学习总结、答疑
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

项目指南

项目详情

数据分析师和数据学家经常使用 A/B 测试。在这个项目中,你将会理解电子商务网站运营 A/B 测试的结果。你的目标是通过课程中给的Jupyter Notebook,帮助公司理解他们是否应该设计新页面、保留原有网页或延长测试时间以便做出决定。

项目前面的几个小测试,需要大家针对项目提供的数据进行操作并回答,你可以打开两个网页,也可以在本地进行操作。

当然还是建议大家下载到本地进行操作,如果文件下载失败,请微信联系我。

关于A/B-test:

AB 测试就是为了验证在先验条件的存在的情况下,进行新的变更是否合理和可行以达到优化的目的。使用 AB 测试的方式能能够度量变更对某些指标的变化,是变更更具有合理性依据更充分。

AB 测试也存在 不适用的场景:1)对没有明确参照的试验,AB 测试是基于先验条件的优化,如果没有一个参照对比是无法进行测试。2)数据获取时间长,AB 测试一般都是进行小规模快速的试验,所以对于数据获取的单周期较长的试验不太适用。

影响测试效果的因素:1)新奇效应:即Novelty Effect 指老用户可能会觉得变化很新鲜,受变化吸引而偏爱新版本,哪怕从长远看来新版本并无益处。2)抗拒改变心理:即 Change Aversion 老用户可能会因为纯粹不喜欢改变而偏爱旧版本,哪怕从长远来看新版本更好。

在课程项目中,我们分成了三块涵盖了本章的所有知识点,这三块分别为:

  • 概率
  • A/B测试
  • 回归

如果在项目进行中,有知识点遗漏或忘记的地方,可以去查看相关课程视频或者导学,之后,记在你的小本本上。

I - 概率

本节的问题都相对比较简单,所以在导学中不过多赘述了。

测试1-理解数据集

这里没什么难度,基本的pandas知识,如果这节有什么问题的话,请查看第六周导学并面壁十分钟-。-

如果非要提醒一下的话,那就是在问题e. new_pagetreatment 不一致的次数中,不要忘了也看看old_page与control的不一致次数,二者相加才是结果。

测试3-更新后的数据集

  • a问题中,因为要将处理后的数据集保存为新的变量,所以使用drop函数时,可以不用使用inplace = True参数。
  • d问题中,因为两个重复值除了时间戳不一致外,其他信息都是一致的,所以随便删除一个重复即可。

II - A/B测试

1.零假设与备择假设

这里只说一点,就是如何在Jupyter Notebook中使用公式的问题,其实也就是如何在Markdown中使用公式的问题,你只需要按照如下步骤即可:

  • 打开Latex公式在线转换,输入好公式后,复制代码

  • 将你想要输入公式的代码框,转为Markdown格式;

  • 输入两个美元符号,即$$;

  • 将刚复制的公式代码粘贴到两个美元符号中间,然后运行该代码框即可。

    录了一个gif在下面,可以参考下:

iMRliF.gif

2.进行假设检验

  • a、b

注意题干中给的要求是:假定在零假设中,不管是新页面还是旧页面, pnew 和 pold 都具有等于 转化 成功率的“真”成功率,也就是说, pnew 与 pold是相等的。此外,假设它们都等于ab_data.csv 中的 转化 率,新旧页面都是如此。

也就是:p_new = p_old = p_ab_data

注意:这并不意味着零假设就是p_new = p_old,可以从后续的c-g步骤能看出,零假设为p_new - p_old ≤ 0

  • c、d

这里的n_new与n_old就是对ab_data中使用新旧页面的用户数量进行统计。

  • e、f、g

使用numpy.random.choice函数,将零假设中的p_new与p_old作为抽样概率,n_new与n_old作为抽样次数,用1表示‘转化成功’,0表示‘未转化成功’,并将结果储存在一个新变量当中。

示例:

1
new_page_converted = np.random.choice([0,1],n_new,p = [1-p_new,p_new])

以上获得的这个新变量,就是我们按照零假设中的n_new抽样n_new次的转化与否的分布模拟,那如何看模拟后的转化率呢?很简单,一个函数就搞定了,这里自己想。

  • h、i、j

这三步是使用for循环,将上面的过程不断重复10000次,获得一个抽样分布直方图,这个图会是正态分布吗?

关于实际观测值,即为你利用ab_data.csv直接计算得来的new_page与old_page转化率之差。

j中得到的值是什么呢?是不是在零假设的条件下,观察到实际观测值甚至更极端(更支持备择假设)的概率?那这个值的学名叫什么?

【这里实际上进行的是单尾检验,也就是对备择假设为p_new - p_old > 0来进行的】

  • i、m

使用了statsmodels中的proportions_ztest函数进行检验。实现的功能和上述a-j是一致的。

为什么要选择这个函数,以及这个函数的用法可以参考课程中给的链接proportions_ztest

不过值得注意的是,在链接的列子中,使用的是双尾检验,也就是针对备择假设为p_new ≠ p_old去做的;但是在课程项目中,我们的备择假设为p_new > p_old,也就是单尾检验,所以函数中的某个参数要改一下。

使用内置函数方法获得的p值应该与前面获得的p值相近,如果差太多,那肯定是有地方需要再琢磨琢磨。

III - 回归

  • a

要想知道执行哪种类型的回归,就应该先看变量是属于数值变量还是分类变量,那题设中的变量是什么类型的变量呢?

  • b

要求是:创建一个 ab_page 列,当用户接收 treatment 时为1, control 时为0。所以在对group列使用get_dummies函数时,应该把生成的treatment列保存为ab_page列,而control列则应该被删掉。

  • c、d

注意的一点是:不要忘了添加截距。在进行结果解释的时候,我们并不关注截距,只是关注变量的coef系数和p值,先看p值是否具有显著性,若有再看coef系数,若没有,则该变量对因变量没有影响。

  • e

在思考零假设与备择假设之前,注意看结果中标红框的位置,想想这是什么意思,这说明在回归计算中,采用的是单尾检验还是双尾?单尾和双尾又分别对应的假设是什么?

iQQBSs.png

  • g

数据集融合问题,之前单独出过一篇导学,如果忘了,请戳:Pandas数据融合,提醒下,合并时采用内连接,可以省去一些麻烦;

get_dummies,注意该函数生成数据的顺序是按照字典顺序来的,所以,你在进行操作时,为了确保顺序不乱,最好能先看一下生成的结果,再进行重命名。

总结

大家能坚持到最后一个项目,十分不易,不过对于数据分析生涯来说,这只是你的开始,请继续保持这段时间的学习状态,如果非要给这个保持加一个期限的话,我希望是一辈子!大家加油!等你们的好消息!!

Everything is difficult until you know how to do it.

Hi,同学们,上周我们学习了统计学基础知识,包括概率基础、描述统计学和推论统计学的基础知识,本周我们将会进一步学习推论统计学——置信区间&假设检验以及它们的应用之一A/B-test,在这之后,我们还会讲解一部分机器学习入门——线性回归&逻辑回归,与上周相比,这周我们会接触较深的理论知识,更多的代码,你可能会觉得学起来有些吃力,但请一定保持信心,你可以多次暂停观看课程中的讲解视频,跟着一起多动手,或者你也可以按照下面我给出的额外资料去查漏补缺,相信你们一定可以的!

项目四(P4)阶段总共包含三周,在这三周内,我们要对统计学进行学习,掌握基础的描述统计学理论、基本的概率知识、二项分布和贝叶斯公式,并学会使用 Python 来实践;学习正态分布、抽样分布、置信区间以及假设检验的概念和计算方式;学习线性回归以及逻辑回归,在真实场景中应用,比如分析 A/B 测试结果,搭建简单的监督机器学习模型。可谓是时间紧任务重,但是也别怕,统计学的基础知识还是非常简单的,跟着课程内容一步步来,自己多做笔记多查资料,一定没问题的!

那么我们的课程安排:

时间 学习重点 对应课程
第1周 统计学基础 描述统计学 - 抽样分布与中心极限定理
第2周 统计学进阶 置信区间 - 逻辑回归
第3周 完成项目 项目:分析A/B测试结果

本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决:

饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧!

注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索!

本周目标

学习课程中的置信区间 - 逻辑回归课程,掌握统计学进阶知识。

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom 置信区间 - 逻辑回归
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 本周学习总结、答疑
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

知识清单

置信区间

学习之前可以先回顾一下正态分布、抽样分布和中心极限定理的相关知识。

是什么

还记得上周用到的优达学生喝咖啡的数据吗?我们同样以此为例来探讨下置信区间是什么。

假设,优达的学生有数十万个(总体),而我们能获得的学生数据只有几百个(样本),我们通过做样本均值进行抽样分布,得到了一个近似正态分布的图形,但这也仅仅是样本的均值分布,也就是样本统计量。我们利用样本统计量的分布去构造总体均值(总体参数)的估计区间,就叫做置信区间

有什么

  • 置信区间的两种应用

    • 刚才的举例中我们用得是“均值”,这算是利用抽样分布建立单个参数的置信区间,可以应用在单变量估计等方面;

    • 你还可以计算两种分类之间均值的差,这就是两个参数的置信区间,可以用在两变量的对比(A/B-Test)上,比如说医学上不同药物的治疗效果,不同广告的吸金率,不同网页的点击率等等。

  • 置信区间的显著性

    • 统计显著性:即我们通过理论分析得到的结果。在统计学上用α表示,叫做显著性水平,它表达的是区间估计的不可靠概率。比如说,我们获取了95%的置信区间,那么显著性水平α = 1 - P = 5%。

      一般的,显著性水平都要求达到5%即可,这在之后的假设检验中会学习到。

    • 实际显著性:即我们除了理论分析得到的结果外,还要考虑实际情况,比如说你能有多少资金用于投资,或者你的网站承载力能达到多少等。

  • 与传统置信区间方法的对比

    传统的置信区间/假设检验方法有很多,比如说t-检验、双边t-检验等等,但是我们所掌握的自助取样法可以代替他们全部,当然有一个前提条件,那就是你的样本容量一定要足够大,如果你的样本容量实在是少,那就只能选择传统方法去处理了。

    获取传统方法python代码的方法,请自行去Stackoverflow搜索。

  • 准确性&可靠性

    这里课程中翻译的有点儿晦涩,这里着重讲一下,我们以候选人A为例(在95%可靠性下具有34%±3%的支持率),大概分布可以如下所示:字丑就将就着点看吧。。。

    iVvVW8.md.png

    • 在上图中我们能发现,置信区间的置信概率(可靠性)越高,置信区间的宽度也就越宽,误差范围(准确性)也就会越大;那么当我们缩小误差范围时,置信区间的宽度和可靠性也就随之降低。
    • 结论:置信区间的准确性和可靠性是一对相互矛盾的标准,所以在实际工作中,只能提出其中一个条件,然后推求另一条件的变动情况,如果所推求的另一条件不能满足要求,就应该考虑增加样本容量,重新进行抽样,直至符合要求为止。

怎么用

课程中已经给出了很好的示例、问题及解答,在这里只是拎出一些面生的代码进行讲解。

1
2
3
4
5
6
#设置随机种子,能保证结果之后可以复现
np.random.seed(7)
#按百分比取值
np.percentile(array,q)#q介于0到100,取的是array中的q%位置的数。(从小至大排序)
#拓展——按分位数取值,其实效果和上面按百分比取值一样,只是q值的范围变了
np.quantile(array,q)#q介于0到1,取的是array中的q位置的数。

注意:置信区间和假设检验只关注的是总体参数,而不能对某一个体下结论。

假设检验

是什么

  • 基本概念

刚才我们讲解了什么是置信区间——为了得到总体指标,使用样本统计量去估计总体参数——这是一个从样本出发去研究总体的过程。

我们现在换一个角度,在实际分析问题中,能否去假定总体参数,然后根据样本数据,去检验这种假定是否正确,从而实现对总体指标的分析?其实这种从总体出发,用样本尺度去检验实现对总体参数分析的过程,就叫做假设检验

置信区间与假设检验的关系:从上面的表述可以看出,假设检验和置信区间在本质上是一致的。如果使用样本数据对总体参数进行估计,在一定的置信区间下,总体参数就应该落在这个区间,如果假设的总体参数不在该区间中,则就有理由拒绝该假设,这其实就是从置信区间的角度去完成了假设检验的工作内容。

  • 名词解释

    • 零假设H0:一般的,零假设就是你不想要的结果,总包含等号。我们的目的就是要证明零假设是不成立的,是可拒绝的。比如说,你更新了网页设计,不想看到的是更不更新对你网站的流量没什么影响,那么零假设就可以这样设置。
    • 备择假设H1:一般的,这就是你想要的结果。注意,备择假设应该是零假设的对立。
    • 一类错误:原假设H0为真,却被拒绝。也叫拒真概率,一类错误是更为严重的错误。
    • 二类错误:原假设H0为假,却被接受。也叫受伪概率。

    在实际工作中,我们不可能要求一个检验方法永远不出错,但可以要求尽可能地减少犯错误的概率。但在样本容量给定的条件下,两种错误发生的概率必是此消彼长,因此,我们通常是控制第一类错误的概率,使它不超过某一给定的值(一般的取0.05),这样加以控制第一类错误,以此来制约犯第二类错误的概率。

    • p值:当零假设为真时,我们以零假设的参数建立正态分布(根据中心极限定理,当样本数量和抽样次数足够大时,抽样分布趋于正态分布),在该正态分布中观察到样本统计量甚至是更极端值(也就是偏向备则假设)的概率。

      若这个概率很大,比如说p = 1,那么就表示样本统计量在按照零假设模拟的正态分布内,我们就不能拒绝零假设;

      若这个概率很小,比如说 p < 0.05,那么在我们模拟的正态分布中观察到样本统计量的概率就是一个小概率事件,我们就可以拒绝零假设;

      若p值等于0.05,可增加样本容量,重新进行抽样检验。

有什么

  • 假设检验的基本思想

    • 逻辑上的反证法:我们先假设原命题(零假设H0)成立,然后推出明显矛盾的结果,证明原命题不成立,则我们的所证命题(备择假设H1)成立。
    • 小概率事件:概率很小的随机事件再一次随机实验中可以认为几乎是不会发生的,这就是小概率事件,我们证明零假设H0不成立,就是利用的小概率事件。

    假设检验的基本思想可以归纳为:我们把不想要的结果(即零假设H0)假设成立,然后利用样本计算出该假设成立时的概率(即支持该假设的概率,也就是p-value),如果这个概率小于显著性水平α(一般的为0.05),那么就可以说明零假设是小概率事件,可以拒绝,就证明了我们想要的结果(即备择假设H1)成立,可以表述为:在显著性水平α下拒绝原假设

    试着理解一下上面这段话,如果理解不了,可以看看怎么用,会有详细的分步讲解。

  • 进行多次假设检验的校正

    • Bonferroni Correction:是一种降低多重比较时第一类错误的矫正方法,举例说明该用法:如果你想在 20 个假设检验中把 I 类错误率维持在 1%,邦弗朗尼 校正率应为 0.01/20 = 0.0005。你应该使用这个新比率作为显著性水平α,对比每 20 个检验的 p 值,再做出决定。

怎么用

  • 建立假设: 一般的都是均值或和与某数值之间的关系。示例如下:

$$
H_0:\mu \leqslant 7
$$

$$
H_1:\mu > 7
$$

  • 进行多次重复取样(自助法)
1
2
3
4
5
6
7
8
#从原数据集中取样,样本容量要大于30
sample_df = df.sample(100)
#新建列表
means = []
#循环取样,并计算均值,存贮在列表中
for _ in range(10000):
bootsample = sample_df.sample(100,replace = True)#设置重复取样
means.append(bootsample.height.mean())#计算数据集中height变量的均值
  • 构建零假设的正态分布(因为根据中心极限定理可知,当样本容量足够大,取样次数足够多时,均值的抽样分布近似于正态分布)
1
2
3
4
#计算抽样分布的标准差
null_std = np.std(means)
#构建正态分布
null_vals = np.random.normal(7,null_std,10000)#三个参数依次为正态分布的均值、标准差和取值数量,其中均值即为零假设设置的值。
  • 计算p值
1
2
3
4
#计算原始样本的均值
sample_mean = sample_df.height.mean()
#计算支撑原假设的概率,即p值。计算由原假设构建的正态分布(均值为7)大于样本统计量的概率。
p_value = (null_vals > sample_mean).mean()

若零假设为:u ≥ 7,则p_value = (null_vals < sample_mean ).mean();

若零假设为:u = 7,则p_value = (null_vals < sample_mean).mean() + (null_vals > null_mean + (null_mean - sample_mean) ).mean()

线性回归

基本概念

线性回归是属于机器学习中监督学习范畴的一种简单预测算法。我们通过查看两个定量变量之间是否存在线性关系,来进行预测。一般使用散点图对变量之间的关系进行可视化。

  • 反应变量就是你想进行预测的变量,其实也就是因变量(y);

  • 解释变量就是你用于预测的变量,其实也就是自变量(x)。

  • 相关系数:最常用的就是皮尔逊相关系数,用r表示,取值范围为[-1,1],正值表示正相关,负值表示负相关,绝对值越大,相关性就越强。在描述相关性强弱时,可以参考如下取值范围:

    imFK0K.png

    关于更多更详细的相关系数的知识,请戳统计学之三大相关性系数,博主写得深入浅出,而且有很多浅显易懂的例子,感兴趣的话可以看看。

方程

  • 方程模型

线性回归的方程模型就是一元一次方程,如下所示:

ila641.png

b0表示截距,也就是回归线与y轴交点的y坐标;

b1表示斜率,也就是回归线的倾斜程度;

y^ 表示回归线反应变量的预测值,并不是确切的数据集中的y值。

  • 拟合回归线

拟合回归线时我们采用的主要算法叫做 最小二乘法,即通过回归线得到的预测反应变量值与实际反应变量之差最小时的那条就是最佳拟合回归线,其原理公式可以表示为:

ilag9x.png

编程实现

在python中我们需要调用statsmodels包来拟合回归线:

1
2
3
4
5
6
7
8
9
10
11
# 加载statsmodels包
import statsmodels.api as sm
#注意一定不要忘了截距
df['intercept'] = 1
# 构建变量模型及其拟合
# y为因变量,X表示单个或多个自变量(其中要包含截距),例如 df[["intercept", "area"]] 包括了截距和面积两个变量
lm = sm.OLS(y, X)
result = lm.fit()

# 获取最终的拟合模型报告
print(result.summary())

在建立模型时,一般情况下都是需要手动添加截距(一般为常数 1), 想了解更多,可以查阅Statcon: Why we need the intercept或者When is it ok to remove the intercept in a linear regression model? - Cross Validated

参数和结果解释

  • coef:对应变量的参数值
  • std err:标准误差
  • t:统计检验值
  • P>|t| :这个是对应的 p 值,它的零假设为该变量的参数值等于0,可以指示该变量是否有利于预测反应变量,也能用于比较多个变量中哪个更重要。
  • R-squared :即决定系数,它是相关系数的平方。取值范围在[0,1],值越大,拟合效果就越好,这个值的统计意义可以简单解释为此次拟合中的解释变量能有多少百分比的可能去解释反应变量。

多元线性回归

基本概念

多元线性回归就是由多个自变量去预测因变量的方法,其模型方程与简单线性回归基本一致,只不过是将单自变量变为了多个自变量的矩阵,如下所示:

ilaRgK.png

其中X就是多个自变量的矩阵。

编程实现

在Python中的编程实现步骤也如简单线性回归类似,别忘了要定义一个截距

1
2
3
4
5
6
7
8
9
10
11
# 加载statsmodels包
import statsmodels.api as sm
#注意一定不要忘了截距
df['intercept'] = 1
# 构建变量模型及其拟合
# y为因变量,X表示多个自变量的矩阵(其中要包含截距),例如 df[["intercept", "area","bedroom", "bathroom"]] 包括了截距和面积、卧室数量、洗手间数量四个变量
lm = sm.OLS(y, X)
result = lm.fit()

# 获取最终的拟合模型报告
print(result.summary())

参数和结果解释

这里和简单线性回归是一致的,只不过在解释单个自变量与因变量之间的关系时,需要加上一句“在其它变量不变的情况下……”

处理分类变量

  • 思路

处理分类变量的一个思路就是将其转化为虚拟变量,也就是将各个分类变量单独成列,然后把观察行对应的分类变量量化为0(可理解为“否”)和1(可理解为“是”)作为该列的元素,再进行拟合处理。

在拟合处理时,我们添加的虚拟变量的数量应该为原数据集中的虚拟变量总数减一。

因为要计算最佳拟合系数时,需要用到变量矩阵的转秩,而判断矩阵是否可逆的充分必要条件就是这个矩阵是满秩的,又因为我们的虚拟变量矩阵中每一个变量都可以由其他变量推导而来,所以必须要舍弃一列才能确保变量矩阵为满秩。【感兴趣可以去可汗学院补一补线性代数知识】

  • 方法

使用pandas中的get_dummies函数来进行虚拟变量的转换

1
2
#对neighborhood列进行量化,并将结果存储在df数据集的A/B/C三个新列中
df[['A','B','C']] = pd.get_dummies(df['neighborhood'])

注意:get_dummies函数输出结果的默认排序为字典顺序(即a-z),所以在进行新列储存时,一定要注意原始变量中的分类与虚拟变量列一一对应。

  • 结果解释

还是以ABC三个分类变量来假设,我们以C作为基准变量(也就是删除的那列),那么在显示的结果中:

coef
Intercept i
A a
B b

1.Intercept的coef表示:如果分类为C的话,因变量即为i;

2.A的coef表示:如果分类为A的话,因变量为i+a;

3.B的coef表示:如果分类为B的话,因变量为i+b。

潜在问题

这部分课程中给了很多额外资料的链接,理论性很重,不太好啃,建议等通关后复盘的时候试着看一看。

多重共线性现象和分析

如果我们的自变量彼此相关,就会出现多重共线性。多重共线性的一个主要问题在于:它会导致简单线性回归系数偏离我们想要的方向。要判断是否有多重共线性,最常见的办法是借助散点图或 **方差膨胀因子 (即 VIF)**。

  • 散点图

散点图比较好理解,使用之前提到过的seaborn中的pairplot能很直观的看出各个变量之间的相关性。代码如下:

1
2
import seaborn as sns
sns.pairplot(df[["col_1", "col_2", "col_3"]])
  • 方差膨胀因子

方差膨胀因子(Variance Inflation Factor,VIF)是指解释变量之间存在多重共线性时的方差与不存在多重共线性时的方差之比。具体的计算方法如下(计算不做要求,但要理解)

假若有X1 、X2 、X3三个自变量,X1的vif计算:
1.x1对常数项(截距)、x2、x3做多元线性回归,求出R^2
2.则变量X1的VIF=1/(1-R^2)
3.同理计算出变量X2和X3的VIF。

它是指示多元线性回归中多重共线性严重与否的指标,VIF越大,多重共线性就越严重。

经验判断方法表明:

当0<VIF<10,不存在多重共线性;

当10≤VIF<100,存在较强的多重共线性;

当VIF≥100,存在严重多重共线性。

所以我们在处理的时候,就要去除VIF超过10的最不感兴趣的变量。

在python中的编程实现如下:

1
2
3
4
5
6
7
8
9
10
# 计算 VIF 需要使用 statsmodel 包
from statsmodels.stats.outliers_influence import variance_inflation_factor
from patsy import dmatrices

# 筛选出作线性回归的变量(截距不要加)
y, X = dmatrices('col_y ~ col_1 + col_2 + col_3', df, return_type='dataframe')
vif = pd.DataFrame()
# 使用 variance_inflation_factor 来计算 VIF,并储存在vif DataFrame中
vif["VIF Factor"] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
vif["features"] = X.columns

【选修】高阶项

高阶项就是在回归模型中添加诸如x^2,x^3,x1·x2等变量,获取的方式可以直接使用df[‘col_1’]进行高阶计算即可。

关键是在于观察变量之间的散点图,来确定是否需要添加高阶项。

  • 二阶、三阶的函数曲线很有辨识度,观察他们拐几个弯就可以;
  • 交叉项的话,就看两自变量各自与因变量之间的回归线,如果回归线几乎平行,那就不必添加交叉项;

注意:如果确定要添加某变量的高阶项,一定要确保该变量也要添加进去。

之后的24-33节也是选修,而且给了Udacity一套免费的机器学习入门课程,建议通关后再来复盘。

逻辑回归

逻辑回归就是对分类变量进行预测的方法,尤其是对二分类问题(非1即0),比如说是否使用优惠券,是否存在贷款逾期问题等等。

方程

逻辑回归的方程模型就是sigmoid函数:

iKlzUe.png

结合二分类问题的概率,做对数变换可得:

izcBWD.png

如上p/(1-p)即为事件的机会比,在该问题中,能预测范围在0到1之间。

编程实现

编程实现与线性回归类似,只不过将最小二乘法(OLS)替换成了逻辑回归(Logit):

1
2
3
4
5
6
7
8
9
10
11
# 加载statsmodels包
import statsmodels.api as sm
#注意一定不要忘了截距
df['intercept'] = 1
# 构建变量模型及其拟合
# y为二分类变量,X表示多个自变量的矩阵(其中要包含截距),例如 df[["intercept","duration"]] 包括了截距和持续时间
lm = sm.Logit(y, X)
result = lm.fit()

# 获取最终的拟合模型报告
print(result.summary())

参数和结果解释

  • coef:对应变量的系数
  • std err:标准误差
  • t:统计检验值
  • P>|t| :这个是对应的 p 值,可以指示该变量是否有利于预测反应变量,也能用于比较多个变量中哪个更重要。

在这里我们并不关注截距,而重点关注各个解释变量。

在进行结果解释时我们常说:

在保持其他变量不变的情况下

  • (对于数值变量)该变量每增加一个单位,那么作为y的分类变量则增大e^coef倍;
  • (对于分类变量)该变量为它的对立时,作为y的分类变量发生的几率为该变量基础的e^coef倍。

【选修】模型评估

之后的课程已经是机器学习入门阶段的范畴,可以等通关后,再去研究。(建议先开始免费的机器学习课程,再结合本章内容复盘看,更有助于你理解)

总结

本周导学的内容较难,理解起来也比较困难,对于置信区间和假设检验两节,大家可以再额外补充一些统计学方面的相关知识,更有助于你理解;对于回归知识,建议多看几遍教学视频再结合例题,在实践中不断尝试去理解,大家加油!下周就要开始项目四了,阶段性的胜利就在前方!

If you tell yourself you can’t, you won’t.

Hi,同学们,上一阶段我们学习了数据分析的基本流程、Pandas在数据分析各个过程中的应用以及Matplotlib&Pandas的可视化基础,截至目前,你们已经算是掌握了基础的数据分析技能啦!撒花!但是在统计学理论和预测方面仍有欠缺,那么P4阶段就是解决这个欠缺哒!

本周开始,我们就进入到了项目四(P4)阶段,本阶段总共包含三周,在这三周内,我们要对统计学进行学习,掌握基础的描述统计学理论、基本的概率知识、二项分布和贝叶斯公式,并学会使用 Python 来实践;学习正态分布、抽样分布、置信区间以及假设检验的概念和计算方式;学习线性回归以及逻辑回归,在真实场景中应用,比如分析 A/B 测试结果,搭建简单的监督机器学习模型。可谓是时间紧任务重,但是也别怕,统计学的基础知识还是非常简单的,跟着课程内容一步步来,自己多做笔记多查资料,一定没问题的!

那么我们的课程安排:

时间 学习重点 对应课程
第1周 统计学基础 描述统计学 - 抽样分布与中心极限定理
第2周 统计学进阶 置信区间 - 逻辑回归
第3周 完成项目 项目:分析A/B测试结果

本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决:

饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧!

注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索!

本周目标

学习课程中的描述统计学 - 抽样分布与中心极限定理课程,掌握统计学基础知识。

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom 描述统计学 - 抽样分布与中心极限定理
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 本周学习总结、答疑
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

本周知识清单

描述统计学基础

描述统计分析就是通过数字或可视化的方法,对数据集进行整理、分析,并对数据的分布状态、数字特征和随机变量之间的关系进行估计和描述。其简要可以分为集中趋势分析、离散程度分析以及相关分析三大部分。所以,虽然这部分是选修内容,但拜托各位一定要看,这部分理论是数据分析的基础。

数据类型

数据类型是基础,尤其是之后在进行回归预测时,针对不同的数据类型可以选择不同的算法,所以必须掌握。

数据类型可以分为两大类:数值和分类;进而分为四小类:连续、离散、定序和定类。

数据类型
数值: 连续 离散
身高、年龄、收入 书中的页数、院子里的树、咖啡店里的狗
分类: 定序 定类
字母成绩等级、调查评级 性别、婚姻状况、早餐食品

描述统计的量

数据类型 描述方面 描述方式 备注
数值: 集中趋势 均值
中位数 偶数个时取中间两值均数
众数 存在没有或多个的可能
离散程度 极差 max - min
四分位差(IQR) 75%数 - 25%数
方差 每个观察值与均值之差平方和的平均数
标准差 方差的平方根
数据形状 左偏态 均值小于中位数(普遍但不绝对,下同)
(需做直方图) 右偏态 均值大于中位数
对称分布(通常是正态分布) 均值等于中位数
异常值 一般为上下超过1.5倍四分位差 处理方式见下面【异常值的处理】
分类: 分类计量个数或比例
  • 偏态分布示意图

  • 其他概念:

    • 五数概括描述法:利用最小值、第一四分位数(25%处)、第二四分位数(中位数)、第三四分位数(75%处)和最大值五个数对数值型变量的离散程度进行描述的方法。

    • 当我们的数据遵循正态分布时,我们可以使用均值标准差完全理解我们的数据集。

      但是,如果我们的数据集是偏态分布,五数概括法(和关联的集中趋势度量)更适用于概括数据。

    • 除直方图外,你还可以使用箱线图进行统计描述,箱线图其实是五数概括法的可视化。

  • 异常值的处理:

    1. 至少注意到它们的存在并确定对概括统计的影响。

    2. 如果是输入错误 — 删除或改正

    3. 理解它们为何存在,以及对我们想要回答的关于数据的问题的影响。

    4. 当有异常值时,报告五数概括法的值通常能比均值和标准差等度量更好地体现异常值的存在。

    5. 报告时要小心。知道如何提出正确的问题。

随机变量

随机变量集用大写字母,如X表示;

而集里面的某个变量用对应的小写字母,如x1,x2等表示。

推论统计学基础

推论统计就是根据现有收集的部分数据对更大的总体数据进行推论的方法。他的几个关键要素为:

  1. 总体 —— 我们想要研究的整个群体。
  2. 参数 —— 描述总体的数值摘要
  3. 样本 —— 总体的子集
  4. 统计量 —— 描述样本的数值摘要

辛普森悖论

本节以录取案例分析为例,展示了辛普森悖论。这个例子不必深究,只是为了提醒大家要以多种方式去观察数据,避免出现案例分析中的反例。

辛普森悖论是在某个条件下的两组数据,分别讨论时都会满足某种性质,可是一旦合并考虑,却可能导致相反的结论。那么如何避免辛普森悖论呢?那就要从产生它的源头——混杂因素上考虑,混杂因素就是一个与核心研究无关的变量,它会随着变量的改变而改变,就比如说在课程中的例子中,不同专业的总人数就有很大差异,它会随着专业的改变而改变。所以在之后处理类似问题时就要进行多变量分析,这样才能帮助我们认清事件的本质。

概率

概率与统计的关系

从课程中给的这幅关系图就能很明显的看出来,概率是由模型(MODEL)去预测数据(DATA),而统计是由数据去建立模型(进而再去做预测,也就是‘’根据数据去预测数据’‘)。

iAkgoj.png

基础知识

概率,是一种几率、可能性,描述是事件发生的可能性度量量。随机事件,指一个被赋予机率的事件
集合,针对的是事件在样本空间的一个子集。事件A发生的概率,用符号P(A)表示 。

  • 任何事件的发生概率在 0 和 1 之间,其中包括 0 和 1。(0表示不可能发生,1表示必然发生)

  • 独立事件:事件每次发生的结果与前后的发生结果无关。比如说,第一次掷骰子的结果与第二次的结果

  • 互斥事件:不可能在同一次实验中出现的俩事件。比如说,掷骰子实验中的1和6

  • 对立事件:是一种特殊的互斥事件,即试验中只有俩种可能A和B,那么事情的发生非A即B。可以表示为

    iuFI3Q.png

    如掷硬币的正面和反面。

  • 加法原理:若两种方法均能完成此事,则此事发生的概率为P(A) + P(B)

  • 乘法原理:若两个步骤分别不能完成此事,则此事发生的概率为P(A)·P(B)

二项分布

也叫伯努利分布,是指n个独立的事件A发生的概率分布。设每次试验中事件A发生的概率为p,则进行n次试验,A发生k次的概率为:

iuFocj.png

条件概率

在现实中,我们处理的事情并不像骰子和硬币那样简单,有些时间的结果往往依赖于其他的事情,比如说晨练的概率跟这个人是不是夜猫子有关等等。那么,这就引出了条件概率,即在事件B发生的条件下,事件A发生的概率为:

iuFTjs.png

其中,P(AB)表示AB同时发生的概率。

在如下的文氏图中,AB同时发生的概率可以表示为两个圆的交集,那么B已经发生的条件下A发生的概率就是这个交集(橙色部分)占整个B圆的比例。

iA5UMT.png

之前讲过独立事件,那么用公式的方式可以表达为:P(A) = P(A|B)。根据条件概率公式可以推导出,当P(AB) = P(A)P(B)时,则可说明A事件与B事件相互独立。

全概率公式

也就是A发生的概率为在互斥的多个事件(B1,B2…)已发生的条件下的条件概率之和。公式可以表示为:

iuFHun.png

贝叶斯法则

贝叶斯法则是概率推理的黄金法则,是利用先验概率计算后验概率的方法。

课程中的癌症例子十分贴切,讲解的也十分详细,所以大家看到前20个小节,能理解贝叶斯法则就可以了,后面的是在无人驾驶中的应用例子,可以跳过不看。

在课程示例中:

iuFqH0.md.png

由条件概率能计算出患癌与检查结果为阳性同时发生的概率P(C,Pos)(红色区域占整个矩形的比例)和没患癌与检查结果同时发生的概率P(~C,Pos)(绿色区域占整个矩形的比例)。

iuFbBq.png

二者相加,即为检查结果为阳性的概率(全概率公式)P(Pos)。

则,检查结果为阳性的条件下患癌概率为:

iuFOEV.png

这样我们就得到了更接近真实的检查结果为阳性的患癌概率。

iAIrnS.png

在这个例子中:

癌症发生的概率P(C)为先验概率,即在我们进行检查之前就对患癌概率的一个判断;

阳性结果下为癌症的概率P(C|Pos)为后验概率(阳性下非癌症、阴性癌症、阴性非癌症都是),这些是在检查发生之后,我们对患癌概率这件事的重新评估;

这就是贝叶斯法则的含义。我们先预估一个”先验概率”,然后加入实验结果,由此得到更接近事实的”后验概率”。

如果感觉理解困难,可以看一下白话版的贝叶斯讲解:怎样用非数学语言讲解贝叶斯定理(Bayes’s theorem)

Python概率练习

前面我们学习了概率的基本知识,有了理论基础,本节就是利用Python落地的教学。应用的第三方包为NumPy和Pandas。

均匀随机取整

使用的函数为numpy.random.randint(low, high=None, size=None, dtype='l')

  • low:当没有high参数输入时,作为取值范围的最大值+1;当有high参数输入时,则作为取值范围的最小值;
  • high:取值范围的最大值+1,默认为无输入;
  • size:输入数字则表示取值的数量,输入元组则表示取值矩阵的行和列;
  • dtype:数据类型,默认为np.int;
  • 函数的输出为int或者是由int数据类型组成的ndarray。

函数的具体用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

# 未定义high参数,取值范围是是0到1(即low - 1)
>>> np.random.randint(2, size=10)
array([1, 0, 0, 0, 1, 1, 0, 0, 1, 0])
# 定义了high参数,取值范围是2(即low)到4(即high - 1)
>>> np.random.randint(2,5,size = 10)
array([2, 2, 3, 3, 4, 2, 3, 2, 2, 4])
# 定义一个2x4的矩阵,取值范围是0到4
>>> np.random.randint(5, size=(2, 4))
array([[4, 0, 2, 1],
[3, 2, 2, 0]])

不均匀随机取数

使用的函数为numpy.random.choice(a, size=None, replace=True, p=None):

  • a:输入列表时,取数就从该列表中取;若输入为数字时,取值范围为0到该数字 - 1;
  • size:输入数字则表示取值的数量,输入元组则表示取值矩阵的行和列;
  • replace:布尔值,默认为True,若设置为False表示取数不会重复;(以从袋子中取球为例,True是取完放回再取,而False则是取了不放回,继续取)
  • p:表示概率,与a的输入值一一对应。
  • 函数的输出为int或者是由int数据类型组成的ndarray。

函数的具体用法如下:

1
2
3
4
5
6
7
8
9
#输入数字时取数
>>> np.random.choice(5, 3)
array([0, 3, 4])
#设置replace参数
>>> np.random.choice(5, 3, replace=False)
array([3,1,0])
#设置概率
>>> np.random.choice(5, 3, replace=False, p=[0.1, 0, 0.3, 0.6, 0])
array([2, 3, 0])

二项分布

使用的函数为numpy.random.binomial(n, p, size=None),参数也很好解释。

参数中的n即为每次试验中取值的次数,p则为试验中的某一种事件成功的概率,size则是试验的次数。

条件概率与贝叶斯规则测试

这里主要是一些Pandas函数的应用,经过上一阶段的学习应该已经很熟练了。

主要涉及的函数是分组和统计计数类的函数,比如说groupby,query,count等,如果忘记的话,自己查官方文档或者之前的笔记,这里不再赘述。

正态分布

课程中以抛硬币模型引入了二项分布进而讲解了正态分布模型,那么到底什么是正态分布或者满足什么条件就可以算是正态分布了呢?

在相同条件下,我们随机地对某一测试对象(抛硬币20次,其中正面的次数)进行多次测试(抛很多次20次)时,测得的数值在一定范围内波动(从0到20),其中接近平均值的数据(10左右)占多数,远离平均值的占少数。具有这种分布规律的随机变量的分布就称作正态分布。

大概长这样儿:

iEkWCR.png

它的概率密度函数可以表示为:

iuFXNT.png

这里为什么要引入正态分布呢?

  • 假设检验是基于正态分布的
  • 许多社会和经济现象对应的随机变量分布,都可以用正态分布来描述

中心极限定理

在此之前,先回顾下推论统计的几个概念:

  1. 总体 —— 我们想要研究的整个群体。
  2. 参数 —— 描述总体的数值摘要
  3. 样本 —— 总体的子集
  4. 统计量 —— 描述样本的数值摘要

课程中举得例子是统计优达学生中喝咖啡的人所占比例,我们看下图:

iEr4AK.png

图中所有的杯子(学生)就叫做总体;此外可以看到有四个深浅不一的蓝色底框,每个底框链接了5个学生,这5个学生就是样本,每组样本我们还计算了喝咖啡的比例,这就是统计量

一般的,样本数≥30即可称为大样本。 大样本条件下,抽样平均数的分布接近正态分布。

但必要抽样数目的确定是有相关公式计算的,这里就不给出了,感兴趣的话可以去搜搜看。

现在我们继续按照课程中的例子进行取样,样本容量为5,不断得取10000次,计算均值的分布情况如下:

iEcyUx.png

(完全看不出这是个什么分布)

将样本容量改为50,仍然取10000次,计算均值的分布情况如下:

iEc656.png

已经可以看出正态分布的样子了,那如果继续增加样本容量,改为5000,同样取10000次,计算均值的分布情况如下:

1536915532459

想比上一幅图,这幅可视化更接近正态分布,均值处于相同的位置,但方差(离散程度)明显小了很多。

上面的这个过程就是中心极限定理的含义,随着样本容量的逐渐增大,平均数的抽样分布越接近正态分布(但也不一定必须要很大很大才能近似于正态分布),同样这也适用于求和,比例等,但不适用于所有的统计量,比如说最大值,方差等等。

中心极限定理的妙处就在于,我们可以从任意的乱七八糟的分布取任意数量的样本值(比如上面例子中的5,50),然后计算样本的均值(或者和),不断得取值求均,最终做他们频率的可视化,你会发现这是一个非常完美的正态分布。

现实生活中有很多的随机过程,有的分布就是乱七八糟,但是你可以通过中心极限定理,得到他们均值或者和的正态分布,这也是为什么正态分布在统计中如此常用的原因之一。

如果感觉理解起来还是有点儿困难的话,你可以戳在线抽样分布模拟器,自己动手试一试。

大数定理

大数定理表达的是随着样本容量增加,样本平均数越来越接近总体平均数,字面上的意思很好理解,但这里有一点要注意,我们举例来说明一下:

比如说,我现在有100枚硬币,放在一个盒子里,随便摇一下盒子,打开,对正面朝上的硬币进行计数(当然,我们知道期望为100 x 0.5 = 50):

第一次实验的结果是55;第二次是60;第三次是70,三次实验的均值为((55+60+70)/3 ≈62),那你觉得,下次实验的结果是更有可能小于50还是大于50呢?

你有可能这样想,根据大数定理,随着我们试验次数的不断增加,均值肯定是不断趋向于50的,前三次的实验中每次都超过50,那么下次的实验会有更大的可能小于50,来纠正前三次实验的偏差。

如果你真的这样想,你就陷入了赌徒悖论。大数定理不关心前面发生的有限次实验,因为后面还有无限次的实验,而这无限次实验的期望值是50。这个例子可能比较随意,但这就是大数定理的含义。

自助法

自助法,bootstrap,也就是重复抽样。还记得上一节导学中讲到的numpy.random.choice函数吗?里面有一个replace参数,默认为True表示重复取样,也就是自助法;若设置为False,则表示不重复取样。

总结

本期导学主要对描述统计学和概率的基础知识进行了总结,这部分偏理论一些,如果觉得理解起来有点吃力,可以通过重复看视频,边看边用笔去算或者去网上搜集一些资料或者找一些教科书去查阅,要求是:不一定要完全掌握其原理,但求理解和会用。

Nothing is particularly hard if you divide it into small jobs.

Hi,同学们,本周是我们P3阶段的最后一周,前三周我们掌握了数据分析的基本流程、Pandas在数据分析各个流程中的基本应用,使用matplotlib&Pandas进行可视化的技巧,并且在项目三中得到了巩固和锻炼。我也陆续收到了大家的项目展示,都十分厉害,尤其是问题的提出以及可视化,非常能吸引人,只是数据整理阶段的代码还需再慢慢磨练,得以精简。本周导学呢,我们就是对之前所学做一个总结,希望大家也能自己做一份总结(这份总结才是最贴切你自己需求的),优达日的时候我们会一起交流一下自己的项目心得以及踩过的坑,等你们哦~

项目三(P3)阶段总共包含四周,在这一个月内,我们要对数据分析入门进行学习,学习数据分析思维,掌握Python数据分析及可视化方法,并使用所学知识完成项目三:探索数据集,尝试着自己完成整个数据分析的流程,得到一些饶有兴趣的结论,你一定会非常有成就感哒!那么以下便是这四周的学习安排:

时间 学习重点 对应课程
第1周 数据分析过程-1 数据分析过程&案例研究-1
第2周 数据分析过程-2 案例研究-1&案例研究-2
第3周 完成项目 项目:探索数据集
第4周 项目修改与通过 修改项目、查缺补漏、休息调整

!!看这里!!:在P3课程里面安排了SQL的高阶课程,但是因为在项目三中并不会涉及到SQL知识,所以为了保证大家学习的连贯性,在完成前两周的课程之后,就开始项目。至于!!SQL的高阶知识,大家可以放在课程通关后进行选修!!;

本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决:

饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧!

注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索!

本周目标

  • 完成你的项目,并且对P3阶段做一个自我总结,最好能以博客或者朋友圈文章的形式进行输出。

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom 项目三
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 本周学习总结、答疑
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

知识点清单

第六周-数据分析过程

  • 数据分析的基本流程

    • 提出问题
    • 整理数据(收集、评估、清理)
    • 探索性数据分析
    • 得出结论,传达结果
  • Pandas在数据分析中的应用

    • 导入文件(read_csv/excel/sep/encoding)
    • 数据评估(shape / info / describe / columns/ isnull/ duplicated/ value_counts/ sort_values/ ascending/ unique/ nunique)
    • 数据筛选(df[‘col_name’]/loc/iloc/np.r_/isin/query/groupby/&/|
    • 数据清理(drop/inplace/fillna/dropna/drop_duplicates/rename/replace)
    • 数据融合(merge/concat/append/join)
    • 可视化(plot)
    • 导出数据(to_csv/index/encoding = ‘utf-8-sig’)

第七周-可视化

  • 基本概念(fig/ax)

  • 开始绘图(plt.subplots/plt.add_subplot/plt.figure)

  • 坐标轴设置

    • 调整范围(ax.axis/xlim/ylim)

    • 调整刻度

      • 设置间隔(locator_params)
      • 设置顺序,角度(xticks(order_list,tick_names,rotation)
    • 双轴(twinx)

  • 标题与轴标题(title,xlabel,ylabel)

  • 图例(legend)

  • 颜色与样式(plot(x,y,’color``marker``line‘)

  • 网格(grid)

  • 图像注释(annote)

  • 平行于坐标轴的线(vline/hline)

  • 常用可视化图形

    • 散点图(scatter)
    • 条形图(bar/barh)
    • 直方图(hist)
    • 饼状图(pie)
    • 箱线图(box)

第八周-TMDb数据分析

  • 如何提出问题? 找出关键变量,提与之相关的问题
  • 数据备份(copy)
  • 如何将一列处理为多列?(genres列的处理
    • 拓展:pivot函数

  • 如何着手探索性数据分析?

    • 单变量 - 双变量 - 多变量
    • 关键变量 - 其他变量与关键变量
  • 可视化

    • 热度图(heatmap)
    • pairplot
  • 一些函数:

    • 获取某一位置的数值 quantile
    • 按列表筛选 isin

第八周-FBI枪支数据分析

  • DataFrame行列变换:transpose
  • 按字符串内容筛选:contains
  • 按索引进行数据融合:join

总结

通过这四周的学习,你又掌握了:

  • 数据分析的基本流程
  • Pandas在数据分析各个流程中的基本应用
  • Pandas常用函数的用法
  • Matplotlib在可视化中的应用

此外,你还增长了这些软技能:

  • 数据分析思维(化繁为简、化难为易、关键信息的提取)
  • 耐心(EDA的过程,做过的都知道)
  • 细心(有没有调试半天最终才发现是自己马虎导致的问题?)

如果你学习时间充裕,你还有可能掌握了:

  • Seaborn在可视化中的应用
  • 如何快速有效地使用搜索引擎
  • 在Stackoverflow注册账户,提出问题,成为一名铜牌用户
  • 有了自己的技术博客,并发表了第一篇总结性文章
  • … …

哈!这么总结下来,发现不知不觉间,又掌握了很多!又进步了很多!我导师之前教育我说:“你之所以现在这么焦虑,都是因为你自己的能力满足不了你的欲望。”那么,同样因为对未来感到焦虑来到这里学习的你们,经过这段时间的学习,焦虑是不是缓解了许多呢?哈哈,所以,请不要放松脚步,KEEP GOING!

Stop being afraid of what could go wrong and start being positive about what could go right.

Hi,同学们,经过了前两周的学习,我们掌握了数据分析的基本流程、Pandas在数据分析各个流程中的基本应用以及使用matplotlib&Pandas进行可视化的技巧,那么本周我们就真刀实枪地找一套数据集练练手。本周的导学有两期,分别选用了项目三中的两个数据集(TMDb电影数据和FBI枪支数据)进行分析,只是分享思路和方法,起一个抛砖引玉的作用,大家选择其他的数据集也可以举一反三,如果有什么棘手的问题随时微信联系我就OK~

本周开始,我们就进入到了项目三(P3)阶段,本阶段总共包含四周,在这一个月内,我们要对数据分析入门进行学习,学习数据分析思维,掌握Python数据分析及可视化方法,并使用所学知识完成项目三:探索数据集,尝试着自己完成整个数据分析的流程,得到一些饶有兴趣的结论,你一定会非常有成就感哒!那么以下便是这四周的学习安排:

时间 学习重点 对应课程
第1周 数据分析过程-1 数据分析过程&案例研究-1
第2周 数据分析过程-2 案例研究-1&案例研究-2
第3周 完成项目 项目:探索数据集
第4周 项目修改与通过 修改项目、查缺补漏、休息调整

!!看这里!!:在P3课程里面安排了SQL的高阶课程,但是因为在项目三中并不会涉及到SQL知识,所以为了保证大家学习的连贯性,在完成前两周的课程之后,就开始项目。至于!!SQL的高阶知识,大家可以放在课程通关后进行选修!!

本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决:

饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧!

注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索!

本周目标

  • 此处挑选和你确认过眼神的数据集,并对其进行数据分析和探索,得出你自己的结论,然后进行提交。

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom 项目三
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 本周学习总结、答疑
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

项目准备

环境准备

强烈建议大家完成本地环境的搭建,在本地完成此项目。搭建本地环境的方法请参考Anaconda的安装与配置一节,完成后你将获得本项目中会用到的关键软件:SpyderJupyter Notebook

文件准备

  • 项目文件:依次进入到项目:探索数据集 –> 3.实战项目中,下载项目文件的ipynb格式。

Pz6nds.md.png

  • 数据集选择:在此处选择你感兴趣的数据集并下载至与项目文件相同的文件夹。(若下载失败,请微信联系我索取)

  • 本地打开:在项目文件的文件夹下,按住Shift键,右击选择在此处打开命令窗口,输入jupyter notebook,待打开本地页面之后,选择项目文件打开,之后就请开始你的表演。

方法准备

项目文件中已经给大家列好了基本流程,所以请在开始项目之前,一定要先整体浏览一遍项目文件,着重看一下:

  • 项目流程
  • 每一个流程中你需要做哪些工作
  • 每一个流程中的提示

要记得,数据分析过程不是一蹴而就的,是螺旋上升接近目标的过程,所以一定要保持耐心,对照着项目评估准则一步步完成。

另外,一开始你的notebook会显得很乱没有章法,那在提交之前最好能再修改一个整理好的版本

项目流程(FBI枪支数据)

数据集说明

该数据来自联邦调查局 (FBI) 的全国即时犯罪背景调查系统 (NICS)。NICS 用于确定潜在买家是否有资格购买枪支或爆炸物。枪支店可以进入这个系统,以确保每位客户没有犯罪记录或符合资格购买。该数据已经收纳了来自
census.gov 的州级数据作为补充数据。NICS 数据在一个 xlsx 文件格式的一个表格中,它包含了按照月份(month)、州 (state) 、类型 (type) 统计的武器调查数量 (the number of firearm checks) ;美国的人口普查数据 (U.S. census data) 储存在一个 csv 文件中。它包含了州级的几个变量,每个州的大多数变量在 2016 年只有一个数据点,但一些变量有一年以上的数据。

提出问题

虽说本数据集有两个数据文件,但围绕的关键词只有一个,那就是枪支,所以提出问题时,也一定要围绕着该关键词进行提问。问题示例:

  • 就本数据集统计而言,哪个州的枪支总量增长最高?该州的增长速率如何?
  • 就本数据集统计而言,全美整体购买枪支总量及各种类的趋势是什么?
  • 2016年哪个州的人均拥有枪支量最高?
  • 结合2016年各州的人口普查数据,是否有哪项数据与人均拥有枪支量线性相关?

导入拓展包

一般来说,就导入如下几个拓展包就够了,当然如果后续操作中还需导入其他包的话,再补充即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 用这个框对你计划使用的所有数据包进行设置
# 导入语句。
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns

# 务必包含一个‘magic word’,以便将你的视图与 notebook 保持一致。
%matplotlib inline
#关于更多信息,请访问该网页:
# http://ipython.readthedocs.io/en/stable/interactive/magics.html

数据整理

导入数据

1
2
3
4
#导入枪支数据
df_gun = pd.read_excel('gun_data.xlsx')
#导入人口普查数据,这里有一点需要注意,若数据集中全部是包含有千位分隔符的数据,可以在read_csv中添加参数"thousands = ','"。
df_census = pd.read_csv('U.S. Census Data.csv')

评估数据

枪支数据

  • 浏览数据
1
df_gun.head()

这里要注意一点,因为数据集的列数较多,jupyter会自动折叠中间的部分列,导致我们预览数据时总是看不完整,这时候你可以尝试下:

1
2
#col_numbers设置为不小于你数据集列数的某一值
pd.set_option('max_columns',col_numbers)

同理,也可以用’max_rows’设置最大显示行数。

  • 列及数据类型
1
df_gun.info()
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
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 12485 entries, 0 to 12484
Data columns (total 27 columns):
month 12485 non-null object
state 12485 non-null object
permit 12461 non-null float64
permit_recheck 1100 non-null float64
handgun 12465 non-null float64
long_gun 12466 non-null float64
other 5500 non-null float64
multiple 12485 non-null int64
admin 12462 non-null float64
prepawn_handgun 10542 non-null float64
prepawn_long_gun 10540 non-null float64
prepawn_other 5115 non-null float64
redemption_handgun 10545 non-null float64
redemption_long_gun 10544 non-null float64
redemption_other 5115 non-null float64
returned_handgun 2200 non-null float64
returned_long_gun 2145 non-null float64
returned_other 1815 non-null float64
rentals_handgun 990 non-null float64
rentals_long_gun 825 non-null float64
private_sale_handgun 2750 non-null float64
private_sale_long_gun 2750 non-null float64
private_sale_other 2750 non-null float64
return_to_seller_handgun 2475 non-null float64
return_to_seller_long_gun 2750 non-null float64
return_to_seller_other 2255 non-null float64
totals 12485 non-null int64
dtypes: float64(23), int64(2), object(2)
memory usage: 2.6+ MB

纵览了一下,各列的数据类型基本没什么问题,唯一有问题的是month列,应该是datetime类型。整个数据集就是由时间、州名和各式各样的枪支数据组成的。

  • 查看各列的缺失值情况
1
2
#这里我们计算的缺失比例
df_gun.isnull().sum()/df_gun.shape[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
month                        0.000000
state 0.000000
permit 0.001922
permit_recheck 0.911894
handgun 0.001602
long_gun 0.001522
other 0.559471
multiple 0.000000
admin 0.001842
prepawn_handgun 0.155627
prepawn_long_gun 0.155787
prepawn_other 0.590308
redemption_handgun 0.155386
redemption_long_gun 0.155467
redemption_other 0.590308
returned_handgun 0.823789
returned_long_gun 0.828194
returned_other 0.854626
rentals_handgun 0.920705
rentals_long_gun 0.933921
private_sale_handgun 0.779736
private_sale_long_gun 0.779736
private_sale_other 0.779736
return_to_seller_handgun 0.801762
return_to_seller_long_gun 0.779736
return_to_seller_other 0.819383
totals 0.000000
dtype: float64

可见数据集的缺失情况非常严重,这时候需要你直接运行df_gun去观察全部数据,这样才能有据猜想数据缺失的原因。简要通览数据后,我们发现近年的数据缺失不大,猜想之前的统计中没有对枪支进行详细分类或者是统计不全导致的,而且就枪支数量而言,缺失数据较少的permit、handgun、long_gun和other等列占绝对优势,所以我们完全可以只筛选最有代表性的这几列进行分析。

因为筛选后的数据跟之前相差较大,为了提高后续步骤的效率,可以在此先进行数据清理

1
2
#因为此次筛选的数据列是间隔的,所以调用了numpy的r_函数生成列表,按照列序号筛选间隔的列。
df_gun = df_gun.iloc[:,np.r_[0:3,4,5,7,8,26]].dropna()

之后,还需对最后一列totals进行修正

1
df_gun['totals'] = df_gun['permit']+df_gun['handgun']+df_gun['long_gun']+df_gun['multiple']+df_gun['admin']
  • 查看重复值
1
2
#检查是否有数据重复
sum(df_gun.duplicated())
1
0

无重复数据。

  • 查看state列的唯一值数
1
df_gun['state'].nunique()
1
55

美国一共有50个州,多出来的5个是什么鬼?是不是有缩写的州名导致的重复?

1
df_gun['state'].value_counts()
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
New Mexico              227
California 227
South Carolina 227
Arkansas 227
Kansas 227
New Jersey 227
West Virginia 227
Texas 227
Maryland 227
District of Columbia 227
New Hampshire 227
Alaska 227
Mississippi 227
Alabama 227
Vermont 227
Illinois 227
North Dakota 227
Rhode Island 227
Pennsylvania 227
Oklahoma 227
Kentucky 227
Florida 227
North Carolina 227
Utah 227
Idaho 227
Connecticut 227
Missouri 227
Nebraska 227
Tennessee 227
Massachusetts 227
Nevada 227
Arizona 227
Hawaii 227
Indiana 227
Oregon 227
Michigan 227
Minnesota 227
Ohio 227
New York 227
Wyoming 227
Iowa 227
Maine 227
Guam 227
Wisconsin 227
South Dakota 227
Puerto Rico 227
Georgia 227
Washington 227
Delaware 227
Louisiana 226
Virginia 226
Montana 226
Colorado 226
Mariana Islands 218
Virgin Islands 214
Name: state, dtype: int64

结果一目了然,不仅有美国各州,还包括了Mariana Islands 、Virgin Islands 等地,感兴趣可以去搜了一下,都是老美宣誓主权的一些群岛。

人口普查数据

评估的步骤差不多,所以只罗列一些需要注意的点。

1
df_census.info()
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 85 entries, 0 to 84
Data columns (total 52 columns):
Fact 80 non-null object
Fact Note 28 non-null object
Alabama 65 non-null object
Alaska 65 non-null object
Arizona 65 non-null object
Arkansas 65 non-null object
California 65 non-null object
Colorado 65 non-null object
Connecticut 65 non-null object
Delaware 65 non-null object
Florida 65 non-null object
Georgia 65 non-null object
Hawaii 65 non-null object
Idaho 65 non-null object
Illinois 65 non-null object
Indiana 65 non-null object
Iowa 65 non-null object
Kansas 65 non-null object
Kentucky 65 non-null object
Louisiana 65 non-null object
Maine 65 non-null object
Maryland 65 non-null object
Massachusetts 65 non-null object
Michigan 65 non-null object
Minnesota 65 non-null object
Mississippi 65 non-null object
Missouri 65 non-null object
Montana 65 non-null object
Nebraska 65 non-null object
Nevada 65 non-null object
New Hampshire 65 non-null object
New Jersey 65 non-null object
New Mexico 65 non-null object
New York 65 non-null object
North Carolina 65 non-null object
North Dakota 65 non-null object
Ohio 65 non-null object
Oklahoma 65 non-null object
Oregon 65 non-null object
Pennsylvania 65 non-null object
Rhode Island 65 non-null object
South Carolina 65 non-null object
South Dakota 65 non-null object
Tennessee 65 non-null object
Texas 65 non-null object
Utah 65 non-null object
Vermont 65 non-null object
Virginia 65 non-null object
Washington 65 non-null object
West Virginia 65 non-null object
Wisconsin 65 non-null object
Wyoming 65 non-null object
dtypes: object(52)
memory usage: 34.6+ KB

发现一个奇怪的事情,基本上所有列数据都在65行之后没有了,肯定有什么猫腻,可以用tail()或者直接打开文件查看(因为数据量很小),发现后面几行都是对数据统计的一些说明,没有实际意义,直接删除即可。而且在该数据中只有50个州的数据。

清理数据

清理数据就是对上一步中发现的问题进行清理,并且删除无关列,最终得到的是一个方便你进行分析及可视化的干净数据。

清理前记得备份数据

  • 删除无关列

    建议使用drop函数

    1
    2
    3
    4
    #删除列
    df_census.drop('Fact Note',axis = 1,inplace = True)
    #删除行
    df_census.drop(np.arange(64,85),inplace = True)
  • 数据融合

    想要找出人口普查的数据与枪支数据之间的关系,肯定要把这两个数据进行融合。

    融合前,我们先观察一下人口普查数据中到底有哪些,发现每个州的大部分变量都只在2016年有记录点,所以我们就要分别从人口普查数据和枪支数据中筛选出2016年的数据,再以州作为键(key)进行合并。

    筛选数据

    1
    2
    3
    4
    5
    6
    #先筛选出人口普查数据中2016年的数据,并将Fact列作为索引
    df_census_2016 = df_census[df_census.Fact.str.contains('2016')].set_index('Fact')
    #转秩
    df_census_2016 = df_census_2016.transpose()
    #筛选2016年的枪支数据,并按照州分组计算全年均值
    df_gun_2016 = df_gun[df_gun['month'].str.contains('2016')].groupby('state').mean()

    处理千位分隔符和百分号

    在人口普查数据中数字中均包含有千位分隔符或者是百分号,这会给我们之后进行分析带来不便,处理掉他们,并且转换为浮点型数据。

    1
    2
    3
    4
    5
    #先将有千位分隔符的列转为float类型
    for i in [ 'Population estimates, July 1, 2016, (V2016)','Housing units, July 1, 2016, (V2016)', 'Building permits, 2016']:
    df_census_2016[i] = df_census_2016[i].str.split(',')
    df_census_2016[i] = df_census_2016[i].str.join('')
    df_census_2016[i] = df_census_2016[i].astype(float)

    百分号的处理方式同上类似。

    数据融合

    我们在之前的导学中总结过Pandas做数据融合的方法,就此项目而言,两个数据以索引(Index,也就是各州的州名)为键进行融合,最简单的方法就是用join()函数了。如果你忘了,可以点这里复习一下。

    1
    df_2016 = df_gun_2016.join(df_census_2016)

    好,至此我们的数据就算是整理完毕了,接下来就是探索性分析及可视化阶段,这里没有什么特别需要注意的地方,大家就随性而为。

探索性数据分析

在这个阶段你可以随意做可视化,尽可能多得去探索你想解决的问题。在探索阶段,作图可以不用很规范,你自己知道是什么意思就可以,而且可能会有些探索的问题结果意义不大,所以在提交项目时,要进行择优保留并对其润色修饰

  • 探索不同年份,美国或者是不同州的枪支数量变化就使用df_gun数据集;
  • 探索不同州的人口普查数据与枪支持有量之间的关系就使用我们之后整理的df_2016数据集。

得出结论

对你整理好的可视化图像进行总结,结论要有根有据但也不要只是停留在描述,可以进行适当的猜测。

最后

  • 导学只是参考和分享,我是还原了自己在做项目时的思路历程,这并不是提交项目时应有的样子。
  • 记得提交前一定要再重新审视一遍,调整代码,注释,修缮可视化及结论。
  • 经过P3的历练,相信你能更自信,也更能有成就感,坚持!!
  • 加油!!!

Awareness is the greatest agent for change.

Hi,同学们,经过了前两周的学习,我们掌握了数据分析的基本流程、Pandas在数据分析各个流程中的基本应用以及使用matplotlib&Pandas进行可视化的技巧,那么本周我们就真刀实枪地找一套数据集练练手。本周的导学有两期,分别选用了项目三中的两个数据集(TMDb电影数据和FBI枪支数据)进行分析,只是分享思路和方法,起一个抛砖引玉的作用,大家选择其他的数据集也可以举一反三,如果有什么棘手的问题随时微信联系我就OK~

本周开始,我们就进入到了项目三(P3)阶段,本阶段总共包含四周,在这一个月内,我们要对数据分析入门进行学习,学习数据分析思维,掌握Python数据分析及可视化方法,并使用所学知识完成项目三:探索数据集,尝试着自己完成整个数据分析的流程,得到一些饶有兴趣的结论,你一定会非常有成就感哒!那么以下便是这四周的学习安排:

时间 学习重点 对应课程
第1周 数据分析过程-1 数据分析过程&案例研究-1
第2周 数据分析过程-2 案例研究-1&案例研究-2
第3周 完成项目 项目:探索数据集
第4周 项目修改与通过 修改项目、查缺补漏、休息调整

!!看这里!!:在P3课程里面安排了SQL的高阶课程,但是因为在项目三中并不会涉及到SQL知识,所以为了保证大家学习的连贯性,在完成前两周的课程之后,就开始项目。至于!!SQL的高阶知识,大家可以放在课程通关后进行选修!!

本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决:

饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧!

注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索!

本周目标

  • 此处挑选和你确认过眼神的数据集,并对其进行数据分析和探索,得出你自己的结论,然后进行提交。

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom 项目三
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 本周学习总结、答疑
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

项目准备

环境准备

强烈建议大家完成本地环境的搭建,在本地完成此项目。搭建本地环境的方法请参考Anaconda的安装与配置一节,完成后你将获得本项目中会用到的关键软件:SpyderJupyter Notebook

文件准备

  • 项目文件:依次进入到项目:探索数据集 –> 3.实战项目中,下载项目文件的ipynb格式。

Pz6nds.md.png

  • 数据集选择:在此处选择你感兴趣的数据集并下载至与项目文件相同的文件夹。(若下载失败,请微信联系我索取)

  • 本地打开:在项目文件的文件夹下,按住Shift键,右击选择在此处打开命令窗口,输入jupyter notebook,待打开本地页面之后,选择项目文件打开,之后就请开始你的表演。

方法准备

项目文件中已经给大家列好了基本流程,所以请在开始项目之前,一定要先整体浏览一遍项目文件,着重看一下:

  • 项目流程
  • 每一个流程中你需要做哪些工作
  • 每一个流程中的提示

要记得,数据分析过程不是一蹴而就的,是螺旋上升接近目标的过程,所以一定要保持耐心,对照着项目评估准则一步步完成。

另外,一开始你的notebook会显得很乱没有章法,那在提交之前最好能再修改一个整理好的版本

项目流程(TMDb)

数据集说明

本项目选择的数据集为Kaggle提供的TMDb电影数据。此数据集中包含 1 万条电影信息,信息来源为“电影数据库”(TMDb,The Movie Database),包括用户评分和票房等。数据已进行了简单清理,涉及到的变量如下表所示:

变量名 注释 变量名 注释
id 电影序号 keywords 电影关键词
imdb_id imdb电影序号 overview 剧情摘要
popularity 受欢迎程度 runtime 电影时长(min)
budget 预算($) genres 电影风格
revenue 收入 production_companies 制作公司
original_title 电影名称 release_date 发布日期(月/日/年)
cast 演员表 vote_count 评价次数
homepage 电影网址 vote_average 平均评分
director 导演 release_year 发布年份
tagline 宣传词 budget_adj 预算(考虑通胀)
revenue_adj 收入(考虑通胀)

提出问题

对数据简单浏览之后,你要进行角色扮演了,假如你现在就是一名电影行业的数据分析师,通过分析此数据集,你能为公司提供哪些有用的发现或者规律呢?或者你只是一名会数据分析的电影爱好者,通过分析此数据集,你能否给小伙伴们推荐一些合适的电影呢?这里提供几个参考:

  • 电影类型相关:

    • 哪些类型的受欢迎程度最高?随着时间推移有什么变化呢?
    • 随着时间的推移,各类型的数量身上有什么变化呢?
    • 哪些类型赚钱最多?投资收益比呢?
    • 哪些类型拍摄的数量最多?
  • 导演相关:

    • 哪些导演最能吸金?
    • 哪些导演的电影平均评分最稳定或者最高?
  • 制作公司相关:

    • 哪些公司最能赚钱?最能赚口碑?评分最稳定或者最高?
  • 影响电影评分的要素有哪些?

  • 影响电影收益的要素有哪些?

  • 最近几年的电影都有哪些关键词?

    ……

整理好你感兴趣的问题后,那就开始吧~

在本示例中,选择的主题为今晚有空,让好电影与你相伴,所以我们的目标就是筛选出好看的电影咯~

导入拓展包

一般来说,就导入如下几个拓展包就够了,当然如果后续操作中还需导入其他包的话,再补充即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 用这个框对你计划使用的所有数据包进行设置
# 导入语句。
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns

# 务必包含一个‘magic word’,以便将你的视图与 notebook 保持一致。
%matplotlib inline
#关于更多信息,请访问该网页:
# http://ipython.readthedocs.io/en/stable/interactive/magics.html

数据整理

导入数据

1
2
df = pd.read_csv('tmdb-movies.csv')
df.head(3)

评估数据

  • 列及数据类型
1
df.info()
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
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10866 entries, 0 to 10865
Data columns (total 21 columns):
id 10866 non-null int64
imdb_id 10856 non-null object
popularity 10866 non-null float64
budget 10866 non-null int64
revenue 10866 non-null int64
original_title 10866 non-null object
cast 10790 non-null object
homepage 2936 non-null object
director 10822 non-null object
tagline 8042 non-null object
keywords 9373 non-null object
overview 10862 non-null object
runtime 10866 non-null int64
genres 10843 non-null object
production_companies 9836 non-null object
release_date 10866 non-null object
vote_count 10866 non-null int64
vote_average 10866 non-null float64
release_year 10866 non-null int64
budget_adj 10866 non-null float64
revenue_adj 10866 non-null float64
dtypes: float64(4), int64(6), object(11)
memory usage: 1.7+ MB

纵然了一下,各列的数据类型没什么问题,唯一一个可能有问题的是release_date列,应该是datetime类型,但因为我们后面的分析中只会用到电影的上映年份,也就是release_year列,所以这列不处理也罢。

  • 查看各列的缺失值情况
1
df.isnull().sum()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
id                         0
imdb_id 10
popularity 0
budget 0
revenue 0
original_title 0
cast 76
homepage 7930
director 44
tagline 2824
keywords 1493
overview 4
runtime 0
genres 23
production_companies 1030
release_date 0
vote_count 0
vote_average 0
release_year 0
budget_adj 0
revenue_adj 0

可见数据集的情况很不错,几个关键列几乎没有缺失。至于director列的缺失,你可以依照电影标题去搜索它的导演,然后进行填充,或者干脆直接删除掉。

  • 查看重复值
1
sum(df.duplicated())
1
1

有一行重复数据,过会儿直接清理掉。

  • 查看基本数据统计情况
1
df.describe()

iSxdmD.png

因为这是在数据评估阶段,所以着重看min和max,检查是否有异常值。本数据集中没什么问题。

  • 查看各列元素

    1
    df['column_name']

可以查看各列的详细情况,避免因为折叠而忽略了某些严重问题。

比如说,我们通过查看各列情况,发现castkeywordsgenresproduction_companies这四列中的都包含有以|分隔开的多个平级元素,这在进行之后的按类分析时会非常不便,所以需要清理。(但也不是这四列都要清理,只用清理你的分析中会用到的就行。)

iSzMgP.png

还有就是budget_adjrevenue_adj两列是科学记数法,在进行可视化的时候,坐标轴的显示肯定就会很丑,到时候要注意处理。

清理数据

清理数据就是对上一步中发现的问题进行清理,并且删除无关列,最终得到的是一个方便你进行分析及可视化的干净数据。

清理前记得备份数据

  • 数据备份

    1
    df_clean = df.copy()
  • 删除无关列

    在本次示例项目中,我们的目的是找出好看的电影,所以评分和受欢迎程度是关键参数,然后再探索下他们与其他参数之间是否存在联系。

    那就按照如下方法删除一些无关列(其实是筛选出想要的列,顺便再拍一下序):

    1
    df = df[['original_title','production_companies','director','cast','genres','keywords','runtime','popularity','vote_count','vote_average','release_year','budget_adj','revenue_adj']]
  • 缺失值的处理

    因为关键列并没有出现数据缺失,所以并未进行处理。

  • 删除重复值

    1
    df.drop_duplicates(inplace = True)
  • genres列处理

    电影类型是关键筛选条件,所以要细分。

    1
    2
    #将genres列转为str格式(因为NaN是float格式的)
    df_clean.genres = df_clean.genres.astype(str)
    1
    2
    3
    4
    #获取所有的电影类型
    genres_set = set() #定义空集合
    for x in df_clean['genres']:
    genres_set.update(x.split('|'))
    1
    2
    #从genres_set中删除nan
    genres_set.remove('nan')
    1
    2
    3
    #将各电影类型作为列添加到数据集中,并用1表示‘是’,0表示‘否’
    for genres in genres_set:
    df_clean[genres] = df_clean['genres'].str.contains(genres).apply(lambda x:1 if x else 0)
    1
    2
    3
    #删除genres列,并检查
    df_clean.drop('genres',axis = 1,inplace = True)
    df_clean.head(3)
  • production_companies列处理

    属于电影的参考列,所以我们只筛选首公司。

    1
    2
    #只筛选第一家主要投资的公司
    df_clean.production_companies = df_clean.production_companies.str.split('|').str[0]
    1
    2
    #为了符合逻辑,更改列名
    df_clean.rename(columns = {'production_companies':'production_company'},inplace = True)
  • cast列处理

    演员也是电影的参考列,只筛选出两名主演。

    1
    2
    3
    4
    5
    #筛选前两位主演
    df_clean['major_actor_1'] = df_clean.cast.str.split('|').str[0]
    df_clean['major_actor_2'] = df_clean.cast.str.split('|').str[1]
    #删除cast列
    df_clean.drop('cast',axis = 1,inplace = True)
  • 添加income_adj

    原数据中只有budget_adjrevenue_adj列,后者减去前者即为电影的收益。

    1
    df_clean['income_adj'] = df_clean['revenue_adj'] - df_clean['budget_adj']

    至此,清理数据告一段落。

探索性数据分析

在这个阶段你可以随意做可视化,尽可能多得去探索你想解决的问题。在探索阶段,作图可以不用很规范,你自己知道是什么意思就可以,而且可能会有些探索的问题结果意义不大,所以在提交项目时,要进行择优保留并对其润色修饰

探索受欢迎程度及评分

电影的受欢迎程度和平均评分是我们在进行电影推荐时的主要参考,所以我们先来观察下这两列的主要分布情况以及与其他列的相关性。

  • 分布情况
1
2
3
4
#受欢迎程度的分布情况
df_clean['popularity'].plot(kind = 'hist',bins = 200,title = 'The Distribution of Popularity(log)',logx = True,figsize = (8,6))#这里采用了x轴的对数坐标,考虑下为什么呢?
plt.ylabel('Count of Movies')
plt.xlabel('Popularity(log)');

ipxy2q.png

1
2
3
4
#平均评分的分布情况
df_clean['vote_average'].plot(kind = 'hist',bins = 30,title = 'The Distribution of Average Rating',figsize = (8,6))#这里就是用的普通的x轴坐标,为什么呢?
plt.ylabel('Count of Movies')
plt.xlabel('Average Rating');

ipx7xx.png

通过观察这两幅图我们可以发现:绝大部分的电影受欢迎程度都在10以下,平均评分却是一个类正态分布,电影评分集中在5到7之间。

  • 与上映年份的关系

    1
    2
    3
    #受欢迎程度
    df_clean.groupby('release_year')['popularity'].mean().plot(kind = 'line')
    plt.hlines(df_clean['popularity'].quantile(.75),xmin = 1960,xmax = 2015,color = 'red');

    ipz9zt.png

    1
    2
    3
    #评分
    df_clean.groupby('release_year')['vote_average'].mean().plot(kind = 'line')
    plt.hlines(df_clean['vote_average'].quantile(.75),xmin = 1960,xmax = 2015,color = 'red');

    ipzpRI.png

通过观察这两幅可视化,我们发现:随着上映日期逐渐接近现在,受欢迎程度呈波动上升趋势,但是评分却是波动下降。这应该是因为年代越久远的电影观看人数越少,评分次数也就越少(需附图验证),个别的高评分对平均评分的影响也就越大,这才导致了受欢迎程度低却评分高的现象。

  • 与其他数值型变量的关系

本数据集中的数值型变量不是很多,但要是一对一对的去看他们之间的相关性会很累,懒人智者推动科技进步嘛,前辈们帮我们都考虑好了,可以参考下面的代码:

1
2
#筛选出数值变量
df_corr = df_clean[['runtime','popularity','vote_count','vote_average','budget_adj','revenue_adj','income_adj']]

各变量之间相关性的热度图

1
2
3
4
5
fig, ax = plt.subplots(figsize=(10, 6)) 
corr = df_corr.corr() #计算相关性
hm = sns.heatmap(round(corr,2), annot=True, ax=ax, cmap="coolwarm",fmt='.2f', linewidths=.05)
fig.subplots_adjust(top=0.93)
fig.suptitle('Movie Attributes Correlation Heatmap', fontsize=14);

i97tOJ.png

从这幅图里面,可以很明显的读出一些信息:

  • 受欢迎程度与评分人数有较强的正相关关系,与收益的正相关程度也稍强,这很好理解;
  • 平均评分却鲜有相关的变量,那影响评分的因素都有哪些呢?(导演?主演?制片公司?)

pairplot

你不满足于只看冷冰冰的数字,想看到更直观的散点图或者直方图,那就请参考如下代码:

1
2
3
4
5
pp = sns.pairplot(df_corr, size=1.8, aspect=1.8, plot_kws=dict(edgecolor="k", linewidth=0.5), diag_kind="kde", diag_kws=dict(shade=True)) 
fig = pp.fig
fig.subplots_adjust(top=0.93, wspace=0.3)
t = fig.suptitle('Movie Attributes Pairwise Plots', fontsize=14)

i9HinJ.png

从上面这幅可视化中,我们不仅能看到各变量两两之间的散点图(相关性),还能看到各变量的分布情况,真可谓是大杀器。

那,热度与评分和其他分类变量有没有什么关系呢?

…(请继续探索)

… KEEP GOING

电影推荐

在做电影推荐时,受欢迎程度和评分是我们的关键评估指标。

  • 按电影类型推荐

比如说,你有一个哥们比较喜欢看Adventure类的电影,听说你在做TMDb的电影数据分析,所以来找你推荐,你会推荐哪些呢?

1
2
#首先我们要筛选出Adventure类的电影
df_Ad = df_clean[df_clean['Adventure'] == 1]
1
2
3
#既然是推荐,自然要筛选一些热门的评分高的电影,所以这里我们选择了好于其他90%的电影(结果为15部电影)
df_Ad_po = df_Ad[df_Ad.popularity > df_Ad.popularity.quantile(.9)]
df_Ad_po_vo = df_Ad_po[df_Ad_po.vote_average > df_Ad_po.vote_average.quantile(.9)]
1
2
#排序
df_Ad_po_vo.sort_values(by = 'popularity',inplace = True)
1
2
3
4
5
6
7
8
#可视化
sns.set(style="white")#小美化一下

x = df_Ad_po_vo.original_title
y = df_Ad_po_vo['popularity']
#排序能让可视化更美观
plt.yticks(np.arange(len(x)), x)
plt.barh(np.arange(len(x)),y);

i9kJRe.png

结论立马就出来了,首推的电影就是Interstellar(星际穿越)。当然这种方法可以定义成一个函数,参数即为电影类型,这样就能省心省力的得到所有电影的最热最佳推荐了。

当然,你还可以尝试:

  • 按导演推荐

    我一开始想着用groupby直接按照导演分类,然后求评分的均值再作图,可是结果并不如人意。

1
df_clean.groupby('director')['vote_average'].mean().sort_values()[-15:].plot(kind = 'barh',color = 'b');

iCNGXd.png

这些导演好像都不是很熟悉,应该是数据集中只收录了一部或者很少的电影作品,然而又因为这些作品的评分较高,才导致这种情况,所以我们要先对导演做一个筛选,比如说,筛选出收入作品数量在10部及以上的导演。

1
2
3
4
5
6
7
#先对原数据中的director列作计数统计,然后筛选大于等于10的数据存为一个新的DataFrame(目的是为了方便筛选)
df_director = pd.DataFrame(df_clean.director.value_counts() >= 10)
#将10部及以上作品的导演存为一个列表
directors = list(df_director[df_director['director']].index)
#然后使用isin函数,筛选原数据中在directors列表中的导演,并求均值作图
#平均评分
df_clean[df_clean.director.isin(directors)].groupby('director')['vote_average'].mean().sort_values()[-10:].plot(kind = 'barh',color = 'b');

iCUhVI.png

1
2
#受欢迎程度
df_clean[df_clean.director.isin(directors)].groupby('director')['popularity'].mean().sort_values()[-10:].plot(kind = 'barh',color = 'b');

iCUWqA.png

这次得到的结果更大众一些,出现的导演名字也基本都听过。Christopher Nolan和Quentin分别获得了双料榜首和榜眼,这两个人的名字也算是电影的品质保证了吧。

  • 按主演推荐

  • 按制片公司推荐

    … …

当然,你还可以分析电影评分与其他变量的相关性,或者从效益角度出发,去分析票房、预算、收益等等。但万变不离其宗,用数据分析的流程做指导,所学知识为基础,Bing或者Google为利剑(搜索的时间可能要占到一半以上,所以不要慌,搜索完记在小本本上),开始你的项目三征服之路吧!

得出结论

对你整理好的可视化图像进行总结,结论要有根有据但也不要只是停留在描述,可以进行适当的猜测。

最后

  • 导学只是参考和分享,我是还原了自己在做项目时的思路历程,这并不是提交项目时应有的样子。
  • 记得提交前一定要再重新审视一遍,调整代码,注释,修缮可视化及结论。
  • 经过P3的历练,相信你能更自信,也更能有成就感,坚持!!
  • 加油!!!

If you don’t like where you are , change it. You’re not a tree.

Hi,同学们,上一周我们学习了数据分析的基本流程,以及Pandas在数据分析各个流程中的应用,本周呢就是在上周的基础上,掌握Python数据分析可视化的基础知识,包括matplotlibpandas可视化。可视化是数据分析的重要环节,是你进行探索性数据分析、得出结论、传达结果的关键,所以,一定的可视化技巧是非常必须的,除了本章涉及到的两个知识点外,我还会在最后提供一些其他的python可视化库链接和其他可视化软件的链接,希望大家能不满足于导学,而去积极求索,加油!!

本周开始,我们就进入到了项目三(P3)阶段,本阶段总共包含四周,在这一个月内,我们要对数据分析入门进行学习,学习数据分析思维,掌握Python数据分析及可视化方法,并使用所学知识完成项目三:探索数据集,尝试着自己完成整个数据分析的流程,得到一些饶有兴趣的结论,你一定会非常有成就感哒!那么以下便是这四周的学习安排:

时间 学习重点 对应课程
第1周 数据分析过程-1 数据分析过程&案例研究-1
第2周 数据分析过程-2 案例研究-1&案例研究-2
第3周 完成项目 项目:探索数据集
第4周 项目修改与通过 修改项目、查缺补漏、休息调整

!!看这里!!:在P3课程里面安排了SQL的高阶课程,但是因为在项目三中并不会涉及到SQL知识,所以为了保证大家学习的连贯性,在完成前两周的课程之后,就开始项目。至于!!SQL的高阶知识,大家可以放在课程通关后进行选修!!

本阶段可能是个挑战,请一定要保持自信,请一定要坚持学习和总结,如果遇到任何课程问题请参照如下顺序进行解决:

饭要一口一口吃,路要一步一步走,大家不要被任务吓到,跟着导学一步一步来,肯定没问题哒!那我们开始吧!

注:本着按需知情原则,所涉及的知识点都是在数据分析过程中必须的、常用的,而不是最全面的,想要更丰富,那就需要你们课下再进一步的学习和探索!

本周目标

  • 学习总结课程中数据分析过程案例研究1&2中所用到的可视化知识,掌握可视化在数据分析中的应用。

学习计划

时间 学习资源 学习内容
周二 微信群 - 每周导学 预览每周导学
周三、周四 Udacity - Classroom 案例研究1&2
周五 微信/Classin - 1V1 课程难点
周六 Classin - 优达日 本周学习总结、答疑
周日 笔记本 总结沉淀
周一 自主学习 查漏补缺

本周知识清单

matplotlib

matplotlib是Python泰斗级别的绘图库,因受到Matlab的启发构建而成,所以你会觉得它的命令API,还有那九十年代感强烈的可视化图像跟matlab很相似。它非常适合在jupyter notebook中交互式作图,这个库“功能非常强大”,但也“非常复杂”,所以这里只能介绍matplotlib的一些基础和常用的方法,想了解更多就需要你自主探索啦!

  • 导入matplotlib
1
import matplotlib.pyplot as plt
  • 在notebook中使用
1
2
#想在Jupyter Notebook中顺利显示出可视化图像,你需要添加如下代码
%matplotlib inline

官方链接

你可以点击matplotlib.pyplot搜索查看一些函数的说明和用法;或者你可以点击Pyplot Gallery查看一些代码实例,找到灵感。

基本概念

在使用matplotlib生成图像时,整个图像为一个Figure对象。在Figure对象中可以包含一个,或者多个Axes对象。每个Axes对象都是一个拥有自己坐标系统的绘图区域。其逻辑关系如下:

P7zm2n.jpg

在如下的单图fig中,我们给出了我们的绘图中只有一个坐标系区域(也就是ax),此外还有以下对象:

  • Data: 数据区,包括数据点、描绘形状
  • Axis: 坐标轴,包括 X 轴、 Y 轴及其标签、刻度尺及其标签
  • Title: 标题,数据图的描述
  • Legend: 图例,区分图中包含的多种曲线或不同分类的数据
  • 其他的还有图形文本 (Text)、注解 (Annotate)等其他描述

P7zQbT.jpg

各个对象之间的隶属关系如下图所示:

P7zMrV.jpg

所以大家在之后进行可视化的时候,根据这些隶属关系来去对参数进行设置,这样逻辑不乱,代码也清晰。

常用参数设置

开始绘图

在绘图前,首先需要设置的就是fig(画布)和ax(图),我们主要通过plt.subplots()函数来定义

1
2
#绘制单图
fig, ax = plt.subplots()

Pbp9aT.png

1
2
#绘制多图,subplots的第一个参数为行数,第二个参数为列数
fig,(ax1,ax2) = plt.subplots(1,2,sharey = True)#设置共享y轴

PbSzq0.png

1
2
#绘制多图时,注意前面的变量为一个矩阵的形式,如下前面为2x2矩阵,则后面subplots的行列参数也应该都为2
fig,((ax1,ax2),(ax3,ax4)) = plt.subplots(2,2,sharex = True)#设置共享x轴

PbppZV.png

另一种添加子图的方法

绘制子图主要使用的函数为:add_subplot(abc),调用该函数会生成一个包含axb个子图的画布,而c则表示位置,按照从左至右,从上至下的顺序依次排列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
x = np.arange(1,100)

fig = plt.figure() #定义画布
ax1 = fig.add_subplot(221) # 定义2*2个子图(1表示左一)
ax1.plot(x,x) # 绘制左一折线图

ax2 = fig.add_subplot(222)
ax2.plot(x,-x) # 绘制右一折线图(右一)

ax3 = fig.add_subplot(223)
ax3.plot(x,x*x) # 绘制左二折线图(左二)

ax4 = fig.add_subplot(224)
ax4.plot(x,np.log(x)); # 绘制右二折线图(右二),添加分号可以只显示图像

PHCqtU.png

坐标轴设置

  • 调整范围

    主要是用来利用调整坐标轴范围进行图像的截取,可以使用ax.axis()函数,也可使用plt.xlim()或者plt.ylim()函数,具体用法如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #ax.axis([0,10,0,50]) [x左,x右,y下,y上]
    x = np.arange(-10,10,0.1)
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(x,x**2)
    ax.axis([0,10,0,50])

    #plt.xlim([0,10]) ,调整x轴坐标范围
    #plt.ylim([0,50]) ,调整y轴坐标范围
    fig1 = plt.figure()
    ax1 = fig1.add_subplot(111)
    ax1.plot(x,x**2)
    plt.xlim([0,10])
    plt.ylim([0,50]);

    PHO6UJ.png
    PHOyE4.png

  • 坐标轴刻度调整

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #利用ax.locator_params()设置刻度间隔

    x = np.arange(0,11,0.1)
    fig1 = plt.figure()
    ax1 = fig1.add_subplot(111)
    ax1.plot(x,x)
    #ax1.locator_params(nbins=20) #同时调整x轴与y轴
    #ax1.locator_params('x',nbins=20) #只调整x轴
    ax1.locator_params('y',nbins=20) #只调整y轴
    plt.axis([0,10,0,10]);

    PHv3DK.png

    1
    2
    #利用plt.xticks()设置x轴刻度顺序/旋转角度
    plt.xticks([0,2,3,1,4], ['Tom', 'Dick', 'Harry', 'Sally', 'Sue'], rotation=30);

    PHvH54.png

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #时间刻度调整
    import datetime
    import matplotlib as mpl

    start = datetime.datetime(2018,7,1)
    stop = datetime.datetime(2018,8,1)
    delta = datetime.timedelta(days=1)

    dates = mpl.dates.drange(start,stop,delta)
    y = np.random.rand(len(dates))

    fig2 = plt.figure()
    ax2 = fig2.add_subplot(111)
    ax2.plot_date(dates,y,linestyle='-',marker='')

    #日期格式调整,关键代码
    date_format= mpl.dates.DateFormatter('%Y-%m-%d')
    ax2.xaxis.set_major_formatter(date_format)
    fig2.autofmt_xdate();#防止刻度重叠

    PHxRoD.png

  • 双轴

    有时候想要在同一张图中显示两种不同范围的变量,这时候就要设置双轴

    双轴的关键代码为twinx()函数(也就是双胞胎x轴?)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    x = np.arange(1,11,0.1)
    y1 = x*x
    y2 = np.log(x)

    fig1 = plt.figure()
    ax1 = fig1.add_subplot(111)
    plt.ylabel('Y1')
    ax2 = ax1.twinx()#关键代码
    plt.ylabel('Y2',rotation=270)#注意添加ylabel的顺序不能错,旋转显示

    ax1.plot(x,y1)
    ax2.plot(x,y2,'--r');

    PbpYLt.png

标题与轴标题

标题与轴标题都是一幅可视化图像中的必须要素。你可以参考如下示例来设置你的标题与轴标题。

示例:

1
2
3
4
5
6
7
8
9
plt.title('This is title',color = 'r',fontsize = 17)
plt.xlabel('This is xlabel')
plt.ylabel('This is ylabel');

##其等效于:
# fig,ax = plt.subplots()
# ax.set_title('This is title',color = 'r',fontsize = 17)
# ax.set_xlabel('This is xlabel')
# ax.set_ylabel('This is xlabel');

PLvbp4.png

图例

图例在进行多变量比较的可视化中必不可少。你可以通过在plot()函数中添加参数’label’来对所绘曲线设置图例

1
2
3
4
5
6
7
x = np.arange(1,11,1)
fig = plt.figure()
ax = fig.add_subplot(111)
line1 = ax.plot(x,x*2,label='Bad')
line2 = ax.plot(x,x*3,label='Normal')
line3 = ax.plot(x,x*4,label='Good')
plt.legend(loc='best');

PLKnTU.png

也可以通过调用plt.legend()函数对图例进行设置。

1
2
3
4
5
6
7
8
x = np.arange(1,11,1)
fig = plt.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x,x*2) #注意line1后面的逗号,不可缺少
line2, = ax.plot(x,x*3)
line3, = ax.plot(x,x*4)

plt.legend(handles = [line1, line2, line3],labels = ['Bad', 'Normal', 'Good'],loc = 'best');

PLKmwT.png

颜色与样式

调用matplotlib.pyplot.plot函数即可设置所画图像的颜色与样式,设置方法如下:

1
plt.plot(x,y,'[color][marker][line]')
  • 常用颜色

    字符 颜色 字符 颜色
    b 蓝色 g 绿色
    r 红色 y 黄色
    c 青色 k 黑色
    m 洋红色 w 白色
    #rrggbb RGB颜色 0.7 灰度值
  • 常用线条样式

    字符 描述 字符 描述
    ‘-‘ 实线 ‘:’ 虚线(·······)
    ‘–’ 虚线(——) ‘None’或’ ‘或’’ 什么都不画
    ‘-.’ 点划线
  • 线条标记

    字符 描述 字符 描述
    ‘o’ 圆圈 ‘.’
    ‘D’ 菱形 ‘s’ 正方形
    ‘h’ 六边形1 ‘*’ 星号
    ‘H’ 六边形2 ‘d’ 小菱形
    ‘_’ 水平线 ‘v’ 一角朝下的三角形
    ‘8’ 八边形 ‘<’ 一角朝左的三角形
    ‘p’ 五边形 ‘>’ 一角朝右的三角形
    ‘,’ 像素 ‘^’ 一角朝上的三角形
    ‘+’ 加号 ‘\‘ 竖线
    ‘None’,’’,’ ‘ ‘x’ X

示例:

1
2
3
4
5
6
fig,ax = plt.subplots()

y=np.arange(1,5)
ax.plot(y,'cx--')
ax.plot(y+1,'kp:')
ax.plot(y+2,'mo-.');

PLZy3q.png

网格

也就是可视化图像中的网格,可以方便读者快速估取某点的横纵坐标。我们通过调用plt.grid()函数来对启用网格。一般情况下,使用该函数的默认参数即可

1
2
3
4
5
6
7
#采用默认参数
x= np.arange(1,10,0.1)
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.grid()
ax1.plot(x,np.log(x))
plt.show()

PLZWbF.png

但你也可以通过如下方式进行设置。

1
2
3
4
5
6
7
y = np.arange(1,5,0.1)
plt.plot(y,y**2)
plt.grid(color='r',linestyle=':',linewidth='2')
# color 设置网格的颜色(颜色与样式中的均可用)
# linestyle 设置线显示的类型(一共四种即'-','--','-.',':')
# linewidth 设置网格线宽
plt.show()

PLeToQ.png

添加图中注释

有时候你需要为可视化图中的某个关键点做出注释,方便读者能一眼看出,这时候你就需要调用plt.annote()函数来实现你的目的了。

该函数中几个关键的参数分别为:

  • str:一个字符串,来写出你想要标注的内容;

  • xy:标注点的坐标

  • xytext:标注内容起始位置的坐标(也就是从该点开始显示你的注释内容)

  • arrowprops:设置注释指向标注点的箭头

    • facecolor:箭头颜色
    • width:箭头宽度
    • headlength:箭头头部长度(单位为磅)
    • headwidth:箭头头部宽度

你也可以去搜索该函数,获取更多参数的设置方法。

示例:

1
2
3
4
5
6
7
8
x =np.arange(-10,11,1)
y = x*x

fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.plot(x,y)
ax1.annotate('this is minimum',xy=(0,0),xytext=(-1.5,20),
arrowprops=dict(facecolor='r',headlength=10));

PLMhVK.png

添加平行于坐标轴的线

你可能需要添加一条平行于x轴或者是y轴的线,在图像中分割不同区域。这时候,你就需要调用vlines(x, ymin, ymax)函数或者是hlines(y, xmin, xmax)函数,除了括号内的参数之外,你还可以设置颜色(color)参数和线型(linestyles)参数。(设置方法参考颜色与样式章节)

示例:

1
2
plt.vlines(0, 0, 0.5, colors = "c", linestyles = "--");
plt.hlines(0.25, -0.04, 0.04, colors = "r", linestyles = "-.");

PLvCyn.png

常用图形

可视化图形参考

如何能选择最适合的图形来表示你想分析的结果呢?这里提供一个简单的参考~

POERc6.md.jpg

散点图(scatter)

1
2
3
4
5
6
7
8
9
np.random.seed(7)#设置随机种子,可以保证每次的随机数是一致的

N = 50
x = np.random.rand(N)#生成50个0到1的随机数
y = np.random.rand(N)
colors = np.random.rand(N)
area = (30 * np.random.rand(N))**2 #随便设置的一个计算值,来表示大小

plt.scatter(x, y, s=area, c=colors, alpha=0.5);#用s设置大小区分,用c设置颜色区分

POEJts.png

条形图(bar)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#例1
#函数使用包
from matplotlib.ticker import FuncFormatter

x = np.arange(4)
money = [1.5e5, 2.5e6, 5.5e6, 2.0e7]

def millions(x, pos):
'''定义一个函数,将科学记数法转为以million为单位,保留一位小数,并添加美元$和单位M;
两个参数分别表示导入的值和位置。'''
return '$%.1fM' % (x * 1e-6)


formatter = FuncFormatter(millions)#调用函数,将millions函数作为模块化函数

fig, ax = plt.subplots()
ax.yaxis.set_major_formatter(formatter)#设置y轴按函数模块化
plt.bar(x, money)
plt.xticks(x, ('Bill', 'Fred', 'Mary', 'Sue'));

POV8KK.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#例2 横向柱形图

x = np.arange(4)
money = [1.5e5, 2.5e6, 5.5e6, 2.0e7]

def millions(x, pos):
'''定义一个函数,将科学记数法转为以million为单位,保留一位小数,并添加美元$和单位M;
两个参数分别表示导入的值和位置。'''
return '$%.1fM' % (x * 1e-6)


formatter = FuncFormatter(millions)#调用函数,将millions函数作为模块化函数

fig, ax = plt.subplots()
ax.xaxis.set_major_formatter(formatter)
plt.barh(x, money)#关键代码:barh
plt.yticks(x, ('Bill', 'Fred', 'Mary', 'Sue'));

POV4x0.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#例3 拼接柱状图
N = 5
menMeans = (20, 35, 30, 35, 27)
womenMeans = (25, 32, 34, 20, 25)
ind = np.arange(N) # 等效于[0,1,2,3,4]
width = 0.35 # 柱的宽度

p1 = plt.bar(ind, menMeans, width)
p2 = plt.bar(ind, womenMeans, width,bottom=menMeans) #关键代码:bottom

plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.xticks(ind, ('G1', 'G2', 'G3', 'G4', 'G5'))
plt.yticks(np.arange(0, 81, 10))
plt.legend((p1, p2), ('Men', 'Women'));

POZPde.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#例4 并列柱状图
N = 5
menMeans = (20, 35, 30, 35, 27)
womenMeans = (25, 32, 34, 20, 25)
ind = np.arange(N)
width = 0.35

p1 = plt.bar(ind-width/2, menMeans, width) #关键代码 -width/2,也就是将柱子向左移动了width/2
p2 = plt.bar(ind+width/2, womenMeans, width) #关键代码 +width/2

plt.ylabel('Scores')
plt.title('Scores by group and gender')
plt.xticks(ind, ('G1', 'G2', 'G3', 'G4', 'G5'))
plt.yticks(np.arange(0, 81, 10))
plt.legend((p1[0], p2[0]), ('Men', 'Women'));

POZKeS.png

直方图(hist)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fig = plt.figure()
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)
ax3 = fig.add_subplot(212)

mu = 100 #定义均值
sigma = 20 #定义标准差
x = mu +sigma * np.random.randn(2000) #生成一个标准正态分布函数

ax1.hist(x,bins=10,color='green',normed=True) #输入数据,bins=总共有几条条状图,color=颜色,normed=True:图形面积之和为1

ax2.hist(x,bins=50,color='red',normed=False) #normed=False:纵坐标显示实际值


x = np.random.randn(1000)+2
y = np.random.randn(1000)+3

ax3.hist2d(x,y,bins=10); #二维直方图

POZXTg.png

饼状图(pie)

1
2
3
4
5
6
7
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10] #占比
explode = (0, 0.1, 0, 0) #设置第二位也就是‘Hogs’凸显,间距为0.1

fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',shadow=True, startangle=90)#autopct对输出进行格式化,startangle为起始角度,一般设置为90比较好看
ax1.axis('equal');#保证为正圆

POnmsx.png

箱线图(box)

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
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

data = np.random.normal(size=1000, loc=0.0, scale=1.0)

ax1.boxplot(data,sym='o',whis=1.5)
# plt.boxplot(x, notch=None, sym=None, vert=None, whis=None, positions=None, widths=None, patch_artist=None, meanline=None, showmeans=None, showcaps=None, showbox=None, showfliers=None, boxprops=None, labels=None, flierprops=None, medianprops=None, meanprops=None, capprops=None, whiskerprops=None)
# x:指定要绘制箱线图的数据;
# notch:是否是凹口的形式展现箱线图,默认非凹口;
# sym:指定异常点的形状,默认为+号显示;
# vert:是否需要将箱线图垂直摆放,默认垂直摆放;
# whis:指定上下须与上下四分位的距离,默认为1.5倍的四分位差;
# positions:指定箱线图的位置,默认为[0,1,2…];
# widths:指定箱线图的宽度,默认为0.5;
# patch_artist:是否填充箱体的颜色;
# meanline:是否用线的形式表示均值,默认用点来表示;
# showmeans:是否显示均值,默认不显示;
# showcaps:是否显示箱线图顶端和末端的两条线,默认显示;
# showbox:是否显示箱线图的箱体,默认显示;
# showfliers:是否显示异常值,默认显示;
# boxprops:设置箱体的属性,如边框色,填充色等;
# labels:为箱线图添加标签,类似于图例的作用;
# filerprops:设置异常值的属性,如异常点的形状、大小、填充色等;
# medianprops:设置中位数的属性,如线的类型、粗细等;
# meanprops:设置均值的属性,如点的大小、颜色等;
# capprops:设置箱线图顶端和末端线条的属性,如颜色、粗细等;
# whiskerprops:设置须的属性,如颜色、粗细、线的类型等;
data = np.random.normal(size=(100, 4), loc=0.0, scale=1.0)

labels = ['A','B','C','D']

ax2.boxplot(data, labels=labels);

POnIfJ.png

散点直方图(scatter hist)

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

x = np.random.randn(200)
y = x + np.random.randn(200)*0.5

#定义坐标轴参数
margin_border = 0.1
width = 0.6
margin_between = 0.02
height = 0.2

#散点图参数
left_s = margin_border #距左边框距离
bottom_s = margin_border #距底部距离
height_s = width #散点图高度
width_s = width #散点图宽度

#顶部直方图参数
left_x = margin_border #距左边框距离
bottom_x = margin_border+width+margin_between #距底部距离 = 散点图距底部距离+散点图高度+散点图与直方图的间距
height_x = height #直方图高度
width_x = width #直方图宽度

left_y = margin_border+width+margin_between
bottom_y = margin_border
height_y = width
width_y = height

plt.figure(1,figsize=(8,8))
rect_s = [left_s,bottom_s,width_s,height_s]
rect_x = [left_x,bottom_x,width_x,height_x]
rect_y = [left_y,bottom_y,width_y,height_y]

# 开始按照定义的尺寸绘图
axScatter = plt.axes(rect_s)
axHisX = plt.axes(rect_x)
axHisY = plt.axes(rect_y)
axHisX.set_xticks([])#取消顶部直方图的x轴刻度显示
axHisY.set_yticks([])#取消右侧直方图的y轴刻度显示

#绘制散点图
axScatter.scatter(x,y)

#设定边界
bin_width = 0.25
xymax = np.max([np.max(np.fabs(x)),np.max(np.fabs(y))])#取出x与y中最大的绝对值
lim =int(xymax/bin_width+1) * bin_width
axScatter.set_xlim(-lim,lim)
axScatter.set_ylim(-lim,lim)

bins = np.arange(-lim,lim+bin_width,bin_width)

axHisX.hist(x,bins=bins)
axHisY.hist(y,bins=bins,orientation='horizontal')#水平作图

axHisX.set_xlim(axScatter.get_xlim())
axHisY.set_ylim(axScatter.get_ylim());

POmosP.png

其他

保存图像到本地

参考如下代码:

1
2
3
4
#保存至当下路径
fig.savefig('test.jpg');
#保存至其他路径
fig.savefig('E:/DAND/DAND_VIP/test.jpg');

显示中文

使用matplotlib做可视化不能显示中文,根本原因是因为官方配置中没有中文字体,所以,我们把中文字体添加进去就ok啦。具体方法如下:

1
2
#coding:utf-8
plt.rcParams['font.sans-serif']=['simhei']#simhei为‘黑体’

示例:

1
2
3
4
5
6
7
8
9
10
11
12
x = np.arange(1,11,1)

fig = plt.figure()
ax = fig.add_subplot(111)
line1 = ax.plot(x,-x*2,label='优')
line2 = ax.plot(x,-x*3,label='良')
line3 = ax.plot(x,-x*4,label='差')

plt.legend(loc='best')
plt.title('标题',color = 'r',fontsize = 17)
plt.xlabel('x轴',fontsize = 13)
plt.ylabel('-y轴',fontsize = 13);

POSpSe.png

坐标轴显示负号

有可能你做得可视化图像中,坐标轴的符号显示一个框框,这时候你添加如下设置即可。

1
plt.rcParams['axes.unicode_minus']=False

Pandas Plot

pandas plot函数是基于matplotlib的一个在pandas中快速绘图的方法,用法简单,而且兼容所有matplotlib属性设置的函数,所以,你可以用pandas plot函数来绘图,然后调用matplotlib中的函数对可视化图形进行设置,最终达到你心中的预期。

官方链接

pandas.DataFrame.plot

常用参数设置

  • data:你可以直接调取DataFrame作为参数输入
  • x:x轴数据
  • y:y轴数据
  • kind:绘图类型
    • line :折线图
    • bar :条形图
    • barh:水平条形图
    • hist:直方图
    • box:箱线图
    • kde:就是在条形图的基础上添加了概率密度曲线
    • area :相当于填充面积的折线图
    • pie:饼状图
    • scatter:散点图
    • hexbin:热度图

其余参数与matplotlib的参数设置类似,这里不再赘述。

总结

matplotlib是python可视化的鼻祖,绘图全面,多功能是他的优点,几乎没有他不能完成的可视化任务;

但是,他的缺点也很明显,比如:可视化图形配色丑;参数太多,设置琐碎;没有交互式。。。

所以针对这些问题,后人们又开发了许多python的可视化包,比如说:以美观、简洁著称的seaborn、做交互式的plotlypyecharts等等,后续我看时间允许的话,再出一些教程,大家也可以按需去官网学习,主要是看给出的示例,看关键代码,自己多总结。

项目相关

P3的项目需要你完完整整得过一遍数据分析的过程,所以呢,单独的某一个数据集肯定满足不了大家,贴心的Udacity给大家准备了几个数据集备选,戳数据集预览,挑一个自己感兴趣的先~

参考

matplotlib绘图基础