Resive world

Come world to Record life


  • Home

  • Tags

  • Categories

  • Archives

  • Sitemap

  • Search

逻辑回归算法

Posted on 2016-01-28 | In Machine Learning

说到逻辑回归(Logistic Regression),其实他解决的并不是回归问题(Regression),而是分类问题(Classification)。分类问题都明白了,他和一般的回归问题的差别其实也就在于一个值域是连续的,而另一个值域是离散的,

Sigmoid函数

我们都知道分类问题需要解决的问题是给你一个分好类的训练集,然后给你一个数据让你判断这个数据属于哪一类。严格来说这是一个离散的问题,然而我们一般能够处理的都应该是连续可导的函数。而连续可导的线性函数一般都不能非常好的体现出离散的特征。这时候我们就需要一个特殊的函数来近似的处理离散的分类问题,这就引入了我们著名的逻辑函数(Logistic Function),又称Sigmoid函数:$$S(t)=\frac{1}{1+e^{-\theta t}}$$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
from matplotlib.pylab import *

x=np.linspace(-5,5,100)
y=1/(1+np.exp(-x))
plot(x,y,color='blue', linewidth=2.5,label='$S(t)=\\\\frac{1}{1+e^{-t}}$')
y=1/(1+np.exp(-2*x))
plot(x,y,color='green', linewidth=2.5,label='$S(t)=\\\\frac{1}{1+e^{-2t}}$')
y=1/(1+np.exp(-4*x))
plot(x,y,color='yellow', linewidth=2.5,label='$S(t)=\\\\frac{1}{1+e^{-4t}}$')
y=1/(1+np.exp(-8*x))
plot(x,y,color='red', linewidth=2.5,label='$S(t)=\\\\frac{1}{1+e^{-8t}}$')
legend(loc='upper left')
show()

我们可以看到随着$t$的值逐渐远离原点,函数值迅速的向0或者1无限逼近,非常好的模拟了一个离散的效果,而且随着\theta值的增大,逼近的趋势也更加明显。这就很好的满足了我们的要求。

有了这个函数,我们就可以试着用他来拟合一些分类的问题。为了简单起见,我们先讨论二值分类的问题。

决策边界(Decision Boundary)

使用了逻辑函数作为拟合函数后,我们就可以写出我们的预测函数了:$$h_\theta(x)=S(\theta^Tx)$$S函数里面的其实就是一个线性方程,很明显,这个线性方程大于0的时候,输出的结果就是1,小于0的时候输出的结果就是0。也就是说,这个线性方程的解就是我们做出决策的边界了。

当然,这个边界完全可以不用是线性方程。比如,我们完全可以通过构造一些高阶的参数来使决策边界呈现一个圆:
$$\theta^Tx=\theta_0+\theta_1x_1^2+\theta_2x_2^2$$

由此,理论上我们就可以构造任何形状的决策边界来拟合各种各样的分类问题。

代价函数(Cost Function)

在之前介绍线性回归的函数时,我们在比较预测的函数和数据集的匹配程度的时候用到了$\frac12 (h_\theta(x_i)-y_i)^2$这个东西。这个其实就是一个代价函数或者叫损失函数(Loss Function)(具体一点,这其实叫做平方损失函数),即相似程度越不好,那么这个使用这个函数的代价就越大,就越不建议使用他。于是我们完全可以用这个函数作为比较拟合程度的依据,而后对数据集中的所有数据的代价求和,就是我们总的代价,也就是之前的J函数。

综上,我们可以先定义线性回归中的Cost Function:
$$Cost(h_\theta(x),y)=\frac12(h_\theta(x)-y)^2$$

