Python 和数据科学

Note

这里是 Scott 在学习数据科学所写的学习笔记,欢迎交流与指教。

目录:

入门篇

这一部分主要介绍数据科学的入门内容;包含数据科学的基础工具,如:Jupyter、Linux,以及 Python 基本的数据科学包 Numpy,画图包 Matplotlib;

Linux 基础

Date:2016-04-03

这一节记录下做数据处理时用到的一些 Linux 和 命令行技巧。大部分命令在 OS X 系统也适应。

为什么使用 Linux 和命令行

Have you ever noticed in the movies when the “super hacker,”— you know, the guy who can break into the ultra-secure military computer in under thirty seconds —sits down at the computer, he never touches a mouse? It’s because movie makers realize that we, as human beings, instinctively know the only way to really get anything done on a computer is by typing on a keyboard.

Most computer users today are only familiar with the graphical user interface (GUI) and have been taught by vendors and pundits that the command line interface (CLI) is a terrifying thing of the past. This is unfortunate, because a good command line interface is a marvelously expressive way of communicating with a computer in much the same way the written word is for human beings. It’s been said that “graphical user interfaces make easy tasks easy, while command line interfaces make difficult tasks possible” and this is still very true today.

—The Linux Command Line

Linux 安装和配置

如果没有任何编程及命令行基础,推荐使用 Ubuntu,有经验后可转 Debian,包多,稳定。进入系统,安装下 Anaconda[1],基本的 Python 环境 & 数据工具箱便有了。

再进入终端仿真器,0S X 自带 Terminal,但推荐用 iTerm 2,Debian 是 Konsole,配置下 终极Shell 环境 Oh My ZSH!

sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

如果提示你没有安装相关的依赖包,那么则需先安装相关依赖包,比如 Ubuntu 则需要想安装 Git、和 zsh 等,

sudo apt-get install git zsh

再装个查看数据、转换数据的小工具 csvkit,

sudo apt-get install csvkit

至此,便可开始数据科学之旅了。

基础命令

很多数据问题都可以用命令行解决,而且有些可以解决的非常高效,前提你熟悉一些基础的。 入门级命令,无非这些:

pwd #打印出当前工作目录名
cd #更改目录
ls #列出目录内容
ls #列出目录内容
file #确定文件类型
less #浏览文件内容
cp #复制文件和目录
mv #移动/重命名文件和目录
mkdir #创建目录
rm #删除文件和目录
ln #创建硬链接和符号链接

上面的 # 号代表注释,没有任何意义

入门级命令太简单了,就不介绍了,如果从来没碰过命令行,不熟悉使用可以查看帮助,如ls --help,另外我推荐些好书。

重定向和管道符

若你有仔细看过推荐书的任何一本,并做了些许练习,那么你的命令行已经入门了。在介绍命令行处理数据前,我想先谈谈重定向和管道符,若要给 Linux 的符号们举行「频繁使用」比赛,那他们必定是冠军。

平常你在终端里输入ls -l,结果应该类似这样:

➜  Dropbox ls -l
total 704
drwxr-xr-x@ 19 Scott  staff   646B Apr  3 10:27 A.HighlyEffectiveSelf
drwxr-xr-x@  5 Scott  staff   170B Apr  3 09:28 B.CreativePleasure
drwxr-xr-x@ 10 Scott  staff   340B Apr  3 09:10 C.TheArtOfWork
drwxr-xr-x@ 11 Scott  staff   374B Mar 10 12:40 D.HistoricalMemory
drwxr-xr-x@ 12 Scott  staff   408B Apr  3 10:09 E.DataBank
drwxr-xr-x@ 19 Scott  staff   646B Apr  3 09:14 F.BambooBasket
drwxr-xr-x@  5 Scott  staff   170B Mar  9 12:34 G.Other
-rw-r--r--@  1 Scott  staff     0B Apr  3 07:58 Icon?
-rw-rw-r--@  1 Scott  staff   312B Apr  3 16:18 README.md

文件是文件名排序的,若加个管道符 | 呢?

➜  Dropbox ls -l | sort
-rw-r--r--@  1 Scott  staff     0B Apr  3 07:58 Icon
-rw-rw-r--@  1 Scott  staff   312B Apr  3 16:18 README.md
drwxr-xr-x@  5 Scott  staff   170B Apr  3 09:28 B.CreativePleasure
drwxr-xr-x@  5 Scott  staff   170B Mar  9 12:34 G.Other
drwxr-xr-x@ 10 Scott  staff   340B Apr  3 09:10 C.TheArtOfWork
drwxr-xr-x@ 11 Scott  staff   374B Mar 10 12:40 D.HistoricalMemory
drwxr-xr-x@ 12 Scott  staff   408B Apr  3 10:09 E.DataBank
drwxr-xr-x@ 19 Scott  staff   646B Apr  3 09:14 F.BambooBasket
drwxr-xr-x@ 19 Scott  staff   646B Apr  3 10:27 A.HighlyEffectiveSelf
total 704

这里我加了 |sort 命令,你会发现,文件的排序已经变了,变成了文件大小的排序。这个命令和简单解释为ls -l输出了文件排序结果,而 sort 则接受了这个结果,并把它重新按文件的大小进行了排序,所以 | 就是管道的作用,可以从标准输入读取数据,然后再把数据输送到标准输出。这个特性非常有用,意味着你可以进行非常复杂的操作。

而什么是重定向‘>’呢?你用命令行操作的结果正常是直接显示在屏幕上的,那还有别的方式吗?你试试:

ls -l > ex01.txt

你发现,没有任何动静,但工作目录多了一个 ex01.txt 的文件,查看下这个文件试试,

➜  Dropbox cat ex01.txt
total 704
drwxr-xr-x@ 19 Scott  staff  646 Apr  3 10:27 A.HighlyEffectiveSelf
drwxr-xr-x@  5 Scott  staff  170 Apr  3 09:28 B.CreativePleasure
drwxr-xr-x@ 10 Scott  staff  340 Apr  3 09:10 C.TheArtOfWork
drwxr-xr-x@ 11 Scott  staff  374 Mar 10 12:40 D.HistoricalMemory
drwxr-xr-x@ 12 Scott  staff  408 Apr  3 10:09 E.DataBank
drwxr-xr-x@ 19 Scott  staff  646 Apr  3 09:14 F.BambooBasket
drwxr-xr-x@  5 Scott  staff  170 Mar  9 12:34 G.Other
-rw-r--r--@  1 Scott  staff    0 Apr  3 07:58 Icon
-rw-rw-r--@  1 Scott  staff  312 Apr  3 16:18 README.md
-rw-rw-r--   1 Scott  staff    0 Apr  3 16:57 ex01.txt

输出结果已经在这个文件里面了,这就是重定向的特性,允许我们来重定义标准输出送到哪里,在‘>’符号后面接个文件名即可。这点是非常实用的,比如你处理完数据后,肯定希望保存到一个文件里面。另外要注意一点,‘>’会格式化原有文件的内容,所以如果你是添加内容,请采用‘>>’。

处理数据常用命令
行过滤

若拿到一个很大的数据后,你肯定不想立马查看所有数据,一没必要,而打开慢,而是想做下行过滤,看看一小部分。常用的行过滤命令有head、tail、seq

看前10行数据:

➜  ~ head user_service_time.txt
bid service_time    weekday hour    lasttime
17283201    2016-1-27 8:30:00   3   8   3.0
17283201    2016-1-29 9:00:00   5   9   3.0
17283201    2016-2-22 17:00:00  1   17  3.0
17283201    2016-2-25 16:00:00  4   16  3.0
17283201    2016-2-29 16:30:00  1   16  3.0
17283201    2016-3-2 9:00:00    3   9   3.0
17283201    2014-9-19 9:00:07   5   9
17283201    2014-11-3 13:00:00  1   13
17283201    2014-11-22 15:00:00 6   15  3