与之前不同,对于逻辑回归,现在我们的$h(x)$不再是一个线性方程了。很明显,对这个函数如果用平方损失函数来算的话,对后续的求导求和等运算会带来极大的不便。而且更重要的是,他并不是一个下凸函数,所以甚至不能用GD算法求极值。因此我们将他的Cost Function定义为下式:
$$
Cost(h_\theta(x),y)=\left\{\begin{aligned}-log(h_\theta(x))\ if\ y=1&\\-log(1-h_\theta(x))\ if\ y=0 & \end{aligned}\right.
$$

当然,如果想把分类函数合并下也可以得到下面的形式:
$$Cost(h_\theta(x),y)=-ylog(h_\theta(x))-(1-y)log(1-h_\theta(x))$$

对于这个方程,我们要看到,当$h_\theta(x)$与$y$相差很大的时候,他的代价甚至可以趋近去正无穷!而且,这个函数可以非常方便的求导数,也可以非常方便的对$\theta$求偏导。这样的代价方程以后也会经常用到,他又叫对数损失函数。

梯度下降

有了损失函数,我们就可以构造用于梯度下降的J函数了。实际上就是对每一个代价求和就行了:
$$J(\theta)=\frac{1}{m}\underset{i=1}{\overset{m}{\Sigma}}Cost(h_\theta(x_i),y_i)$$

进而,我们对J函数中每一个\theta求偏导,可以得到下面的梯度下降算法:

repeat until convergence:

$$\begin{aligned}\theta_j&:=\theta_j-\alpha\frac{\partial}{\partial\theta_j}J(\theta)\\&:=\theta_j-\alpha \underset{i=1}{\overset{m}{\Sigma}}(h_\theta(x_i)-y_i)x_{i,j}\\\end{aligned}$$
simultaneously update all $\theta_j$

这里有$h_\theta(x)=\frac{1}{1+e^{-\theta^Tx}}$,而$x_i$对应的是每一组数据构成的列向量,$x_{i,j}$表示第i组数据的第j个值。

没错,最终的表达式跟线性回归的计算方法几乎一模一样(注意少了一个分母上的m)!这就是Sigmoid函数的强大之处。

优化算法

对于逻辑回归算法,有一些高级的优化算法比如Conjugate gradient、BFGS、L-BFGS等,这些跑起来快,但是难学。。。这里就不提了。

多元分类问题

有了二元的分类问题,很自然我们就会想到多元的分类问题。对于多元的分类问题,我们的处理方法其实很朴素,就是把一个n元的分类问题转化为n个二元的分类问题,又叫”One-vs-All“。意思已经很清楚了,照着二元的分类问题弄n次就好了。

多变量线性回归算法

Posted on 2016-01-27 | In Machine Learning

其实所谓的多变量的线性回归(Linear Regression with multiple variables )本质上将与单变量的线性回归没啥差别。因此我们完全可以用上一节中的梯度下降算法来解决,只需要在每一次迭代的时候多考虑几个变量而已。所以这一节就稍微介绍一下了,不再用例子分析。不过毕竟多了一些变量,在对多变量跑梯度下降算法时,显然对参数的调节就更加重要了,因此我们首先得学会一些参数调节的技巧。这些技巧在实际的操作过程中尤为重要。

调节参数

特征值缩放(Feature Scaling)

我们知道在进行梯度下降算法时,经常会有这样一个问题,就是如果两个特征变量$x_i$和$x_j$的范围差别很大,那么每一次迭代时,他们下降的相对速率就不一样,这就直接导致了范围大的那个变量下降的过慢。为了解决这个问题,我们引入了特征值缩放这个技巧。其实也很简单,就是把每一个参数的变化范围大概控制在一起,这样他们的下降速率就不会受到相互的牵连。具体的操作就是将他所有参数的值,都缩放在大小差不多的一个区域内(通常是(-1,1))。为了进行这样的缩放,我们就需要接下来的方法。

标准化(Mean Normalization)

为了缩放到一个区域((-1,1))内,我们要做两件事:第一,把平均值对应到0点;第二,把最大最小值对应到-1和1这两点。想想也很好理解,用公式表示就是:
$$x_i:=\frac{x_i-u}{2\sigma}$$

这里的$x_i$表示需要标准化的数据,$u$表示在数据集中这种参数的平均值,$\sigma$表示数据集中这种参数的标准差。看着很眼瘦?没错,这个就是我们求正态分布的那个标准化转换函数。
经过这样的转换,每一个变量都会将他的值缩放到(-1,1)中了,进而方便我们进行梯度下降。

学习因子$\alpha$的选取

我们知道学习因子既不能过大也不能过小。实际上,对于一个学习因子是好是坏我们可以这样判断。对于一个特定的学习因子$\alpha$,我们可以画出J函数与迭代次数的关系图。对于一个好的$\alpha$,他的函数图像应该是一个类似$y=\frac1x$的图像。如果J函数下降的速度过慢,显然我们需要增加学习因子使他下降的更快;如果J函数是增函数,或者在某些区间内有上升的趋势,那么显然我们需要减小学习因子防止学习过度。

多项式回归(Polynomial Regression )

对于某些不能用线性回归的问题,我们有时候可以试着用多项式来进行回归拟合。其实多项式回归完全可以看成是多变量的线性回归问题,因为我们完全可以把其中的$x^i$看成是第$i$个独立的变量,只不过他的值是由$x$推出来的而已。原理很简单,但是如果想不到那就头大了0.0。

公式法(Normal equation)

介绍

对于多变量的线性回归,除了用我们之前学的GD算法,我们其实还有另外一个直接套公式的算法(卧槽早说)。这牵涉到线性代数的知识,我们需要做的只是将数据集组合成几个矩阵,然后运算一个公式即可,这个公式就叫 Normal equation (觉得叫成“正规方程”好难听):
$$\theta=(X^TX)^{-1}X^Ty$$

其实这个方法就是矩阵最小二乘法了。

其中$X^T$表示$X$的转置,$X^{-1}$表示$X$的逆。

这个公式,得到的结果就是对整个数据集最好的线性逼近。下面介绍下这个公式怎么用。

用法

假设我们的数据集有m个数据,我们的变量有n个(即每一个数据有n个特征值),那么我们可以把所有的输入数据写成一个m*(n+1)的矩阵。为什么是n+1列,因为我们知道,对n个参数的回归需要用到n+1个$\theta$。只是这当中的$\theta_0$一直取1罢了。因此这个矩阵的第一列全部都是1。

上面的这个矩阵,就是我们公式中的X了。

对于公式中的$y$,其实是由所有的输出数据组成的列向量,与输入一一对应。

最后,我们只需要计算上面这个公式的结果就能计算出$\theta$向量的值了,(很明显这个向量应该是一个n+1维的列向量)

至于这个公式的证明。。。貌似很麻烦,百度normal equation 可以找到需要的证明过程。

说明

这里有一个问题,就是如果$X^TX$没有逆元怎么办?

事实上正常情况下是不会没有逆元的,没有逆元的情况一般有两种:

1、参数中有线性相关的两组量。比如一个参数是用厘米表示的高度,另一个参数是用米表示的同样的那个高度。显然,这样选择参数是没有意义的,对于这种情况我们只要删掉其中一个参数就好了。

2、数据集的数量m小于参数的个数n。通常情况下当然是不会发生这种事的,毕竟都没几个数据还怎么好意思来拟合?不过万一出现这种状况,也是有对应的办法的,这种情况以后再说。

性能

我们注意到这里需要求矩阵的逆,而$X^TX$是一个n*n的矩阵,因此他的复杂度通常至少是$O(n^3)$(虽然可以优化,但是也差不多这么大)。这在n比较小的时候效果还挺不错的,而且比GD算法更加方便准确。但是当参数的个数变多了的时候,效率就会特别慢,相比之下GD算法的优势就显现出来了。

实现

接下来我就结合上一节的例子试着实现一下,虽然是单变量,但是道理是一样的。

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
import numpy as np
import theano.tensor as T
from pylab import *
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

#read file

file=open("data","r")
brain=[]
body=[]
for line in file:
num,_brain,_body=line.split()
brain.append(_brain)
body.append(_body)

#calculate
size=len(brain)
X=np.matrix(np.vstack((np.ones(size),brain))).reshape(2,size).T.astype(np.float)
Y=np.matrix(body).T.astype(np.float)
out=(X.T*X).I*X.T*Y
print out

#draw
out=np.array(out)
px=np.linspace(-100,600,100)
py=px*out[1]+out[0]

plt.plot(px,py)
plt.scatter(brain,body,s=100,alpha=.5)
plt.xlim(-100,600)
plt.ylim(-200,1400)
plt.show()

(这里写代码的时候要非常注意np.matrix的用法以及强制指定数据类型)

最后算得:$\theta_0=55.95185719,\theta_1=1.24271276$,从图上看还是拟合的挺不错的。

批量梯度下降算法

Posted on 2016-01-26 | In Machine Learning

这一讲介绍了我们的第一个机器学习算法,”批量“梯度下降算法(Batch Gradiant Descent)。注意到他在前面加了个“批量(Batch)”,这其实是为了与以后的另一种梯度下降算法进行区分从而体现出这个算法的特点。

线性回归

梯度下降算法这是用来解决所谓的“线性回归”问题。线性回归应该都懂了,这里大概的进行下定义(以单变量为例):

1、给你一个数据集(Training Set),数据集中有很多个数对,表示$(x_i,y_i)$。

2、你的任务是构造一个预测函数$h_\theta(x)=\theta_0+\theta_1x$,使得这个函数对于任意给定的$x$,能很好的预测出他对应的$y$。

3、为了判断预测函数的准确性,我们引入一个费用方程:
$$J(\theta_0,\theta_1)=\frac{1}{2m} \underset{i=1}{\overset{m}{\Sigma}}(h(x_i)-y_i)^2$$
这里的m表示数据集中数据的个数,x和y表示每一个数据。很明显这里用的是最常见的求平方差的二次误差函数,不过这里多引入了一个$\frac{1}{2}$,其实没有别的意思,只是为了后面求导的时候方便约掉他,从而使求导后的式子更好看。

4、我们的目标就是找到$\theta_0,\theta_1$使得J函数取最小值。

一个具体的数据

为了更加直观的表现,我在people.sc.fsu.edu 上找到了一些线性回归的数据集,用了其中的第一个来展示(去掉了一些夸张的数据):

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
 1     3.385    44.500
2 0.480 15.500
3 1.350 8.100
4 465.000 423.000
5 36.330 119.500
6 27.660 115.000
7 14.830 98.200
8 1.040 5.500
9 4.190 58.000
10 0.425 6.400
11 0.101 4.000
12 0.920 5.700
13 1.000 6.600
14 0.005 0.140
15 0.060 1.000
16 3.500 10.800
17 2.000 12.300
18 1.700 6.300
19 4.235 50.400
20 0.023 0.300
21 187.100 419.000
22 521.000 655.000
23 0.785 3.500
24 10.000 115.000
25 3.300 25.600
26 0.200 5.000
27 1.410 17.500
28 529.000 680.000
29 207.000 406.000
30 85.000 325.000
31 0.750 12.300
32 62.000 1320.000
33 0.104 2.500
34 3.500 3.900
35 6.800 179.000
36 35.000 56.000
37 4.050 17.000
38 0.120 1.000
39 0.023 0.400
40 0.010 0.250
41 1.400 12.500
42 250.000 490.000
43 2.500 12.100
44 55.500 175.000
45 100.000 157.000
46 52.160 440.000
47 10.550 179.500
48 0.550 2.400
49 60.000 81.000
50 3.600 21.000
51 4.288 39.200
52 0.280 1.900
53 0.075 1.200
54 0.122 3.000
55 0.048 0.330
56 192.000 180.000
57 3.000 25.000
58 160.000 169.000
59 0.900 2.600
60 1.620 11.400

第一列是编号,第二列表示人脑的重量,第三列表示人身体的重量,我们用matplotlib画个图来看看:

绘图代码

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np
import theano.tensor as T
import matplotlib.pyplot as plt
file=open("data","r")
brain=[]
body=[]
for line in file:
num,_brain,_body=line.split()
brain.append(_brain)
body.append(_body)
plt.scatter(brain,body,s=100,alpha=.5)
plt.show()

ok,接下来我们就是找出符合条件的$\theta_0,\theta_1$了。

J函数

根据J函数的表达式,我们可以很容易的求出他的具体的表达式。当然,我们也可以很容易的画出他的函数图像。很明显,他的图像应该是一个三维图像(当然,如果因变量不止一个的话,得到的应该是更高维度的图像):

绘图代码

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
import numpy as np
import theano.tensor as T
from pylab import *
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

#read file

file=open("data","r")
brain=[]
body=[]
for line in file:
num,_brain,_body=line.split()
brain.append(_brain)
body.append(_body)

brain=np.array(brain).astype(float)
body=np.array(brain).astype(float)

#calculate p
def p(t0,t1):
sum=0
num=len(brain)
for i in range(0,num):
sum+=pow((t0+t1*brain[i]-body[i]),2)
sum/=2*num
return sum

#important values

size=20
X=np.linspace(-100,100,size)
Y=np.linspace(0,2,size)

#draw the picture
X,Y=np.meshgrid(X,Y)

X=X.reshape(size*size)
Y=Y.reshape(size*size)

Z=np.arange(0,size*size)
for i in range(0,size*size):
Z[i]=p(X[i],Y[i])
X=X.reshape(size,size)
Y=Y.reshape(size,size)
Z=Z.reshape(size,size)

fig=figure()
ax=Axes3D(fig)
ax.plot_surface(X,Y,Z,rstride=1,cstride=1,cmap=plt.cm.hot)
ax.contourf(X, Y, Z, zdir='z', offset=-2 )
plt.show()

(画图时注意设置图像的各部分参数使他的表现效果最好,语法不熟,写的蠢了)

从图中大概也能看到他的最低点啦,$\theta_0$大概是0±50,$\theta_1$大概是1±0.5(纯属目测)。

梯度下降

有了直观的感受我们就来看看对J求梯度下降的具体意义了。其实也很好理解,就是对于J函数上的某一个点,每一次迭代时都将他沿下降最快的方向走一小段距离(所谓方向,当然是要分到各个变量上面了)。这样经过一段时间,他就会接近图像的最低点了。用数学表达式来理解就是:

repeat until convergence:

$$\begin{aligned}\theta_j&:=\theta_j-\alpha\frac{\partial}{\partial\theta_j}J(\theta_0,\theta_1)\\&:=\theta_j-\frac{\alpha}{m}\underset{i=1}{\overset{m}{\Sigma}}(h(x_i)-y_i)x_i\\&(for\ j=0\ and\ j=1)\end{aligned}$$

上式兼容了多元变量的情况,事实上在本例中$x_0$显然是1,$x_1$就是数据中的x。

这里的$:=$是为了强调这是赋值操作而不是判等。

要注意的是,每一次迭代都要将每一个方向计算一次,而且要注意赋值的顺序,$\theta_j$一定要在迭代最后同时(simultaneously)用新值代替。

这里的$\alpha$又被称为”学习因子(learning rate)“,在迭代的时候要注意这个值的选取。形象的看其实就是每次下降迈的步子的大小。如果过大则会导致跨越了最低点甚至导致越走越远,如果过小则会导致迭代代价太高,运行缓慢。

当然,理论上这个算法也只能求得局部最低点,并不能保证是全局最低点。

根据这个公式,我们注意到每一次迭代都得将所有的数据用一遍,这导致了效率的低下。所以由于这个算法又被称为批量梯度下降算法(BGD)。

简单实现

参考代码

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
import numpy as np
import theano.tensor as T
from pylab import *
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

#read file

file=open("data","r")
brain=[]
body=[]
for line in file:
num,_brain,_body=line.split()
brain.append(_brain)
body.append(_body)

brain=np.array(brain).astype(float)
body=np.array(brain).astype(float)

def partial_t0(a,t0,t1):
sum=0
num=len(brain)
for i in range(0,num):
sum+=(t0+t1*brain[i]-body[i])
return t0-sum*a/num

def partial_t1(a,t0,t1):
sum=0
num=len(brain)
for i in range(0,num):
sum+=(t0+t1*brain[i]-body[i])*brain[i]
return t1-sum*a/num

print("%-6s%20s%20s%20s" %('alpha','theta0','theta1','times'))
for i in range(1,11):
a=pow(10,-i)
t0=0
t1=0
dt0=10000000
dt1=10000000
cnt=0
while abs(t0-dt0)+abs(t1-dt1)>0.0001:
dt0=t0
dt1=t1
t0=partial_t0(a,dt0,dt1)
t1=partial_t1(a,dt0,dt1)
cnt+=1
print("%-6s%20s%20s%20s" %(a,t0,t1,cnt))

输出

1
2
3
4
5
6
7
8
9
10
11
alpha               theta0              theta1               times
0.1 -inf nan 96
0.01 inf nan 139
0.001 inf nan 255
0.0001 0.00310245521884 0.999954444466 26
1e-05 0.00310682944277 0.999536382475 42
1e-06 0.00309052228147 0.994195497596 305
1e-07 0.00292431336052 0.940626826916 1685
1e-08 0.00125884490338 0.40488187492 3099
1e-09 5.20663166667e-08 1.67458362859e-05 1
1e-10 5.20663166667e-09 1.67458362859e-06 1

代码比较简单,就不展开了。这次我把迭代起点选在(0,0)。需要注意的是这个结果,在$\alpha$取不同值的时候,输出的结果和性能的表现也大不相同。

1、由于我是用变化前后的差别来判断聚合程度的,所以当学习因子过小的时候会出现一次迭代就终止了,这显然不是我们想看到的结果;

2、同时,当学习因子过大的时候,会出现函数发散的现象,这显然也不是我们想要的结果;

3、在能得到正确解的学习因子里,程序的运行速度也随着因子的减小而减慢,但是准确程度也因而增加。

所以学习因子的选择至关重要。

因此最终的拟合结果就是。。。。莫急,让我们换一个迭代起点看看,这次我们选(2,2)为迭代起点(将t0和t1分别改成2),这次得到的结果是:

1
2
3
4
5
6
7
8
9
10
11
alpha               theta0              theta1               times
0.1 inf nan 96
0.01 -inf nan 139
0.001 -inf nan 255
0.0001 1.18929235272 0.9963020556 6183
1e-05 1.99615299339 0.994173518979 43
1e-06 1.99637710179 0.999525819249 306
1e-07 1.99677269246 1.05302607963 1690
1e-08 1.99866893391 1.58880170812 3137
1e-09 1.99999994593 1.99998315003 1
1e-10 1.99999999459 1.999998315 1

卧槽,傻眼了,结果与上一个差别还是很大的,那么到底哪一个才更准确呢~~~额,,其实我也不晓得,只能说以现在的知识并不知道怎样很好的解决这个问题。我想应该是因为基于我电脑的速度,我的阈值设置的不够小,导致无论从哪个起点开始迭代最终到达的应该是一个离最优解附近的一个类圆形区域里,无法深入到内部。有一个解决方案大概就是遍历最内部的这个区域来求解吧,不过设置参数应该也是挺麻烦的,复杂度也挺大的…

最后,画一下拟合的结果(取上面提到的所有合理的值):

(怎么和想象中差别有点大。。。)

机器学习笔记引言

Posted on 2016-01-25 | In Machine Learning

写在开头的

从今天起就要开始认真的学习Machine Learning了。在网上查找了很多的资料,也大概看了下deeplearning.net上的一些教程。但是既没有一丝的学习基础,也没有过硬的python编程能力,而且英语阅读水平也跟不上,学起来真是相当的吃力。最后觉得刚上手的话还是跟着入门级的视频教程学比较好。搜索对比下来还是Andrew Ng的视频适合我这种基础差的人看,一方面学习门槛低,一方面又能学到不错的技术,更重要的是学习资源充足。在网上找到了中国海洋大学的黄同学整理翻译的Andrew Ng 2014年最新的视频和课件(重要的是有翻译。。),终于能够好好学学了。

(分享视频以及课件下载地址:mooc学院)。

关于Andrew Ng

话说学ML的应该没人不知道Andrew Ng 吧,毕竟也是业界数的过来的大牛。他其实是一个美籍华人,中文名叫吴恩达,是斯坦福大学的副教授,主攻人工智能和机器学习,最近更是被百度挖过来担任首席科学家,主导百度大脑的深度学习工作(他之前也参加了更加厉害的谷歌大脑的研发工作),被誉为”百度请来的最强外援“。

他也是现在相当知名的mooc网站coursera的创始人之一,自己作为斯坦福大学的讲师也将自己教授的课程发布在了网上供全世界所有的人学习。从这点上来讲,他还是很值得尊重的。

什么是机器学习

其实业内对这个还没有一个统一的定义,一个挺规范的定义来自卡耐基梅隆大学的Tom Mitchell,他给机器学习定义为:

一个程序经过经验E(Experience)的学习之后,被用来解决任务T(Task),他的性能表现P(Performance)能够随着经验的增加而提高,这样的过程就是机器学习。
就像是一个通过学习来优化的下棋算法,经过大量与人的对弈学习后(经验E),当他再次与人对弈时(任务T),他的胜率(表现P)会有所提高。

这个定义还是很泛的,但也是很好理解的,这说明机器学习离我们真的非常的近,最典型的就是网站的推荐准确性啊,垃圾邮件的区分啊,还有就是根据表征进行的疾病诊断啊。。。这些东西里面都与机器学习有着很重要的关系。

总的来讲,机器学习分为两大类,即监督学习和无监督学习。

监督学习(Supervised Learning)

回归问题(Regression)

监督学习的一个基本问题大概就是:给你一个由大量自变量与其对应的函数的数据集供你学习,现在给你一个新的自变量,问你他函数的最大期望值是什么。说白了也就是函数的拟合回归问题。比较简单而典型的就是我们熟知的线性回归,这也算是一种机器学习。不过现实生活中的变量可不仅仅是单变量这么简单,这里的变量通常会有很多维度甚至是无限维;对应的关系也不会只是线性关系这么简单。

分类问题(Classification)

监督学习的另一个基本问题大概就是:给你一些数据集以及其中每一个数据对应的分类供你学习,现在给你一个新的数据,问你他最可能属于哪一个分类。也就是常说的分类了。比如给你一堆临床数据,它告诉你哪些疾病会有哪些表现,那些特征;现在给你一个特定病人的临床症状,问你他的患的是哪一种病的。当然,现实中特征这种东西也是几乎是有无限多个的。

回归问题与分类问题的实质差别是,回归问题是需要你给出一个连续的输出;而分类问题是要你给出一个离散的结果。

无监督学习(Unsupervised Learning)

无监督学习,和监督学习不同(废话),他接受一组数据集,数据集中的每个元素都有很多的特征,但是并没有任何的标签表示哪个数据属于哪一类。经过这些数据的学习,他能给出哪些数据和哪些数据是可以划分为同一类的(即给数据打上标签),就像是“物以类聚”一样,所以又叫“聚类算法”(Clustering Algorithm)。比如百度的新闻爬虫,他爬下了茫茫多的网页,却能自动的将新闻分为各种类别,这就是托聚类算法的福。无监督学习还广泛应用到了DNA的解读上,这一点应该也很好理解。

python读取mnist数据集

Posted on 2016-01-25 | In Machine Learning

在看deeplearning教程的时候遇到了这么个玩意,mnist,一个手写数字的数据集。大概是google为了方便广大程序员进行数字识别而构建的库,里面都是美国中学生手写的阿拉伯数字,但是为了方便存储,他并不是以图片的形式保存的,而是以二进制文件的形式保存的。这就让普通人看着略微蛋疼的了,教程里也并没有提供具体的提取图片的方案。得,读取这个还得自己来。

地址

我用的应该是用python处理过的版本: mnist.pkl.gz,这个好像是为了方便用python读取特意配置过的。

分析

别看他是压缩文件,解压之后并没有用,而是一个很大的文本文件,还得在这里读取。文档里说,这里面有60000个训练图片,10000个测试图片,训练图片又分为了train_set 和valid_set两个集合(不懂是啥意思)。每个集合内都包含了图片和标签两块内容,图片都是28*28的点阵图;而标签,则是0-9之间的一个数字。

说的也挺清楚的,思路也大概晓得了,我们当前的任务应该就是用matplot进行绘图保存即可。

代码

折腾许久也是弄好了,教程中说要用theano来存图,然而theano还不会用。。。0.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import cPickle, gzip
import numpy as np
import matplotlib.pyplot as plt

def display(data):#显示图片
x=np.arange(0,28)
y=np.arange(0,28)
X,Y=np.meshgrid(x,y)
plt.imshow(data.reshape(28,28),interpolation='nearest', cmap='bone')
plt.colorbar()
plt.show()
return

def save(data,name):#保存图片
x=np.arange(0,28)
y=np.arange(0,28)
X,Y=np.meshgrid(x,y)
plt.imshow(data.reshape(28,28),interpolation='nearest', cmap='bone')
plt.savefig(name)
return

f = gzip.open('mnist.pkl.gz', 'rb')#读取数据
train_set, valid_set, test_set = cPickle.load(f)#分类
f.close()
train_set_image,train_set_num=train_set

token=10 #需要显示的图片个数
for i in range(0,token):
save(train_set_image[i],"./"+str(i)+"-"+str(train_set_num[i]))

我显示了10张图片,打开第一张(0-5.png)看看效果:

这就是美国人写的5。。。

matplotlib+numpy绘图之多种绘图

Posted on 2016-01-24 | In Python

下面将以例子的形式分析matplot中支持的,分析中常用的几种图。

填充图

参考代码

1
2
3
4
5
6
7
8
9
from matplotlib.pyplot import *
x=linspace(-3,3,100)
y1=np.sin(x)
y2=np.cos(x)
fill_between(x,y1,y2,where=(y1>=y2),color='red',alpha=0.25)
fill_between(x,y1,y2,where=(y<>y2),color='green',alpha=0.25)
plot(x,y1)
plot(x,y2)
show()

简要分析

这里主要是用到了fill_between函数。这个函数很好理解,就是传入x轴的数组和需要填充的两个y轴数组;然后传入填充的范围,用where=来确定填充的区域;最后可以加上填充颜色啦,透明度之类修饰的参数。

当然fill_between函数还有更加高级的用法,详见fill_between用法或者help文档。

效果图

散点图(scatter plots)

参考代码

1
2
3
4
5
6
7
8
9
from matplotlib.pyplot import *
n = 1024
X = np.random.normal(0,1,n)
Y = np.random.normal(0,1,n)
T = np.arctan2(Y,X)
scatter(X,Y, s=75, c=T, alpha=.5)
xlim(-1.5,1.5)
ylim(-1.5,1.5)
show()

简要分析

首先介绍一下numpy 的normal函数,很明显,这是生成正态分布的函数。这个函数接受三个参数,分别表示正态分布的平均值,标准差,还有就是生成数组的长度。很好记。

然后是arctan2函数,这个函数接受两个参数,分别表示y数组和x数组,然后返回对应的arctan(y/x)的值,结果是弧度制。

接下来用到了绘制散点图的scatter方法,首先当然是传入x和y数组,接着s参数表示scale,即散点的大小;c参数表示color,我给他传的是根据角度划分的一个数组,对应的就是每一个点的颜色(虽然不知道是怎么对应的,不过好像是一个根据数组内其他元素进行的相对的转换,这里不重要了,反正相同的颜色赋一样的值就好了);最后是alpha参数,表示点的透明度。

至于scatter函数的高级用法可以参见官方文档scatter函数或者help文档。

最后设置下坐标范围就好了。

效果图

条形图(bar plots)

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from matplotlib.pyplot import *
n = 12
X = np.arange(n)
Y1 = (1-X/float(n)) * np.random.uniform(0.5,1.0,n)
Y2 = (1-X/float(n)) * np.random.uniform(0.5,1.0,n)
bar(X, +Y1, facecolor='#9999ff', edgecolor='white')
bar(X, -Y2, facecolor='#ff9999', edgecolor='white')
for x,y in zip(X,Y1):
text(x+0.4, y+0.05, '%.2f' % y, ha='center', va= 'bottom')
for x,y in zip(X,Y2):
text(x+0.4, -y-0.05, '%.2f' % y, ha='center', va= 'top')
xlim(-.5,n)
xticks([])
ylim(-1.25,+1.25)
yticks([])
show()

简要分析

注意要手动导入pylab包,否则会找不到bar。。。

首先用numpy的arange函数生成一个[0,1,2,…,n]的数组。(用linspace也可以)

其次用numpy的uniform函数生成一个均匀分布的数组,传入三个参数分别表示下界、上界和数组长度。并用这个数组生成需要显示的数据。

然后就是bar函数的使用了,基本用法也和之前的plot、scatter类似,传入横纵坐标和一些修饰性参数。

接着我们需要用for循环来为柱状图显示数字:用python的zip函数将X和Y1两两配对并循环遍历,得到每一个数据的位置,然后用text函数在该位置上显示一个字符串(注意位置上的细节调整)。text传入横纵坐标,要显示的字符串,ha参数制定横向对齐,va参数制定纵向对齐。

最后调整下坐标范围,并且取消横纵坐标上的刻度以保持美观即可。

至于bar函数的具体用法可以参照bar函数用法或者help文档。

效果图

等高线图(contour plots)

参考代码

1
2
3
4
5
6
7
8
9
10
11
from matplotlib.pyplot import *
def f(x,y):
return (1-x/2+x**5+y**3)*np.exp(-x**2-y**2)
n = 256
x = np.linspace(-3,3,n)
y = np.linspace(-3,3,n)
X,Y = np.meshgrid(x,y)
contourf(X, Y, f(X,Y), 8, alpha=.75, cmap=cm.hot)
C = contour(X, Y, f(X,Y), 8, colors='black', linewidth=.5)
clabel(C, inline=1, fontsize=10)
show()

简要分析

首先要明确等高线图是一个三维立体图,所以我们要建立一个二元函数f,值由两个参数控制,(注意,这两个参数都应该是矩阵)。

然后我们需要用numpy的meshgrid函数生成一个三维网格,即,x轴由第一个参数指定,y轴由第二个参数指定。并返回两个增维后的矩阵,今后就用这两个矩阵来生成图像。

接着就用到coutourf函数了,所谓contourf,大概就是contour fill的意思吧,只填充,不描边;这个函数主要是接受三个参数,分别是之前生成的x、y矩阵和函数值;接着是一个整数,大概就是表示等高线的密度了,有默认值;然后就是透明度和配色问题了,cmap的配色方案这里不多研究。

随后就是contour函数了,很明显,这个函数是用来描线的。用法可以类似的推出来,不解释了,需要注意的是他返回一个对象,这个对象一般要保留下来个供后续的加工细化。

最后就是用clabel函数来在等高线图上表示高度了,传入之前的那个contour对象;然后是inline属性,这个表示是否清除数字下面的那条线,为了美观当然是清除了,而且默认的也是1;再就是指定线的宽度了,不解释,。

效果图

点阵图

参考代码

1
2
3
4
5
6
7
8
9
10
11
from matplotlib.pyplot import *
def f(x,y):
return (1-x/2+x**5+y**3)*np.exp(-x**2-y**2)
n = 10
x = np.linspace(-3,3,3.5*n)
y = np.linspace(-3,3,3.0*n)
X,Y = np.meshgrid(x,y)
Z = f(X,Y)
imshow(Z,interpolation='nearest', cmap='bone', origin='lower')
colorbar(shrink=.92)
show()

简要分析

这段代码的目的就是将一个矩阵直接转换为一张像照片一样的图,完整的进行显示。

前面的代码就是生成一个矩阵Z,不作解释。

接着用到了imshow函数,传人Z就可以显示出一个二维的图像了,图像的颜色是根据元素的值进行的自适应调整,后面接了一些修饰性的参数,比如配色方案(cmap),零点位置(origin)。

最后用colorbar显示一个色条,可以不传参数,这里传进去shrink参数用来调节他的长度。

效果图

3D图

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np
from pylab import *
from mpl_toolkits.mplot3d import Axes3D
fig = figure()
ax = Axes3D(fig)
X = np.arange(-4, 4, 0.25)
Y = np.arange(-4, 4, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=plt.cm.hot)
ax.contourf(X, Y, Z, zdir='z', offset=-2, cmap=plt.cm.hot)
ax.set_zlim(-2,2)
show()

简要分析

有点麻烦,需要用到的时候再说吧,不过原理也很简单,跟等高线图类似,先画图再描线,最后设置高度,都是一回事。

效果图

matplotlib+numpy绘图之基本操作

Posted on 2016-01-23 | In Python

需要导入的包:

1
2
import numpy as np
from pylab import *

第一个函数图像

1
2
3
4
5
X = np.linspace(-np.pi, np.pi, 256,endpoint=True)
C,S = np.cos(X), np.sin(X)
plot(X,C)
plot(X,S)
show()

有matlab基础的同学肯定不陌生。。。是的,这两个模块的组合几乎就跟matlab的用法无二。。

1、首先用np.linspace方法生成一个数组X,这个数组是从$-\pi$开始到$\pi$的总共包含256个元素的数组,endpoint参数表示是否包含首尾端点(他的值是True或False,首字母要大写。。。。)。当然,这个数组就是一个普通的数组了,跟其他数组没有区别。

2、然后用np.cos()和np.sin()方法作用在X数组上,对于X中的每一个元素进行计算,生成结果数组。(免去了迭代的过程)。

3、接着调用pylab的plot方法,第一个参数是横坐标数组,第二个参数是纵坐标数组,其他参数暂且不谈。这样他会生成一个默认的图表了。(不会立刻显示)

4、当然,最后还要调用show方法来显示图表。

5、结果:

图表的名字叫figure1,左下面有几个按钮,都是很实用的东西,右下角会显示当前鼠标左边,也很方便。

图表布局和坐标分布

每一个图表都是在一个figure里面,我们可以通过如下命令生成一个空的figure:

1
figure(figsize=(8,6), dpi=80)

这里参数的顺序没有要求,但是一定要加上参数名,因为他是根据参数名来区别每个参数的,是一种跟C语言类型不同的函数。figsize参数表示figure的宽高比,然后dpi表示每一份占的长度,比如这里就表示图像是640x480的。

输出命令之后会立刻出现一个窗口,接下来所有的plot命令都会立刻显示在这个窗口上而不用再输入show命令了。

一个figure里也能显示多个图表,我们可以用如下函数来分割一个figure:
subplot(3,4,6)
这样就会把当前的figure分割成3行4列的表,而激活其中的第6张,即第2行第3张。以后的plot都是在这一个子表上生成的,如果需要更换则可以重新输入subplot命令来确定其新的位置。

除此之外,如果我们对图表显示的范围不满意,我们还可以直接调整图表的坐标范围:

1
2
xlim(-4.0,4.0)
ylim(-1.0,1.0)

这就表示x轴的范围设置在-4到4,y轴的范围设置在-1到1。当然,如果是想相对的进行修改我们可以利用下numpy数组的min和max方法。比如X.min() 这样的东西。

如果对坐标显示的密度啊什么的不满意,我们也可以调节他的标注点:

1
2
xticks(np.linspace(-4,4,9,endpoint=True))
yticks(np.linspace(-1,1,5,endpoint=True))

对于xticks和yticks,我们实际上可以传入任意的数组,这里不过是为了方便而用numpy快速生成的等差数列。

当然,我们也可以给标注点进行任意的命名,像下面这样:

1
xticks([1,2,3,4,5],['one','two','three','four','five'])

效果也很好想象,就不贴图了。需要注意的是这里也可以支持LaTex语法,将LaTex引用在两个$之间就可以了。(关于LaTex)

这里也有个小窍门,就是如果想不显示标注的话,我们就可以直接给xticks赋一个空的数组。

更改色彩和线宽

我们可以在画plot的时候用如下方法指定他的颜色和线宽:

1
plot(X, C, color='#cadae3', linestyle='-',linewidth=1.3, marker='o', markerfacecolor='blue', markersize=12,)

同样,这里参数的顺序不重要,名字才重要。

  • color参数可以指定RGB的色相,也可以用一些默认的名字,比如red blue之类的。

  • linestyle参数则指定了线的样式,具体参照以下样式:

参数 样式
‘-‘ 实线
‘–’ 虚线
‘-.’ 线-点
‘:’ 点虚线
  • linewidth参数指定折线的宽度,是个浮点数。

  • marker参数指定散点的样式,具体参照以下样式:

参数 样式
‘.’ 实心点
‘o’ 圆圈
‘,’ 一个像素点
‘x’ 叉号
‘+’ 十字
‘*’ 星号
‘^’ ‘v’ ‘<’ ‘>’ 三角形(上下左右)
‘1’ ‘2’ ‘3’ ‘4’ 三叉号(上下左右)
  • markerfacecolor参数指定marker的颜色

  • markersize参数指定marker的大小

这样就基本上能够自定义任何的折线图、散点图的样式了。

移动轴线

这段有点小复杂,暂时不想具体了解奇奇怪怪的函数调用,姑且先记录下用法和原理:

1
2
3
4
5
6
7
ax = gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))

我们知道一张图有上下左右四个轴线,这里我们把右边和上边的轴线颜色调为透明,然后把下边设置到y轴数据为0的地方,把左边设置到x轴数据为0的地方。这样我们就能根据自己想要位置来调节轴线了。

比如下面这段官方的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# -----------------------------------------------------------------------------
# Copyright (c) 2015, Nicolas P. Rougier. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
# -----------------------------------------------------------------------------
import numpy as np
import matplotlib.pyplot as plt

plt.figure(figsize=(8,5), dpi=80)
ax = plt.subplot(111)

ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))

X = np.linspace(-np.pi, np.pi, 256,endpoint=True)
C,S = np.cos(X), np.sin(X)

plt.plot(X, C, color="blue", linewidth=2.5, linestyle="-")
plt.plot(X, S, color="red", linewidth=2.5, linestyle="-")

plt.xlim(X.min()*1.1, X.max()*1.1)
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
[r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])

plt.ylim(C.min()*1.1,C.max()*1.1)
plt.yticks([-1, 0, +1],
[r'$-1$', r'$0$', r'$+1$'])

plt.show()

显示的结果就是:

图例和注解

图例十分简单,下述代码就可以解决:

1
2
3
plot(X, C, color="blue", linewidth=2.5, linestyle="-", label="cosine")
plot(X, S, color="red", linewidth=2.5, linestyle="-", label="sine")
legend(loc='upper left')