查看前5行:

head -5 filename

前 n 行:

head -n filename

tail 则跟 head 刚好相反,查看的是尾行。若需要指定某些行则可用 sedawk,如指定 4-6行,可用sed -n '4, 6p' filename,我这里为了好看,用 nl 命令先把行号打印出来。

➜  ~ nl user_service_time.txt | sed -n '4, 6p'
     4  17283201    2016-2-22 17:00:00  1   17  3.0
     5  17283201    2016-2-25 16:00:00  4   16  3.0
     6  17283201    2016-2-29 16:30:00  1   16  3.0
# 查看奇数行
➜  ~ nl user_service_time.txt | head |  awk 'NR%2'
     1  bid service_time    weekday hour    lasttime
     3  17283201    2016-1-29 9:00:00   5   9   3.0
     5  17283201    2016-2-25 16:00:00  4   16  3.0
     7  17283201    2016-3-2 9:00:00    3   9   3.0
     9  17283201    2014-11-3 13:00:00  1   13
# 偶数行
➜  ~ nl user_service_time.txt | head |  awk '(NR+1)%2'
     2  17283201    2016-1-27 8:30:00   3   8   3.0
     4  17283201    2016-2-22 17:00:00  1   17  3.0
     6  17283201    2016-2-29 16:30:00  1   16  3.0
     8  17283201    2014-9-19 9:00:07   5   9
    10  17283201    2014-11-22 15:00:00 6   15  3
列提取

行提取很简单,那么列提取应该如何做呢?

# 把所有缩进符号改为逗号(英文), 再重定向成 csv 文件, .txt 文件可用 cat,excel 文件则需 in2csv
cat user_service_time.txt | tr '/t' ',' > user_service_time.csv

# 看看前 3 行,有哪些列
➜  ~ head -3 user_service_time.csv | csvlook
|-----------+--------------------+---------+------+-----------|
|  bid      | service_time       | weekday | hour | lasttime  |
|-----------+--------------------+---------+------+-----------|
|  17283201 |  2016-1-27 8:30:00 |  3      |  8   |  3.0      |
|  17283201 |  2016-1-29 9:00:00 |  5      |  9   |  3.0      |
|-----------+--------------------+---------+------+-----------|
# 得知总共有 5 列提取后 3 列 的前 10 行看看
➜  ~ < user_service_time.csv csvcut -c 3-5 | head | csvlook
|----------+------+-----------|
|  weekday | hour | lasttime  |
|----------+------+-----------|
|   3      |  8   |  3.0      |
|   5      |  9   |  3.0      |
|   1      |  17  |  3.0      |
|   4      |  16  |  3.0      |
|   1      |  16  |  3.0      |
|   3      |  9   |  3.0      |
|   5      |  9   |           |
|   1      |  13  |           |
|   6      |  15  |  3        |
|----------+------+-----------|
# 也可以用 -C 来忽略某些行,如忽略 3-5 列的前5行。
➜  ~ < user_service_time.csv csvcut -C 3-5 | head -5 | csvlook
|-----------+----------------------|
|  bid      | service_time         |
|-----------+----------------------|
|  17283201 |  2016-1-27 8:30:00   |
|  17283201 |  2016-1-29 9:00:00   |
|  17283201 |  2016-2-22 17:00:00  |
|  17283201 |  2016-2-25 16:00:00  |
|-----------+----------------------|
grep 查找
# 基本用法是 grep data filename
➜  ~ head user_service_time.txt | grep 29
17283201    2016-1-29 9:00:00   5   9   3.0
17283201    2016-2-29 16:30:00  1   16  3.0
wc 基本统计
  • 统计行数 wc -l file
  • 统计单词数 wc -w file
  • 统计字符数 wc -c file
➜  ~ wc -l user_service_time.txt
    1244 user_service_time.txt
➜  ~ < user_service_time.txt | grep 2016-2 | wc -l
      55
sort 排序
  • -n 按数字进行排序
  • -d 按字典序进行排序
  • -r 逆序排序
  • -k N 指定按第N列排序
# 以第 1 列数字反向排序
➜  ~ < user_service_time.csv | sort -nrk 1 | head -4 | csvlook
|-----------------+-------------------+---+---+----|
|  29101041557001 | 2016-3-6 8:30:00  | 7 | 8 | 4  |
|-----------------+-------------------+---+---+----|
|  29101041557001 | 2016-3-13 8:30:00 | 7 | 8 | 4  |
|  29101041557001 | 2016-2-28 8:30:00 | 7 | 8 | 4  |
|  29101041557001 | 2016-2-21 8:30:00 | 7 | 8 | 4  |
|-----------------+-------------------+---+---+----|
其他

iconv cut past uniq 等工具也是极好的,只不过用的略少,具体的数据分析则用 Pandas 更方便些。其他的,想到再添加。

Footnotes

[1]一个打包好 Python 科学计算常用包的平台工具,安装它,也就拥有了Python、NumPy、SciPy、Matplotlib、IPython、Jupyter 等。

Jupyter 的安装和使用

Date:2016-04-04
IPython 和 Jupyter

IPython 是一个 Python REPl shell,环境远比 Python 自带的强大,而 Jupyter Notebook 则是一个基于 IPython REPl 的 Web 应用,运行结果可保存为后缀.ipynb,交互性强,所见即所得,数据分析,写分析报告等的不二利器。

官方解释:

The Jupyter Notebook is a web application that allows you to create and share documents that contain live code, equations, visualizations and explanatory text. Uses include: data cleaning and transformation, numerical simulation, statistical modeling, machine learning and much more.
安装

如果有看过我上一篇文章 《用 Linux 处理数据》 ,并安装了 Anaconda,那么你已经有 Jupyter 了,打开终端,输入 jupyter notebook 即可。

远程使用

如果有远程使用的需求,则需把远程服务器配置下。

# 服务器下载 ssh 服务,如 Debian
sudo apt-get install openssh-server
# 不知道 ssh 是否打开,可以把他重启下
sudo service sshd restart

然后可以在局域网用其他电脑访问下,Mac 可直接在终端输入 ssh username@ip, 这里的 ip 指的局域网下的这台服务器的 ip,建议在路由器设置成静态 ip,若在外网使用,则需在路由器里面设置好端口转发。

然后参考官方教程 Running a notebook server 配置。

Attention

jupyter_notebook_config.py 这个文件里面 certfile 和 keyfile 的地址应为绝对地址.

一大串输入很麻烦,也易出错,建议打开 .zshrc,并在底部添加一行:

alias jn='jupyter notebook --certfile=/home/scott/.jupyter/mycert.pem --keyfile /home/scott/.jupyter/mykey.key'

这样到其他电脑键入:

jn

若能看到类似下方的输出,证明配置成功了。

[I 09:56:29.937 NotebookApp] The Jupyter Notebook is running at: https://[all ip addresses on your system]:8889/

我的端口配置的是 8889, 你也可以设置成其他的,再到路由器里配置下端口转发,大功告成。如果有用 R,也可用类似的方法配置下 RStudio Server,超简单。

快捷操作

Jupyter Notebook 的快捷键是一大亮点,如果有看过我这篇文章 《让 CapsLock 键更实用》[1] ,并对 Mac 或 Win 做了配置,那么你熟悉几个 Jupyter 的快捷,用 Jupyter 写报告之类基本上不需要鼠标了。

单元类型 (cell type)

Jupyter Notebook文档由一系列的单元 (cell) 组成,主要用的两类单元是:

  • markdown cell,命令模式下,按 m 可将单元切换为 markdown cell
  • code cell,命令模式下,按 y 可将单元切换为 code cell
常用快捷
  • 查看快捷键帮助: h
  • 保存: s
  • cell 间移动: j, k
  • 添加 cell: a, b
  • 删除 cell: dd
  • cell 编辑: x, c, v, z
  • 中断 kernel: ii
  • 重启 kernel: 00
  • 注释 code: Ctrl + /
拆分单元 (split cell)

编辑模式下按 control + shift + - 可拆分 c ell

查看对象信息
import numpy as np

tab 键查看提示信息

np.<tab>

查找 numpy 模块下,名称含有 cos 的对象

np.*cos*?

提供 numpy 模块的帮助信息

np?

提供 numpy 模块更详细的帮助信息

np??

查看 docstring

%pdoc np
魔术命令

最常用的是这个 %matplotlib inline,有点类似 ipython --pylab,画图用的;测试程序运行时间则只需把 %time 放在前面。

更多魔术命令可在 Jupyter Notebook 里键入:

%lsmagic
转换
# ipynb 文件转为 html
jupyter nbconvert --to html filename.ipynb

更多转换内容,请键入:

jupyter notebook --help

转换 rst、py、md 等格式都是非常方便的,但转 pdf,对中文的支持不好。必须先装 LaTex,LaTex 则需先把字体等调好。

Footnotes

[1]让键盘更高效的一篇文,昨天顺手把karabiner 配置的 gist 更新了。

数值计算(Numpy)

数组创建

数组的创建方式有很多,较便捷的方式有以下三种

直接创建

In [1]:
import numpy as np
In [2]:
a = np.array([1, 2, 3, 4, 5])
a
Out[2]:
array([1, 2, 3, 4, 5])

类 range

In [3]:
a = np.arange(10)
a
Out[3]:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [4]:
a = np.arange(1, 10, 2)
a
Out[4]:
array([1, 3, 5, 7, 9])

创建带尾巴的

In [5]:
a = np.linspace(0, 10, 2)
a
Out[5]:
array([  0.,  10.])

更多便捷创建函数

函数 功能
asarray 将输入转换为 ndarray,若输入本身是 ndarray 就不复制
ones、ones_like 根据指定形状和 dtype 创建一个全 1 数组
zeros、zeros_like 根据指定形状和 dtype 创建一个全 0 数组
empty、empty_like 创建新数组,但只分配内存空间不赋值
eye、identity 创建一个正方的N×N单位矩阵(对角线为1,其余为0
在 pandas 中尽量不要使用 np.empty(),这个函数创建的数组里面是有值的,除非你确定创建的这个数组能被完全赋值,否则后面运算起来很麻烦,这些“空值”的布尔类型是 True,而且 dropna() 方法删不掉。想创建空的 Series ,可以使用 Series(np.nan,index=???) 这样。
ndarray 对象属性

.reshape(shape) 改变数组维度

In [6]:
b = np.linspace(0, 7, 8)
b
Out[6]:
array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.])
In [7]:
b = np.linspace(0, 7, 8).reshape(2, 4)
b
Out[7]:
array([[ 0.,  1.,  2.,  3.],
       [ 4.,  5.,  6.,  7.]])
In [8]:
b = np.arange(0, 8).reshape(2, 2, 2)
b
Out[8]:
array([[[0, 1],
        [2, 3]],

       [[4, 5],
        [6, 7]]])

.astype(dtype) 改变数组格式

In [9]:
print b.dtype
b
int64
Out[9]:
array([[[0, 1],
        [2, 3]],

       [[4, 5],
        [6, 7]]])
In [10]:
b.astype(float)
Out[10]:
array([[[ 0.,  1.],
        [ 2.,  3.]],

       [[ 4.,  5.],
        [ 6.,  7.]]])

.transpose(*axes) 转置, transpose 的属性一直没搞懂

In [11]:
b = np.arange(8).reshape(2, 4)
b
Out[11]:
array([[0, 1, 2, 3],
       [4, 5, 6, 7]])
In [12]:
b.T
Out[12]:
array([[0, 4],
       [1, 5],
       [2, 6],
       [3, 7]])
In [13]:
b.transpose()
Out[13]:
array([[0, 4],
       [1, 5],
       [2, 6],
       [3, 7]])

.sort 排序

In [14]:
a = np.array([[1,4],[3,1]])
In [15]:
np.sort(a)                # sort along the last axis
Out[15]:
array([[1, 4],
       [1, 3]])
In [16]:
np.sort(a, axis=None)     # sort the flattened array
Out[16]:
array([1, 1, 3, 4])
In [17]:
np.sort(a, axis=0)        # sort along the first axis
Out[17]:
array([[1, 1],
       [3, 4]])

stats 基本统计

In [18]:
arr = np.arange(12).reshape(3,4)
In [19]:
arr
Out[19]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
In [20]:
arr.sum()
Out[20]:
66
In [21]:
np.sum(arr)
Out[21]:
66
In [22]:
arr.mean(0) # 列均值
Out[22]:
array([ 4.,  5.,  6.,  7.])
In [23]:
arr.mean(1) # 行均值
Out[23]:
array([ 1.5,  5.5,  9.5])

更多统计方法

sum 求和
mean 均值
std,var 标准差和方差
min,max 最小值和最大值
argmin,argmax 最小值和最大值的索引
cumsum 累积和
cumprod 累积积
数组间运算
In [24]:
a = np.arange(8).reshape(2, 4)
b = np.ones_like(a)
In [25]:
a + b
Out[25]:
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])
In [26]:
a * 2
Out[26]:
array([[ 0,  2,  4,  6],
       [ 8, 10, 12, 14]])
索引和切片

基本索引

In [27]:
foo = np.arange(10)
foo
Out[27]:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [28]:
bar = foo[:5].copy() # 若没有 copy,则 bar 的改变会影响 foo
In [29]:
bar
Out[29]:
array([0, 1, 2, 3, 4])
In [30]:
bar[:] = 1
In [31]:
bar
Out[31]:
array([1, 1, 1, 1, 1])
In [32]:
foo
Out[32]:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

二维和三维数组如何索引?

In [33]:
arr2d = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
arr2d
Out[33]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
In [34]:
arr2d[2, 0]
Out[34]:
7
In [35]:
arr3d = np.array([[[1, 2, 3],[4, 5, 6]],
                  [[7, 8, 9],[10, 11, 12]]])
In [36]:
arr3d[0]
Out[36]:
array([[1, 2, 3],
       [4, 5, 6]])
In [37]:
arr3d[0, 1, 2]
Out[37]:
6

切片 从第 0 轴开始的

In [38]:
arr2d
Out[38]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
In [39]:
arr2d.shape
Out[39]:
(3, 3)
In [40]:
arr2d[:1]
Out[40]:
array([[1, 2, 3]])
In [41]:
arr2d[1:4] # 理论上第0轴没有4这个基数
Out[41]:
array([[4, 5, 6],
       [7, 8, 9]])
In [42]:
arr2d[:2, :1]
Out[42]:
array([[1],
       [4]])

布尔型索引

In [43]:
from numpy.random import randn
data = randn(7, 4) # 生成 7*4 个均值为 0,标准差为 1 的数组
data
Out[43]:
array([[ 0.51659011, -0.14527543,  0.73750985, -0.07181445],
       [-0.26857463,  0.34883972,  0.07129706,  0.95455506],
       [ 0.43307006, -0.04072156, -1.32443926,  0.1124177 ],
       [ 1.39517115, -0.54127346, -0.70176892, -0.21847743],
       [ 2.69939163,  0.9403898 , -0.0578206 ,  0.50806596],
       [-0.41641312, -0.45169815,  0.31717456, -0.34085142],
       [ 0.44102963,  0.96447336, -2.92258682, -1.22429012]])