在plot里指定label属性就好了,最后调用下legend函数来确定图例的位置,一般就是’upper left’就好了。

注解就有点麻烦了,要用到annotate命令,挺复杂的,暂时是在不想看,姑且贴一段完整的代码和效果图吧:

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
# -----------------------------------------------------------------------------
# Copyright (c) 2015, Nicolas P. Rougier. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
# -----------------------------------------------------------------------------
import numpy as np
import matplotlib.pyplot as plt

plt.figure(figsize=(8,5), dpi=80)
ax = plt.subplot(111)
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))

X = np.linspace(-np.pi, np.pi, 256,endpoint=True)
C,S = np.cos(X), np.sin(X)

plt.plot(X, C, color="blue", linewidth=2.5, linestyle="-", label="cosine")
plt.plot(X, S, color="red", linewidth=2.5, linestyle="-", label="sine")

plt.xlim(X.min()*1.1, X.max()*1.1)
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
[r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])

plt.ylim(C.min()*1.1,C.max()*1.1)
plt.yticks([-1, +1],
[r'$-1$', r'$+1$'])

t = 2*np.pi/3
plt.plot([t,t],[0,np.cos(t)],
color ='blue', linewidth=1.5, linestyle="--")
plt.scatter([t,],[np.cos(t),], 50, color ='blue')
plt.annotate(r'$\sin(\frac{2\pi}{3})=\frac{\sqrt{3}}{2}$',
xy=(t, np.sin(t)), xycoords='data',
xytext=(+10, +30), textcoords='offset points', fontsize=16,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))