In [44]:
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'] )
names == 'Bob'
Out[44]:
array([ True, False, False,  True, False, False, False], dtype=bool)

当两个轴长度一致时,可以用布尔型的数组切片,比如此例切的是 axis 0

In [45]:
data[names == 'Bob']
Out[45]:
array([[ 0.51659011, -0.14527543,  0.73750985, -0.07181445],
       [ 1.39517115, -0.54127346, -0.70176892, -0.21847743]])
In [46]:
data[names == 'Bob', 2:]
Out[46]:
array([[ 0.73750985, -0.07181445],
       [-0.70176892, -0.21847743]])
In [47]:
data[~(names == 'Bob')]
Out[47]:
array([[-0.26857463,  0.34883972,  0.07129706,  0.95455506],
       [ 0.43307006, -0.04072156, -1.32443926,  0.1124177 ],
       [ 2.69939163,  0.9403898 , -0.0578206 ,  0.50806596],
       [-0.41641312, -0.45169815,  0.31717456, -0.34085142],
       [ 0.44102963,  0.96447336, -2.92258682, -1.22429012]])

布尔型数组求并集

In [48]:
mask = (names == "Bob") | (names == "Will")
mask
Out[48]:
array([ True, False,  True,  True,  True, False, False], dtype=bool)
In [49]:
data[mask]
Out[49]:
array([[ 0.51659011, -0.14527543,  0.73750985, -0.07181445],
       [ 0.43307006, -0.04072156, -1.32443926,  0.1124177 ],
       [ 1.39517115, -0.54127346, -0.70176892, -0.21847743],
       [ 2.69939163,  0.9403898 , -0.0578206 ,  0.50806596]])
利用数组做数据处理

将条件逻辑表述为数组运算, np.where 是一个极其有用的三元函数,它其实是一个条件运算函数,即 foo if cond else bar

In [50]:
xarr = np.arange(1.1, 1.6, 0.1)
In [51]:
xarr
Out[51]:
array([ 1.1,  1.2,  1.3,  1.4,  1.5])
In [52]:
yarr = np.arange(2.1, 2.6, 0.1)
In [53]:
yarr
Out[53]:
array([ 2.1,  2.2,  2.3,  2.4,  2.5])
In [54]:
cond = np.array([True, False, True, True, False])

根据 cond 的值选取 xarr 和 yarr 的值

In [55]:
result = [(x if c else y)
         for x, y, c in zip(xarr, yarr, cond)]
In [56]:
result
Out[56]:
[1.1000000000000001,
 2.2000000000000002,
 1.3000000000000003,
 1.4000000000000004,
 2.5000000000000004]

不够简洁,可用 where 改写

In [57]:
result = np.where(cond, xarr, yarr)
result
Out[57]:
array([ 1.1,  2.2,  1.3,  1.4,  2.5])

np.where 的第二个和第三个参数不必是数组,他们都是标量值

In [58]:
arr = randn(4,4)
arr
Out[58]:
array([[ 2.0086379 , -0.33799069,  0.48232499,  0.00343801],
       [-0.54010599,  1.63779772,  1.22284334, -1.34602676],
       [ 0.80309605, -0.82099082, -0.8703366 ,  0.20060704],
       [ 1.10812415, -0.01419402, -0.30237458,  1.30298964]])
In [59]:
np.where(arr > 0, 2, -2) # 正值设置为 2,负值设置为 -2
Out[59]:
array([[ 2, -2,  2,  2],
       [-2,  2,  2, -2],
       [ 2, -2, -2,  2],
       [ 2, -2, -2,  2]])

  └ 这个代码的意思其实就是 >0 则 2,else -2

其他通用函数

一元函数

函数名 功用
abs,fabs 整数、浮点、复数的绝对值,对于非复数,可用更快的 fabs
sqrt 平方根,等于 arr**0.5
square 平方,等于 arr**2
exp 以 e 为底的指数函数
log,log10,log2,log1p 以 e 为底的对数函数
sign 计算各元素的正负号,1(正),0(零),-1(负)
ceil 计算大于等于该值的最小整数
floor 计算小于等于该值的最大整数
rint round int,四舍五入到整数
modf 将数组的整数和小数部分以两个独立数组的形式返回
isnan 返回一个 “哪些值是 NaN” 的布尔型数组
isfinite,isinf 返回是否是有穷(无穷)的布尔型数组
cos,cosh,sin,sinh,tan,tanh 普通和双曲型三角函数
arccos,arccosh…等同上 反三角函数
logical_not 计算个元素 not x 的真值,等于 -arr
unique 计算元素唯一值并返回排序后的结果

二元函数

函数名 功用
add 加法,+
subtract 减法,-
multiply 乘法,*
divide,floor_divide 除法和地板除,/ 和 //
power 乘方,**
maximum,fmax 元素级最大值,fmax 将忽略 NaN
minimum,fmin 同上
mod 取模,%
copysign 将第二数组元素的符号复制给第一数组
greater(_equal),less(*equal),(not*) equal 字面意义,返回布尔数组
logical_and,logical_or,logical_xor 字面意义,返回布尔数组

数据绘图(Matplotlib)

In [1]:
%matplotlib inline
In [2]:
import matplotlib as mpl
import matplotlib.pyplot as plt
In [3]:
import numpy as np
Get started

画布和图型(Figure and Axis)

In [4]:
x = np.linspace(-5, 2, 100)
y1 = x**3 + 5*x**2 + 10
y2 = 3*x**2 + 10*x
y3 = 6*x + 10
y4 = x**2
In [5]:
len(x) # 100 个从-5 — 2 的数值
Out[5]:
100

最简单的创建办法是这样的

In [6]:
plt.plot(x, y1);
_images/beginning_04_matplotlib_9_0.png

plt.subplots 是一种简便的创建图表的办法,他会创建一个新的 Figure,并返回一个数组

In [7]:
fig,ax = plt.subplots(2, 3)
_images/beginning_04_matplotlib_11_0.png
In [8]:
x = np.linspace(-5, 2, 100)
y1 = x**3 + 5*x**2 + 10
y2 = 3*x**2 + 10*x
y3 = 6*x + 10
y4 = x**2
In [9]:
x1 = -3.33;
y5 = x1**3 + 5*x1**2 + 10;
print y5
28.518463
In [10]:
fig, ax = plt.subplots()
ax.plot(x, y1, color="blue", label="y(x)") # 定义x, y, 颜色,图例上显示的东西
ax.plot(x, y2, color="red", label="y'(x)")
ax.plot(x, y3, color="green", label="y''(x)")
ax.set_xlabel("x") # x标签
ax.set_ylabel("y") # y标签
ax.legend(); # 显示图例
_images/beginning_04_matplotlib_14_0.png

更复杂的例子

In [11]:
x = np.linspace(-5, 2, 100)
y1 = x**3 + 5*x**2 + 10
y2 = 3*x**2 + 10*x
y3 = 6*x + 10
y4 = x**2
In [12]:
fig, ax = plt.subplots(figsize=(8, 5)) # 定义画布和图形

ax.plot(x, y1, lw=1.5, color="blue", label=r"$y(x)$")
ax.plot(x, y2, lw=1.5, color="red", label=r"$y'(x)$")
ax.plot(x, y3, lw=1.5, color="green", label=r"$y''(x)$")