plt.plot([t,t],[0,np.sin(t)],
color ='red', linewidth=1.5, linestyle="--")
plt.scatter([t,],[np.sin(t),], 50, color ='red')
plt.annotate(r'$\cos(\frac{2\pi}{3})=-\frac{1}{2}$',
xy=(t, np.cos(t)), xycoords='data',
xytext=(-90, -50), textcoords='offset points', fontsize=16,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))

plt.legend(loc='upper left', frameon=False)
plt.savefig("../figures/exercice_9.png",dpi=72)
plt.show()

效果图:

还是十分高能的。。。

matplotlib+numpy绘图之引言

Posted on 2016-01-23 | In Python

简述

Matplotlib是一个基于python的2D画图库,能够用python脚本方便的画出折线图,直方图,功率谱图,散点图等常用图表,而且语法简单。具体介绍见matplot官网。中文教程见reverland的博客-Matplotlib教程(来自官方教程的翻译)。

Numpy(Numeric Python)是一个模仿matlab的对python数值运算进行的扩展,提供了许多高级的数值编程工具,如:矩阵数据类型、矢量处理,以及精密的运算库。专为进行严格的数字处理而产生,而且据说自从他出现了以后,NASA就把很多原来用fortran和matlab做的工作交给了numpy来做了,可见其强大。。。他的官网在这里,具体的资料都在里面。

安装

$sudo apt-get install python-matplotlib
$sudo apt-get install python-numpy
(牛力大法好~)

使用

matplotlib可以在脚本中使用,不过如果在ipython中使用则会更加炫(直接添加–pylab参数可以免去导包的过程),而且能得到类似Matlab/Mathematica一样的功能,即时输入,即时输出。个人觉得说白了他就是模仿Matlab/Mathematica的,但是的确比前者更加方便编程。

很多情况下matplot需要配合numpy包一起用,关于numpy包我不打算分开来说,用到的时候提一下就行。有一点需要注意的是,numpy包通常是这样导入的:
import numpy as np
会给他起一个叫np的别名,而且这几乎已经是约定俗成了。

关于matplotlib和numpy的具体用法接下来会依据官方教程分别介绍。

文档

如果不方便或者不高兴看官方教程,其实matplot和numpy自带的文档也挺适合学习的,讲的也很细。

在python或者ipython中输入help(*需要查找的函数*) 就行(当然需要先导入下包)。

python标准库cPickle包用法简析

Posted on 2016-01-22 | In Python

CPickle包是一个很常用的工具,用来将任何一个数据类型存储到文件中,再原封不动的读取出来。在需要保存一些特定格式的数据或是大量的数据的时候相比自己写文件来说,可是非常方便而且有用的。