# 画线,画点,线是由点组成的,可以理解为多个点就组成了线
ax.plot(x, np.zeros_like(x), lw=0.5, color="black") # lw指的是粗细
ax.plot([-3.33, -3.33], [0, (-3.3)**3 + 5*(-3.3)**2 + 10], lw=0.5, ls="--", color="black")# 有时只要知道 x 就行了
ax.plot([0, 0],[0, 10], lw=0.5, ls="--", color="black") # 这个得把相交的点先求值才行
ax.plot([0], [10], lw=0.5, marker='h', color="blue")
ax.plot([-3.33], [(-3.3)**3 + 5*(-3.3)**2 + 10], lw=0.5, marker='o', color="blue")

ax.set_ylim(-15, 40) # 设定y轴上下限
ax.set_yticks([-10, 0, -5, 10, 20, 30])# 故意加一个 -5,有点违和感
ax.set_xticks([-4, -2, 0, 2])

ax.set_xlabel("$x$", fontsize=18) # 设定字体大小
ax.set_ylabel("$y$", fontsize=18)
ax.legend(loc=0, ncol=3, fontsize=14, frameon=False) # loc 等于自己找位置去,ncol 等于列,最后是不要框框
# plt.style.use('ggplot');
Out[12]:
<matplotlib.legend.Legend at 0x106545410>
_images/beginning_04_matplotlib_17_1.png
In [13]:
yticks = np.arange(-10, 40, 10)
In [14]:
yticks
Out[14]:
array([-10,   0,  10,  20,  30])
In [15]:
ax.legend??
In [16]:
fig = plt.figure(figsize=(8, 2.5), facecolor="#f1f1f1")

# axes coordinates as fractions of the canvas width and height
left, bottom, width, height = -0.1, -0.1, 0.8, 0.8 # 这一句没看懂,明天保存之后看看
ax = fig.add_axes((left, bottom, width, height), axisbg="#e1e1e1")
x = np.linspace(-2, 2, 1000)
y1 = np.cos(40 * x)
y2 = np.exp(-x**2)

ax.plot(x, y1 * y2)
ax.plot(x, y2, 'g')
ax.plot(x, -y2, 'g')

ax.set_xlabel("x")
ax.set_ylabel("y")
Out[16]:
<matplotlib.text.Text at 0x1061f0e90>
_images/beginning_04_matplotlib_21_1.png
In [17]:
fig, ax = plt.subplots(nrows=3, ncols=2)
_images/beginning_04_matplotlib_22_0.png
In [18]:
plt.Axes.bar??

例子 4-7:

In [19]:
x = np.linspace(-5, 5, 5)
y = np.ones_like(x)
In [20]:
x
Out[20]:
array([-5. , -2.5,  0. ,  2.5,  5. ])
In [21]:
y
Out[21]:
array([ 1.,  1.,  1.,  1.,  1.])
In [22]:
def axes_settings(fig, ax, title, ymax):
    ax.set_xticks([]) #??
    ax.set_yticks([])
    ax.set_ylim(0, ymax+1)
    ax.set_title(title)
In [23]:
fig, axes = plt.subplots(1, 4, figsize = (16, 3))
_images/beginning_04_matplotlib_29_0.png

下面两行没还没想清楚

In [ ]:
**??**
x = np.linspace(-5, 5, 5)
y = np.ones_like(x)

def axes_settings(fig, ax, title, ymax):
    ax.set_xticks({}) #??
    ax.set_yticks([])
    ax.set_ylim(0, ymax+1)
    ax.set_title(title)

fig, axes = plt.subplots(1, 4, figsize = (16, 3))

linewidths = [0.5, 1.0, 2.0, 4.0]
for n, linewidth in enumerate(linewidths):
    axes[0].plot(x, y + n, color="blue", linewidth=linewidth)
axes_settings(fig, axes[0], "linewidth", len(linewidths))
In [24]:
# ??
linestyles = ['-', '-.',":"]
for n, linestyle in enumerate(linestyles):
    axes[1].plot(x, y + n, color="")
Plot types
In [25]:
fignum = 0

def hide_labels(fig, ax): # 隐藏 Labels,如图例,x/y 的属性等
    global fignum    # ??
    ax.set_xticks([]) # 无 x 轴刻度
    ax.set_yticks([]) # 无 y 轴刻度
    ax.xaxis.set_ticks_position('none') # 无刻度杠
    ax.yaxis.set_ticks_position('none')
    ax.axis('tight')

    fignum += 1
In [26]:
x = np.linspace(-3, 3, 25)
x
Out[26]:
array([-3.  , -2.75, -2.5 , -2.25, -2.  , -1.75, -1.5 , -1.25, -1.  ,
       -0.75, -0.5 , -0.25,  0.  ,  0.25,  0.5 ,  0.75,  1.  ,  1.25,
        1.5 ,  1.75,  2.  ,  2.25,  2.5 ,  2.75,  3.  ])
In [27]:
p = np.arange(-3, 3, 0.25)
p
Out[27]:
array([-3.  , -2.75, -2.5 , -2.25, -2.  , -1.75, -1.5 , -1.25, -1.  ,
       -0.75, -0.5 , -0.25,  0.  ,  0.25,  0.5 ,  0.75,  1.  ,  1.25,
        1.5 ,  1.75,  2.  ,  2.25,  2.5 ,  2.75])
In [28]:
y1 = x**3 + 3*x**2 + 10
y2 = -1.5*x**3 + 10*x**2 - 15
y3 = x**3
In [29]:
fig, ax = plt.subplots(figsize=(4, 3))
ax.plot(x, y1) # plot 是线图
ax.plot(x, y2)
ax.plot(x, y3)
hide_labels(fig, ax)
_images/beginning_04_matplotlib_38_0.png
In [30]:
fig, ax = plt.subplots(figsize=(4, 3))
ax.step(x, y1) # step 是阶梯图
ax.step(x, y2)
# ax.step(x, y3) # 加一条会自己生成红色
hide_labels(fig, ax)
_images/beginning_04_matplotlib_39_0.png
In [31]:
fig, ax = plt.subplots(figsize=(4, 3))
width = 6/50.0 # width 是宽度,0.12 是 x 间隔的一半
ax.bar(x - width/2, y1, width=width, color="blue") # bar 柱型图,主要分析离散数据
ax.bar(x + width/2, y2, width=width, color="green")
hide_labels(fig, ax)  # 没加这条图会变的很小
_images/beginning_04_matplotlib_40_0.png
In [32]:
width
Out[32]:
0.12
In [33]:
6/50 # 没加.0,自然就没有浮点数了
Out[33]:
0
In [34]:
fig, ax = plt.subplots(figsize=(4, 3))
ax.fill_between(x, y1, y2, y3, color="green") # 中间为何是空的,不太明白

hide_labels(fig, ax)
_images/beginning_04_matplotlib_43_0.png
In [35]:
fig, ax = plt.subplots(figsize=(4, 3))
ax.hist(y2, bins=30)
ax.hist(y1,bins=30) # 判断的是连续变量,打成了30组

hide_labels(fig, ax)
_images/beginning_04_matplotlib_44_0.png
In [36]:
fig, ax = plt.subplots(figsize=(4, 3))

ax.errorbar(x, y2, yerr=y1, fmt="o-") # errorbar 应该是误差棒的意思,点的上下线

hide_labels(fig, ax)
_images/beginning_04_matplotlib_45_0.png
In [37]:
fig, ax = plt.subplots(figsize=(4, 3))

ax.stem(x, y2, 'b', markerfmt='bs') # r,是代表颜色,markerfmt 是形状
ax.stem(x, y1, "r", markerfmt='ro') # 这种图主要把x的高度标出来

hide_labels(fig, ax)
_images/beginning_04_matplotlib_46_0.png
In [38]:
ax.stem??
In [39]:
fig, ax = plt.subplots(figsize=(4, 3))

x = np.linspace(0, 5, 50)
ax.scatter(x, -1 + x + 0.25 * x**2 + 2 * np.random.rand(len(x)))
ax.scatter(x, np.sqrt(x) + 2 * np.random.rand(len(x)), color='green') # sqrt是什么含义??

hide_labels(fig, ax)
_images/beginning_04_matplotlib_48_0.png
Advanced Features
In [40]:
fig, ax = plt.subplots(figsize=(8, 4))

x = np.linspace(-20, 20, 100)
y = np.sin(x) / x

ax.plot(x, y)

ax.set_ylabel("y label")
ax.set_xlabel("x label")

for label in ax.get_xticklabels() + ax.get_yticklabels(): # get到标度,后循环set
    label.set_rotation(45)  # 然后旋转45度
_images/beginning_04_matplotlib_50_0.png
Axes
In [41]:
fig, axes = plt.subplots(ncols=2, nrows=3) # 生成一个 2*3 的图形画布, 为何这里不能用 ax

_images/beginning_04_matplotlib_52_0.png

data1

In [42]:
fig, axes = plt.subplots(1, 2, figsize=(8, 3.5), sharey=True)  # sharey 则是代表是否同用一个 y 轴

data1 = np.random.randn(200, 2) * np.array([3, 1]) #产生两列符合标准正太分布的100组数据,做了一个广播,第一列乘以3,第二列乘以1,把标准差扩大了
#area2 = (np.random.randn(200) + 0.5) * 100

data2 = np.random.randn(200, 2) * np.array([1, 3]) #data1 是在x的方向扩大了变异度,data2是在y的方向
# area2 = (np.random.randn(200) + 0.5) * 100

# 第一列当作x,第二列当作y,marker是形状,size 是大小,alpha 是透明度
axes[0].scatter(data1[:,0], data1[:,1], color="green", marker="s", s=30, alpha=0.5) # alpha 是大小的意思,上限是1
axes[0].scatter(data2[:,0], data2[:,1], color="blue", marker="o", s=30, alpha=0.5) # 加了另外一组数据之后,由于刻度的变化整个图形也有所变化

axes[1].hist([data1[:,1], data2[:,1]], bins=15, color=["green", "blue"], alpha=0.5, orientation='horizontal');# []是代表有两组图
_images/beginning_04_matplotlib_54_0.png
legends 调节图例
In [43]:
fig, axes = plt.subplots(1, 4, figsize=(16,4))

x = np.linspace(0, 1, 100)

for n in range(4):
    axes[n].plot(x, x, label="y(x) = x" )
    axes[n].plot(x, x + x**2, label="y(x) = x + x**2")
    axes[n].legend(loc=n+1) # 一行把所有的图例都加上了,for 循环的魅力,如果没有+1,则变成 0,0,1,2
    axes[n].set_title("legend(loc=%d)" % (n+1)) # 原来格式化字符还可以这么玩

## ??理解下n=1,2,3,4 时有什么区别
_images/beginning_04_matplotlib_56_0.png
Advanced grid layout
inset
In [44]:
fig = plt.figure(figsize=(8, 4))

def f(x):
    return 1/(1 + x**2) + 0.1/(1 + ((3 -x)/0.1)**2)

def plot_and_format_axes(ax, x, f, fontsize): ## ?? 定义里面的那张图,x,尺寸
    ax.plot(x, f(x),linewidth=2)
    ax.xaxis.set_major_locator(mpl.ticker.MaxNLocator(5))
    ax.yaxis.set_major_locator(mpl.ticker.MaxNLocator(4))
    ax.set_xlabel(r"$x$", fontsize=fontsize)
    ax.set_ylabel(r"$f(x)$", fontsize=fontsize)

# main graph 主要的图
ax = fig.add_axes([0.1, 0.15, 0.8, 0.8], axisbg="#f5f5f5")
x = np.linspace(-4, 14, 10000) #
plot_and_format_axes(ax, x, f, 18)

# inset
x0, x1 = 2.5, 3.5 # 小图x的上下界
ax = fig.add_axes([0.5, 0.5, 0.38, 0.42], axisbg="none") #这条是定义4个角的位置 axisbg 是??是没有颜色的意思吗?
x = np.linspace(x0, x1, 1000)
plot_and_format_axes(ax, x, f, 14)

# ?? 理解下那个小块具体是怎么画出来的
_images/beginning_04_matplotlib_59_0.png
In [45]:
ncols, nrows = 3, 3

fig, axes = plt.subplots(nrows, ncols)

for m in range(nrows):
    for n in range(ncols):
        axes[m, n].set_xticks([]) # 所有的x轴标度干掉,
        axes[m, n].set_yticks([])
        axes[m, n].text(0.5, 0.5, "axes[%d, %d]" % (m, n),
                       horizontalalignment='center') # ??那个长的我都不想输的单词是说放图里码?
_images/beginning_04_matplotlib_60_0.png
In [46]:
fig, axes = plt.subplots(2, 2, figsize=(6, 6), sharex=True, sharey=True, squeeze=False) # squeeze 可以 y 轴隐藏,yb'ig

x1 = np.random.randn(100) # 生成一维的100个数组
x2 = np.random.randn(100)

axes[0, 0].set_title("Uncorrelated")
axes[0, 0].scatter(x1, x2)

axes[0, 1].set_title("Weakly positively correlated")
axes[0, 1].plot(x1, x1 + x2)

axes[1, 0].set_title("Weakly negatively correlated")
axes[1, 0].scatter(x1, -x1 + x2) # 负相关

axes[1, 1].set_title("Strongly correlated")
axes[1, 1].scatter(x1, x1 + 0.15 * x2) # 减少x2 的分量,强相关了

axes[1, 1].set_xlabel("x")
axes[1, 0].set_ylabel("y")
axes[0, 0].set_ylabel("y")
axes[1, 0].set_xlabel("x")
Out[46]:
<matplotlib.text.Text at 0x1060d0510>
_images/beginning_04_matplotlib_61_1.png

查看 Matplotlib 的 style

In [47]:
print plt.style.available
[u'seaborn-darkgrid', u'seaborn-notebook', u'classic', u'seaborn-ticks', u'grayscale', u'bmh', u'seaborn-talk', u'dark_background', u'ggplot', u'fivethirtyeight', u'seaborn-colorblind', u'seaborn-deep', u'seaborn-whitegrid', u'seaborn-bright', u'seaborn-poster', u'seaborn-muted', u'seaborn-paper', u'seaborn-white', u'seaborn-pastel', u'seaborn-dark', u'seaborn-dark-palette']

数据绘图(Seaborn)

基础篇

这一部分介绍数据科学的基础内容;

数据操作(Pandas)

pandas 对象

引入 pandas 等包,DataFrame、Series 属于常用的,所以直接引入

In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pandas import Series, DataFrame

DataFrame 对象:Pandas DataFrame 是一个表格型的数据结构,有行索引也有列索引

In [2]:
from IPython.display import Image
Image(filename='../../image/DataFrame.png', width=400)
Out[2]:
_images/base_01_pandas_5_0.png

Series 对象:类似于一维数组的对象,由一组同样 type 的数组和索引组成

In [3]:
s1 = Series(range(0,4)) # -> 0, 1, 2, 3
s2 = Series(range(1,5)) # -> 1, 2, 3, 4
s3 = s1 + s2 # -> 1, 3, 5, 7
s4 = Series(['a','b'])*3 # -> 'aaa','bbb'