用法

将数据输出到文件

1
2
3
4
5
6
7
8
9
10
import cPickle

class test():
element1 = 1
element2 = '2'

obj=test()
cPickle.dump(obj,open("data.txt",'wb'))#输出到文件
cPickleString=cPickle.dumps(obj)#输出到变量
print cPickleString

输出:(屏幕和文件)

1
2
3
4
5
(i__main__
test
p1
(dp2
b.

从上面这个例子可以看出用dump方法可以把任何数据类型输出到文件,而dumps方法可以把任何数据输出到变量。当然,存储的形式就是他自己规定的了。

从文件读取数据

用刚才生成的数据来恢复文件:

1
2
3
4
5
6
7
8
9
import cPickle

class test():
element1 = 1
element2 = '2'

obj=cPickle.load(open("data.txt",'rb'))
print obj.element1
print obj.element2

输出:

1
2
1
2

很明显load方法接受文件参数,把读取的数据返回给变量,可以无损恢复。

ps

用法很简单,但是绝对是挺实用的。最后补充句,就是这个cPickle包其实是原来的pickle包用C语言改写的。所以pickle包跟他的用法基本相同,但是cPickle会更快一点。

利用Sphinx工具为python项目生成文档

Posted on 2016-01-22 | In Python

Sphinx(没错,就叫斯芬克斯。。。)其实是一个基于SQL全文检索引擎,大概是个为数据库检索提供一些更加强大的检索功能。这个东西也给很多种的语言比如PHP,Python,Perl,Ruby留有API接口,可以供他们调用实现检索功能。

当然,暂时我还没打算研究这个东西。今天我只是想利用他给Python的接口来为python程序生成基于网页形式的项目文档。(好像国外挺流行这个的,今天就是为了给deep learning的源码生成下文档才晓得有这个东西的)。

目测这潭水还是很深的,今天姑且就事论事,把实现的步骤简要记录下来方便日后使用。

安装

由于是为了在python下使用了,当然使用python的下载工具pip来安装了,pip的使用方法见《pip工具简单用法》。

安装命令:

1
$pip install sphinx

so easy就装好了,接下来就是用他来生成文档了。

生成

对于那些本身就为Sphinx设计过的工程来说,可以直接找到他的doc/目录,如果发现了conf.py文件的话,说明他已经预先做了配置。这时候我们只需要直接生成apidoc就行了:
$ sphinx-apidoc -o .doc/ .
然后在他的输出目录下就会出现一个Makefile,然后我们只要$make html,就会发现一个html文件夹,没错,我们的文档就在这里啦。

而对于那些没有配置过Sphinx的工程来说,我们首先得在他的.py文件的目录下进行预先生成:
$sphinx-quickstart
然后根据提示输入文件名,作者名,版本号啥啥的,然后一路确认就可以了。这样就会生成一个conf.py的文件,然后进行之前的操作就好了。

以上这就是生成文档的最简单的用法。。。应该是一个程序员理所应当需要掌握的了。。。

1…474849…58

574 posts
69 categories
286 tags
© 2024 Companyd
Powered by Hexo
|
Theme — NexT.Muse v5.1.4