index 对象:即 Series 和 DataFrame 的索引

In [4]:
# 获取索引
df = DataFrame(s1)
idx = s1.index
idx = df.columns # the column index
idx = df.index # the row index
In [5]:
# 索引的一些特性
b = idx.is_monotonic_decreasing
b = idx.is_monotonic_increasing
b = idx.has_duplicates
i = idx.nlevels # multi-level indexe
In [6]:
# 索引的一些方法
a = idx.values # get as numpy array
l = idx.tolist() # get as a python list
# idx = idx.astype(dtype) # change data type
# b = idx.equals(other) # check for equality 看看是否是相同的索引
In [7]:
# union of two indexes 合并两个索引
# idx = idx.union(other)

idx1 = pd.Index([1, 2, 3, 4])
idx2 = pd.Index([3, 4, 5, 6])
idx1.union(idx2)
Out[7]:
Int64Index([1, 2, 3, 4, 5, 6], dtype='int64')
In [8]:
i = idx.nunique() # number unique labels
label = idx.min() # minimum label
label = idx.max() # maximum label

创建 Series 和 DataFrame

http://pandas.pydata.org/pandas-docs/stable/dsintro.html

DataFrame 入门
In [2]:
df = DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])

DataFrame 的一些实用查看方法

In [10]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 4 columns):
A    10 non-null float64
B    10 non-null float64
C    10 non-null float64
D    10 non-null float64
dtypes: float64(4)
memory usage: 392.0 bytes
In [11]:
n=4
dfh = df.head(n) # 看前 n 行
In [12]:
dft = df.tail(n) # 看后 n 行
In [13]:
dfs = df.describe() # 各类统计信息
In [14]:
top_left_corner_df = df.iloc[:5, :5]
In [15]:
dfT = df.T # transpose rows and cols

DataFrame index 的一些特性

In [16]:
l = df.axes # list row and col indexes
l
Out[16]:
[RangeIndex(start=0, stop=10, step=1),
 Index([u'A', u'B', u'C', u'D'], dtype='object')]
In [17]:
(r, c) = df.axes # from above
In [18]:
s = df.dtypes # Series column data types
s
Out[18]:
A    float64
B    float64
C    float64
D    float64
dtype: object
In [19]:
b = df.empty # True for empty DataFrame
b
Out[19]:
False
In [20]:
i = df.ndim # number of axes (2)
i
Out[20]:
2
In [21]:
t = df.shape # (row-count, column-count)
t
Out[21]:
(10, 4)
In [22]:
(r, c) = df.shape # from above
(r, c)
Out[22]:
(10, 4)
In [23]:
i = df.size # row-count * column-count
i
Out[23]:
40
In [24]:
a = df.values # get a numpy array for df

实用方法

In [27]:
df = DataFrame([1, 23, 3, 5, 2])
In [28]:
dfc = df.copy() # copy a DataFrame
dfr = df.rank() # rank each col (default) 把每个值的地位列出了
dfs = df.sort() # sort each col (default)
# dfc = df.astype(dtype) # type conversion
/Users/Scott/Library/anaconda2/lib/python2.7/site-packages/ipykernel/__main__.py:3: FutureWarning: sort(....) is deprecated, use sort_index(.....)
  app.launch_new_instance()
In [29]:
# 下面的两个方法没怎么搞懂
df.iteritems()# (col-index, Series) pairs
df.iterrows() # (row-index, Series) pairs
# example ... iterating over columns
for (name, series) in df.iteritems():
    print('Col name: ' + str(name))
    print('First value: ' +
        str(series.iat[0]) + '\n')
Col name: 0
First value: 1

通用函数

method ##
df = df.abs() absolute values
df = df.add(o) add df, Series or value
s = df.count() non NA/null values
df = df.cummax() (cols default axis)
df = df.cummin() (cols default axis)
df = df.cumsum() (cols default axis)
df = df.cumprod() (cols default axis)
df = df.diff() 1st diff (col def axis)
df = df.div(o) div by df, Series, value
df = df.dot(o) matrix dot product
s = df.max() max of axis (col def)
s = df.mean() mean (col default axis)
s = df.median() median (col default)
s = df.min() min of axis (col def)
df = df.mul(o) mul by df Series val
s = df.sum() sum axis (cols default)
DataFrame Columns 列处理

column 其实也是一个 Series

In [2]:
df = DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])
idx = df.columns # get col index
label = df.columns[0] # 1st col label
lst = df.columns.tolist() # get as a list
In [31]:
lst
Out[31]:
['A', 'B', 'C', 'D']
In [32]:
label
Out[32]:
'A'
In [33]:
idx
Out[33]:
Index([u'A', u'B', u'C', u'D'], dtype='object')

column 改名

In [34]:
# df.rename(columns={'old':'new'}, inplace=True)
# df = df.rename(columns={'a':1,'b':'x'})

选择 columns, 也就是提取列

In [ ]:
s = df['C'] # select col to Series
df = df[['C']] # select col to df
df = df[['A','B']] # select 2 or more
df = df[['C', 'B', 'A']]# change order 改变排序了
s = df[df.columns[0]] # select by number
f = df[df.columns[[0, 3, 4]] # by number
s = df.pop('C') # get col & drop from df == df['C']

python 特性提取列

In [4]:
s = df.A # same as s = df['A'],
# 但不能用 python 特性创建新的 columns
# df['new_col'] = df.a / df.b

添加新的 columns,添加一个 column 是极为方便的,只要能添加一组数据就行

In [6]:
df['new_col'] = range(len(df))
df['new_col'] = np.repeat(np.nan,len(df))
df['random'] = np.random.rand(len(df))
df['index_as_col'] = df.index
In [8]:
df.head(2)
Out[8]:
A B C D new_col random index_as_col
0 0.458326 -1.402187 0.446208 -0.459079 NaN 0.920599 0
1 0.366833 0.618661 -0.727332 1.152775 NaN 0.503750 1

详情参考 df1[[‘b’,’c’]] = df2[[‘e’,’f’]] df3 = df1.append(other=df2)

判定函数 pd.Series.where

In [17]:
# 符合 >0 条件的保持原值,其他 =0
df['A'] = df['A'].where(df['A']>0, other=0)
# df['d']=df['a'].where(df.b!=0,other=df.c)

数据格式 转换一列的格式时非常有用。

s = df[‘col’].astype(str) # Series dtype na = df[‘col’].values # numpy array pl = df[‘col’].tolist() # python list

columns 的一些特性和方法

value = df[‘col’].dtype # type of data value = df[‘col’].size # col dimensions value = df[‘col’].count()# non-NA count value = df[‘col’].sum() value = df[‘col’].prod() value = df[‘col’].min() value = df[‘col’].max() value = df[‘col’].mean() value = df[‘col’].median() value = df[‘col’].cov(df[‘col2’]) s = df[‘col’].describe() s = df[‘col’].value_counts()

找出最小值和最大值的位置

In [33]:
df['B'].idxmax()
df['B'].idxmin()
Out[33]:
7

元素级方法

s = df[‘col’].isnull() s = df[‘col’].notnull() # not isnull() s = df[‘col’].astype(float) s = df[‘col’].round(decimals=0) s = df[‘col’].diff(periods=1) s = df[‘col’].shift(periods=1) s = df[‘col’].to_datetime() s = df[‘col’].fillna(0) # replace NaN w 0 s = df[‘col’].cumsum() s = df[‘col’].cumprod() s = df[‘col’].pct_change(periods=4) s = df[‘col’].rolling_sum(periods=4, window=4)

In [42]:
df = df.mul(s, axis=0) # on matched rows,相当于 * other Series 每行都与之相乘
In [47]:
df.columns.get_loc('B')
Out[47]:
0
In [ ]:
df = df.iloc[:, 0:2] # exclusive

获取 columns 的具体位置

In [153]:
df
Out[153]:
year state pop debt
one 2000 Ohino 1.5 NaN
two 2001 Ohino 1.7 NaN
three 2002 Ohino 3.6 NaN
four 2001 Nevada 2.4 NaN
five 2002 Nevada 2.9 NaN

下面那个好像没什么软用

In [167]:
for i in ['pop', 'state']:
    print df.columns.get_loc(i)
2
1
In [152]:
Series(df.columns)
Out[152]:
0     year
1    state
2      pop
3     debt
dtype: object
DataFrame rows 行处理

获取索引和标签

In [3]:
idx = df.index # get row index
label = df.index[0] # 1st row label
lst = df.index.tolist() # get as a list

改变索引或行名

In [ ]:
df.index = idx # new ad hoc index
df.index = range(len(df)) # set with list
df = df.reset_index() # replace old w new
# note: old index stored as a col in df
df = df.reindex(index=range(len(df)))
df = df.set_index(keys=['r1','r2','etc'])
df.rename(index={'old':'new'},inplace=True)

添加行

待补。

Drop row 删除行

df = df.drop(‘row_label’) df = df.drop(row1) # multi-row df = df.drop([‘row1’,’row2’]) # multi-row

查找一些行

In [23]:
# fake up some data
data = {1:[1,2,3], 2:[4,1,9], 3:[1,8,27]}
df = pd.DataFrame(data)
In [4]:
# multi-column isin
lf = {1:[1, 3], 3:[8, 27]} # look for
f = df[df[list(lf)].isin(lf).all(axis=1)] # 这里看不太懂

对行做排序

In [ ]:
df_obj.sort(columns = ‘’)#按列名进行排序
df_obj.sort_index(by=[‘’,’’])#多列排序,使用时报该函数已过时,请用sort_values
df_obj.sort_values(by=['',''])同上

索引前奏

In [122]:
df0 = DataFrame({'x': [1, 2, 3], 'y': [3, 4, 5]}, index=[3, 2, 1])
df1 = DataFrame([[1, 2, 3,], [3, 4, 5], [6, 7, 8]], index=[3, 2, 1])
In [118]:
df0
Out[118]:
x y
3 1 3
2 2 4
1 3 5
In [120]:
df0[1:2]
Out[120]:
x y
2 2 4
In [17]:
df1
Out[17]:
0 1 2
3 1 2 3
2 3 4 5
1 6 7 8
In [18]:
df1[0]
Out[18]:
3    1
2    3
1    6
Name: 0, dtype: int64
In [19]:
df1[0:2]
Out[19]:
0 1 2
3 1 2 3
2 3 4 5
In [21]:
df1.ix[:, 0:2]
Out[21]:
0 1 2
3 1 2 3
2 3 4 5
1 6 7 8
In [124]:
df0[['x','y']]
Out[124]:
x y
3 1 3
2 2 4
1 3 5
索引和切片

整数时一般是不包含的,非整数则会包含尾巴(基于 label)

In [41]:
foo = DataFrame([4.5, 7.2, -5.3, 3.6], index=['a', 'b', 'c', 'd'])
bar = DataFrame([4.5, 7.2, -5.3, 3.6], index=range(4))
In [100]:
print(foo)
print '------'
print(bar)
     0
a  4.5
b  7.2
c -5.3
d  3.6
------
     0
0  4.5
1  7.2
2 -5.3
3  3.6
In [99]:
print foo[:2]
print '------'
print bar[:2]
print '------'
print foo[:'c']
     0
a  4.5
b  7.2
------
     0
0  4.5
1  7.2
------
     0
a  4.5
b  7.2
c -5.3

ix[::, ::] 可以接受两套切片(axis=0)横向,(axis=1)列向

In [2]:
data = {'state':['Ohino','Ohino','Ohino','Nevada','Nevada'],
        'year':[2000,2001,2002,2001,2002],
        'pop':[1.5,1.7,3.6,2.4,2.9]}

df = DataFrame(data,index=['one','two','three','four','five'],
               columns=['year','state','pop','debt'])
In [48]:
df
Out[48]:
year state pop debt
one 2000 Ohino 1.5 NaN
two 2001 Ohino 1.7 NaN
three 2002 Ohino 3.6 NaN
four 2001 Nevada 2.4 NaN
five 2002 Nevada 2.9 NaN
In [81]:
df.ix[:, 'state':'pop']
Out[81]:
state pop
one Ohino 1.5
two Ohino 1.7
three Ohino 3.6
four Nevada 2.4
five Nevada 2.9
In [84]:
df.ix[1] # 切的是行,所以说 ix 默认切的行, 也就是 axis=0
Out[84]:
year      2001
state    Ohino
pop        1.7
debt       NaN
Name: two, dtype: object

非 ix

ix 可以说是 pandas 的标准切法,而没有 ix 时,情况就略复杂些了,作者说:

  • 索引时,选取的是列
  • 切片时,选取的是行

记住一点,如果你想看单列或少数列的索引,那么直接用 df[‘column’], 其他就

In [6]:
print(type(df['year']))
print(type(df[['year']]))
<class 'pandas.core.series.Series'>
<class 'pandas.core.frame.DataFrame'>
In [128]:
# df['one'] # 会报错,没办法这样索引,这是行
df[['year', 'state']] # 可运行
Out[128]:
year state
one 2000 Ohino
two 2001 Ohino
three 2002 Ohino
four 2001 Nevada
five 2002 Nevada
In [91]:
df[0:1] # 切第一行,直接 df[0] 是会报错的。而 ix 不会。
Out[91]:
year state pop debt
one 2000 Ohino 1.5 NaN
In [129]:
df['one':'two'] # 所以他也是可以整数切,也能标签切
Out[129]:
year state pop debt
one 2000 Ohino 1.5 NaN
two 2001 Ohino 1.7 NaN
In [89]:
print(df.columns.tolist())
print(df.index.tolist())
['year', 'state', 'pop', 'debt']
['one', 'two', 'three', 'four', 'five']
In [102]:
df.loc[:, 'year':'state']
Out[102]:
year state
one 2000 Ohino
two 2001 Ohino
three 2002 Ohino
four 2001 Nevada
five 2002 Nevada
In [104]:
df.iloc[:, 1:2]
Out[104]:
state
one Ohino
two Ohino
three Ohino
four Nevada
five Nevada
  • .loc[label] 这是严格基于标签的索引
  • .iloc[inte] 这是严格基于整数位置的索引
  • .ix[] 更像是这两种严格方式的智能整合版。
In [111]:
# df.loc[1:2] 用 label 的去切整数,自然会出错
# df.iloc['two':'three'] 也会出错
In [109]:
df.loc['two':'three']
Out[109]:
year state pop debt
two 2001 Ohino 1.7 NaN
three 2002 Ohino 3.6 NaN
In [105]:
df.iloc[1:2]
Out[105]:
year state pop debt
two 2001 Ohino 1.7 NaN

小结:

  • 尽量写两套切片,除非是索引单列则用 df[column]
  • 多用 ilocloc, 除非你很清晰的基于标签
In [ ]:
# 待补:当标签和整数冲突时
In [ ]:
df2.info() # 说明,ix在这种非整数的整数标签上,他的切片跟loc一样,是基于标签的,而另外两个刚好相反。

概率和统计分析(StatsModels)

数值计算(Scipy)

线性模型(StatsModels)

机器学习初步(SKlearn)

工具篇

这篇是 Python 数据科学方面的书、好资源、好用工具等;