使用Matplotlib绘制散点图

由于要做算法结果的可视化输出,需要绘制大量的散点图,所以打算使用 matplotlib,以下给出一个绘制散点图例子。

效果图

scatter

源代码

import matplotlib.pyplot as plt
import numpy as np

n = 100

for color in ['red','blue','green']:
    x,y=np.random.rand(2,n)
    scale=100*np.random.rand(n)
    plt.scatter(x,y,c=color,s=scale,label=color,alpha=0.6,edgecolors='white')

plt.title('Scatter')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.show()

函数说明

numpy.random.rand(d0,d1,d2…)

返回维度为 (d0,d1,d2…) 的位于区间 [0,1) 满足均匀分布的随机数,返回值结果类型为 ndarray。

matplotlib.pyplot.scatter(x,y,c=color,s=scale,label=color,alpha=0.6,edgecolors=’white’)

scatter() 函数用来绘制散点图, x 和 y 为输入数据,形如 shape (n, )。c 表示散点的颜色,指定一个颜色或者色序。s 表示散点的大小,形如 shape (n, )。label 表示显示在图例中的标注。alpha 是 RGBA 颜色的透明分量。edgecolors 指定三点圆周的颜色。

其他函数

函数名 作用
title 图标的标题
xlabel x轴的名称
ylabel y轴的名称
legend 显示右上角的图例
grid 显示网格
show 显示图像

使用Python对图像进行尺寸和格式的转换

说起来这还是在万网虚拟主机备案的时候遇到的问题。备案的时候要求上传 800×600 的带背景的照片,因为指定的照相馆离我住的地方有一定的距离,所以就申请了幕布自己拍,拍完以后需要当然要修改照片的分辨率。按照以往就是安装一个格式工厂转一下,但是既然学了 Python 当然要使用 PIL 来试试手了!
代码比较简单:

from PIL import Image

img=Image.open('./IMG_0154.jpg')
img.show()
print img.size

resize_img=img.resize((800,600))
resize_img.show()
resize_img.save('resize.jpg')

使用 Image 还能做图像的旋转、缩略图等效果我就不介绍了,真心感慨一下 Python 真是一个方便的好工具!

在C#中使用SQLite简介

SQLite

SQLite 是一种小型的关系数据库。相比于 MySQL、SQLServer 这样的客户端/服务器模式,它的存储方式更接近对文件的读写。而相比于普通的文件,SQLite 又支持我们使用 SQL 语句来操纵数据。本文将会简单介绍一下如何在 C# 语言中使用 SQLite。

System.Data.SQLite

在 C# 中操作 SQLite 我们需要使用 System.Data.SQLite 这个类库。这个库并不是 .NET 的标准库,所以我们需要手动下载它。这里给出一个可用的下载链接

在使用之前,我们需要将 dll 文件拷贝到工程项目中,然后添加对 dll 文件的引用。

基本操作

1.创建数据库文件

SQLiteConnection.CreateFile("sqlite.db");

2.创建和打开数据库连接

SQLiteConnection conn = new SQLiteConnection("Data Source=sqlite.db;Version=3;");
conn.Open();

3.创建表

string sql = "create table employee (name varchar(20), age int)";
SQLiteCommand cmd = new SQLiteCommand(sql, conn);

4.插入数据记录

sql = "insert into employee (name,age) values ('wuzhiyu',25)";
cmd = new SQLiteCommand(sql, conn);
cmd.ExecuteNonQuery();

其中 cmd.ExecuteNonQuery(); 一般用来执行插入、更新和删除操作。

5.查询数据

sql = "select * from employee";
cmd = new SQLiteCommand(sql, conn);
SQLiteDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
    Console.WriteLine("Name:" + reader["name"] + "\t Age:" + reader["age"]);
}

SQLiteDataAdapter adapter = new SQLiteDataAdapter(sql,conn);
DataTable dt=new DataTable();
int count = adapter.Fill(dt);
for(int i=0;i<count;i++)
{
    Console.WriteLine("Name: {0}\t Age: {1}", dt.Rows[i][0], dt.Rows[i][1]);
}

上面给出了两种读取数据的方法,一个是使用类似迭代器(或者说游标)的方法一行行来读取数据记录,第二种则是使用类似适配器的方式将数据填充到 DataTable 中,然后我们对 DataTable 进行操作。

源代码

namespace SQLite
{
    class Program
    {
        static void Main(string[] args)
        {
            //1. Create a database file
            SQLiteConnection.CreateFile("sqlite.db");

            //2. Connecting to a database
            SQLiteConnection conn = new SQLiteConnection("Data Source=sqlite.db;Version=3;");
            conn.Open();

            //3. Create a table
            string sql = "create table employee (name varchar(20), age int)";
            SQLiteCommand cmd = new SQLiteCommand(sql, conn);
            cmd.ExecuteNonQuery();

            //4. Insert records
            sql = "insert into employee (name,age) values ('wuzhiyu',25)";
            cmd = new SQLiteCommand(sql, conn);
            cmd.ExecuteNonQuery();
            sql = "insert into employee (name,age) values ('Frank',50)";
            cmd = new SQLiteCommand(sql, conn);
            cmd.ExecuteNonQuery();

            //5. Query the records
            sql = "select * from employee";
            cmd = new SQLiteCommand(sql, conn);
            SQLiteDataReader reader = cmd.ExecuteReader();
            while(reader.Read())
            {
                Console.WriteLine("Name:" + reader["name"] + "\t Age:" + reader["age"]);
            }

            SQLiteDataAdapter adapter = new SQLiteDataAdapter(sql,conn);
            DataTable dt=new DataTable();
            int count = adapter.Fill(dt);
            for(int i=0;i<count;i++)
            {
                Console.WriteLine("Name: {0}\t Age: {1}", dt.Rows[i][0], dt.Rows[i][1]);
            }
        }
    }
}

参考资料

将WordPress安装或者迁移到万网虚拟机上

万网虚拟机

前一阵子在远景论坛上看到万网的虚拟主机免费,果断申请了一个来使用。使用期间也第一次领教了备案带来的麻烦,好在万网的备案服务还是很好很迅速的,幕布的快递也很给力,就是工信部的审核花了十几天时间。从后台的显示来看,万网的虚拟机可以免费使用两年。这个域名note4code.com也是在万网上购买的,49元/年的价格还算公道。

WordPress的安装

万网的虚拟机使用的操作系统是 CentOS,支持 MySQL和 PHP5.3。WordPress 在该虚拟机上的安装比在 Ubuntu 上安装简单多了(参见上一篇博客在 Ubuntu 上安装 WordPress),不需要安装和设置 Apache2、MySQL 和 PHP,不需要为了修改 URL 而进行的大量操作。安装步骤简单概括就是:

  • 下载 WordPress 源代码。
  • 解压缩文件,创建uploads(wp-content/uploads)文件夹。
  • 复制 wp-config-sample.php,重命名为 wp-config.php 并修改其内容。
/** The name of the database for WordPress */
define('DB_NAME', 'database_name_here');

/** MySQL database username */
define('DB_USER', 'username_here');

/** MySQL database password */
define('DB_PASSWORD', 'password_here');

/** MySQL hostname */
define('DB_HOST', 'localhost');

修改为:

/** The name of the database for WordPress */
define('DB_NAME', 'qdmxxxxxxxxx_db');

/** MySQL database username */
define('DB_USER', 'qdmxxxxxxxxx');

/** MySQL database password */
define('DB_PASSWORD', 'xxxxxxxx');

/** MySQL hostname */
define('DB_HOST', 'qdmxxxxxxxxx.my3w.com');
  • 将所有文件复制到 FTP 服务器的 htdocs 目录下。
  • 登录你的域名(审核已通过的情况下),跟随界面操作。

关于WordPress的迁移

可能不少 WordPress 的用户和我一样,在审核期间就现在本地的 WordPress 上写起了博客,打算在审核通过后再将数据迁移到网上,由于网上相关的经验比较少,我也是花了好几天才摸索出了一套方法。

1.导出上传的图片

在写博客的时候不可避免会用到一些图片,这些图片应该都存在我们建立的 uploads 文件夹里,在向 FTP 服务器复制文件的时候记得将原来的 uploads 文件夹合并到 FTP 上去。

2.导出数据库

我们的文章都存在数据库中,所以 WordPress 的迁移本质上是数据库的迁移,我们首先导出数据库:

mysqldump -u wpuser -p wordpress > wordpress.sql

输入该用户的密码后我们得到一个名为 wordpress.sql 的文件,打开文件删除所有类似 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 的语句和注释,仅保留创建表和插入数据的语句。然后使用 Vim(没错,我支持 Vim)的全局替换字符串功能,将 localhost/wordpress 替换为你的域名。

3.导入数据库

进入虚拟主机数据库的管理界面,导入我们修改好的脚本即可。至此大功告成!

注意:在导入数据前最好将本地WordPress使用的插件在虚拟主机上提前装好,避免数据出现错误或者不一致的情况!

在Ubuntu上安装WordPress(附脚本)

WordPress简介

WordPress是一种使用PHP和MySQL开发的博客平台,其实对个人来说也可以当做一个像印象笔记一样的个人知识、内容管理平台。同时各种第三方的插件、主题也让WordPress具备了独特的个性化选择。

手动安装WordPress

安装WordPress相对来说是一个比较简单的过程,只要按照以下步骤执行,一般都可以顺利安装。

1.安装依赖的软件包

第一步要在Ubuntu上安装WordPress所依赖的MySQL、Apache2、PHP等软件包,具体安装方法如下:

sudo apt-get install apache2
sudo apt-get install libapache2-mod-php5 php5
sudo apt-get install mysql-server-5.0  mysql-common mysql-admin
sudo apt-get install php5-mysql

2.配置MySQL

在上一步中安装完MySQL之后记住MySQL的root用户的密码,在这一步中将会使用。使用如下命令来进入MySQL数据库:

mysql -u root -p

然后输入密码进入MySQL。接着我们创建WordPress所使用的数据库:

create database wordpress;

接着为WordPress创建用户并将数据库wordpress的所有权限赋予这个用户:

create user wpuser@localhost identified by 'wppasswd';
grant all privileges on wordpress.* to wpuser@localhost;
flush privileges;

3.下载并安装WordPress

WordPress的安装文件既可以访问中文官方网站进行下载,也可以使用wget命令下载:

wget -c http://wordpress.org/latest.tar.gz

下载完成后解压文件,复制 wp-config-sample.php 文件并重命名为 wp-config.php,并将相关参数进行替换,将

/** The name of the database for WordPress */
define('DB_NAME', 'database_name_here');

/** MySQL database username */
define('DB_USER', 'username_here');

/** MySQL database password */
define('DB_PASSWORD', 'password_here');

/** MySQL hostname */
define('DB_HOST', 'localhost');

修改为:

/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');

/** MySQL database username */
define('DB_USER', 'wpuser');

/** MySQL database password */
define('DB_PASSWORD', 'wppasswd');

/** MySQL hostname */
define('DB_HOST', 'localhost');

其中’DB_HOST’因为MySQL就在本地所以就不用修改localhost,如果数据库位于其他服务器那么就应该填写相应域名或者IP地址。

4.拷贝WordPress解压文件至Apache2服务器目录下

我们要将解压出来的wordpress文件夹拷贝至/var/www/html/下面,为其创建uploads文件夹(保存上传的图片)并修改文件的拥有者为www-data。

sudo rsync -avP ./wordpress /var/www/html/
sudo mkdir /var/www/html/wordpress/wp-content/uploads
sudo chown -R www-data:www-data /var/www/html/wordpress/*

5.安装MySQL扩展

如果遇到“ Your PHP installation appears to be missing the MySQL extension which is required by WordPress ”的情况,一般在 /etc/php5/apache2/php.ini 中将“ extension=/path/to/extension/mysql.so ”改为“ extension=mysql.so ”就可以了。

6.修改apache2的配置文件来允许URL的重写

本步骤的目的是为了允许WordPress能够自定义固定链接的格式。在/etc/apache2/sites-available/000-default.conf中添加下文星号包括的部分:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html
    *ServerName 127.0.0.1*
    *<Directory /var/www/html/>*
        *AllowOverride All*
    *</Directory>*
    . . .

然后使用如下命令来允许URL的重写以及Apache2的重启:

sudo a2enmod rewrite
sudo service apache2 restart

最后创建 .htaccess 文件并修改其权限与所有者:

touch /var/www/html/wordpress/.htaccess
sudo chown :www-data /var/www/html/wordpress/.htaccess
chmod 664 /var/www/html/wordpress/.htaccess

7.著名的5分钟安装

打开浏览器登录 http://localhost/wordpress 按照图形界面的提示操作即可。

Shell脚本

以下的脚本本人亲测,使用了expect命令来简化设置过程,并添加了几个步骤来修正可能出现的问题.

#!/bin/sh

if [ $# -ne 4 ]; then
    echo "Usage: sudo sh $0 db_name user_name user_passwd mysql_root_passwd"
    exit 1
fi

db_name=$1
user_name=$2
user_passwd=$3
mysql_root_passwd=$4

install_dependency(){
    #1. install the dependency of wordpress
    sudo apt-get install apache2
    sudo apt-get install libapache2-mod-php5 php5
    sudo apt-get install mysql-server mysql-common
    sudo apt-get install php5-mysql
}

config_mysql(){
    #2. configure mysql
sudo apt-get install expect
expect << EOF
set timeout 100
spawn mysql -u root -p
expect {
    "Enter password:" {send "$mysql_root_passwd\r"}
}
expect "mysql>"
send "create database $db_name;\r"
expect "mysql>"
send "create user $user_name@localhost identified by '$user_passwd';\r"
expect "mysql>"
send "grant all privileges on $db_name.* to $user_name@localhost;\r"
expect "mysql>"
send "flush privileges;\r"
expect "mysql>"
send "exit\r"
EOF
}

install_wordpress(){
    #3. install wordpress
    #3.1 download the wordpress
    wget -c http://wordpress.org/latest.tar.gz
    #3.2 extract the files to rebuild wordpress
    tar xvfz latest.tar.gz
    sudo rm -f latest.tar.gz
    #3.3 install some packages to allow you to work with images, install plugins and update portions of your site using ssh.
    sudo apt-get install php5-gd libssh2-php
}

config_wordpress(){
    #4. configure wordpress
    sed "s/database_name_here/$db_name/" ./wordpress/wp-config-sample.php | sed "s/username_here/$user_name/" | sed "s/password_here/$user_passwd/" >> ./wordpress/wp-config.php
}

copy_files(){
    #5. copy files to the document root
    sudo rsync -avP ./wordpress /var/www/html/
    sudo rm -rf ./wordpress
    sudo mkdir /var/www/html/wordpress/wp-content/uploads
    sudo chown -R www-data:www-data /var/www/html/wordpress/*
}

install_mysql_extension(){
    #6. when the problem "Your PHP installation appears to be missing the MySQL extension which is required by WordPress" occurs, you need this.
    sudo sed -i "s/extension=\/path\/to\/extension\/msql.so/extension=mysql.so/" /etc/php5/apache2/php.ini
}

modify_apache_to_allow_url_rewrites(){
    date_time=$(date +%y%m%d%H%M)
    sudo cp /etc/apache2/sites-available/000-default.conf "/etc/apache2/sites-available/000-default.conf.$date_time.bak"
    sudo sed -i "/<\/VirtualHost>/i \        ServerName 127.0.0.1\n        <Directory \/var\/www\/html\/wordpress\/>\n            AllowOverride All\n        <\/Directory>" /etc/apache2/sites-available/000-default.conf
    sudo a2enmod rewrite
    sudo echo 'ServerName localhost' >> /etc/apache2/apache2.conf
    sudo service apache2 restart
}

create_htaccess_file(){
    touch /var/www/html/wordpress/.htaccess
    sudo chown :www-data /var/www/html/wordpress/.htaccess
    chmod 664 /var/www/html/wordpress/.htaccess
}

#install_dependency
config_mysql
install_wordpress
config_wordpress
copy_files
install_mysql_extension
modify_apache_to_allow_url_rewrites
create_htaccess_file

exit 0

参考资料

使用Numpy实现K-Means算法

1. K-Means算法简介

1967年,MacQueen 首次提出了 K 均值聚类算法( K-Means算法 )。迄今为止,很多聚类任务都选择该经典算法。K-Means算法的优点是快速高效,其算法复杂度为 O(tKmn),其中 t 表示算法迭代的次数,K 表示聚类的数目,m 表示每个对象拥有的属性个数,n 表示待聚类的对象的个数。

该算法的核心思想是找出 k 个聚类中心,使得每一个数据点 X_i 和与其最近的聚类中心 C_l 的平方距离和被最小化( 该平方距离和被称为代价函数值 E )。

    \[D(X_i,C_l) = \sum\limits_{j = 1}^{ m } {Euclid^2(X_{ij},C_{lj})}\]

    \[E = \sum\limits_{l = 1}^k {\sum\limits_{i = 1}^{{n}} {D({X_i},{C_l})} }\]

K-Means算法的 mean 为类簇的中心,是一个类簇中所有对象在所有属性上的平均。在聚类的初始阶段,我们一般随机指定待聚类对象中的 K 个对象作为 mean

但是该方法也存在着一些缺陷:(1)K-Means 算法往往只能收敛到一个局部最优值。(2)聚类结果对聚类数目 K 和聚类开始时选取的 K 个初始对象非常敏感。

2. K-Means算法描述

输入:n 个带聚类对象,聚类中心个数 K
输出:K 个类簇(包括类簇中心和类簇中的对象)
算法过程:

  1. n 个对象的数据进行标准化。
  2. 随机选取 K 个对象作为初始的聚类中心。
  3. 计算每个对象到 K 个聚类中心的距离,将对象加入距离最近的类簇中。
  4. 根据类簇内的对象更新类簇的中心。
  5. 计算代价函数值 E
  6. 迭代第3步到第5步直至 E收敛。

3. Python代码

下文的代码实现使用了Python的Numpy库,关于Numpy的安装和使用请参照这里

import numpy as np

def loadDataFromTxt(fileName):
    dataMat=[]
    fr=open(fileName)
    for line in fr.readlines():
        curLine=line.strip().split('\t')
        fltLine=map(float,curLine)
        dataMat.append(fltLine)
    dataMat=np.mat(dataMat)
    return dataMat

def autoNormal(dataSet):
    dataShape=np.shape(dataSet)
    n=dataShape[0]
    m=dataShape[1]
    for j in range(m):
        colMax=np.max(dataSet[:,j])
        colMin=np.min(dataSet[:,j])
        colRange=colMax-colMin
        dataSet[:,j]=(dataSet[:,j]-colMin)/colRange
    return dataSet

def randomInitCentroids(dataSet,k):
    m=np.shape(dataSet)[1]
    centroids=np.mat(np.zeros((k,m)))
    for j in range(m):
        colMin=np.min(dataSet[:,j])
        colMax=np.max(dataSet[:,j])
        rangeJ=float(colMax-colMin)
        centroids[:,j]=colMin+np.random.rand(k,1)*rangeJ
    return centroids

def euclidDistance(vectA,vectB):
    return np.sqrt(np.sum(np.power(vectA-vectB,2)))

def KMean(dataSet,k,normalMethod=autoNormal,intialMethod=randomInitCentroids,distMethod=euclidDistance):
    n=dataSet.shape[0]
    dataSet=normalMethod(dataSet)
    centroids=intialMethod(dataSet,k)
    clusterAssignment=np.mat(np.zeros((n,2)))
    clusterChanged=True
    while clusterChanged:
        clusterChanged=False
        for i in range(n):
            minIndex=-1;minDist=np.inf
            for j in range(k):
                distance=distMethod(dataSet[i,:],centroids[j,:])
                if distance<minDist:
                    minIndex=j
                    minDist=distance
            if clusterAssignment[i,0] != minIndex :
                clusterChanged=True
                clusterAssignment[i,:]=minIndex,minDist        
        for cent in range(k):
            ptsInCluster=dataSet[np.where(clusterAssignment[:,0].A==cent)[0]]
            centroids[cent,:]=np.mean(ptsInCluster,axis=0)
    return centroids,clusterAssignment

dataSet=loadDataFromTxt('data.txt')
centroids,clusterAssignment=KMean(dataSet,2)
print clusterAssignment
print centroids

Markdown基本语法

认识 Markdown 是从使用Github开始的,一直很好奇那个.md 文件到底是干什么的。直到在某次在伯乐在线看到了到了关于Markdown的介绍才有所了解。之前虽然在使用 MediaWiki的时候略微了解了一下语法但是使用时间很短早就忘掉了。直到最近开始使用 IPython Notebook 了,那就好好学习一下优雅的 Markdown 吧!

吐槽一下,博客园的 Markdown 真是渣,显示效果好多不对。

  • 标题与标题之间间距、标题与正文之间的间距
  • 有序列表的嵌套
  • 为什么***就显示不了分割线呢?

1.段落

  1. 单个回车视为空格,多个回车才能分段。
  2. 行尾加两个空格实现段内换行。

2.标题

# 一级标题

## 二级标题

### 三级标题

……

3.区块引用

一级引用在段落前加一个 >,如果二级引用则使用 >>。

> + 这是一个引用的第一行。
这是第二行。
> > – 这是一个嵌套引用的第一行。
嵌套引用第二行。
>
> + 外层引用的第三行

效果:

  • 这是一个引用的第一行。
    这是第二行。

    • 这是一个嵌套引用的第一行。
      嵌套引用第二行。
  • 外层引用的第三行

4.列表

列表分为有序列表和无序列表。
无序列表的定义形式:

* 无序列表中的一项,注意星号以后有空格
  * 无序列表的子项,要以一个制表符或者4个空格缩进
* 无序列表中的第二项

效果:

  • 无序列表中的一项,注意星号以后有空格
    • 无序列表的子项,要以一个制表符或者4个空格缩进
  • 无序列表中的第二项

有序列表的定义形式

1. 有序列表有编号,数字后面紧跟一个空格
 1. 子项起始处保持一个空格缩进
 2. * 或者英文 . 之后保留一个空格
2. 有序列表中的第二项

效果:

  1. 有序列表有编号,数字后面紧跟一个空格
    1. 子项起始处保持一个空格缩进
    2. * 或者英文 . 之后保留一个空格
  2. 有序列表中的第二项

5.代码区块

如果想要插入代码有两种方式。一个是用反引号 ` 包起来,一种是用制表符或至少四个空格缩进。

  void Hello(){ System.out.println(“Hello World!”)}

效果:

void Hello(){ System.out.println("Hello World!")}

6.分割线

3个或3个以上的 ***


7.链接

地址链接

[需要显示的文字](链接地址),例:

[Dr. Lightman](http://www.cnblogs.com/NO-30/)
效果: Dr. Lightman


图片链接

![图片的替代文字](URL),例:

![测试图片](http://pic.cnitblog.com/avatar/504460/20130316182932.png)
测试图片


参考形式

[Dr. Ligthman][1]
![Dr. Ligthman Logo][2]

[1]:http://www.cnblogs.com/NO-30/
[2]:http://pic.cnitblog.com/avatar/504460/20130316182932.png

效果:

Dr. Ligthman
Dr. Ligthman Logo

8.强调

  1. *斜体* 的效果为 斜体
  2. **粗体** 的效果是 粗体

9.反斜杠

反斜杠用来作为转义字符,比如放在 * 前面取消斜体的转义等。

尾声

最后推荐一下我使用过的几个在线 Markdown 编辑器:

个人觉得最赞的还是马克飞象。这三个在线编辑器都提供了丰富的文本编辑功能,但是马克飞象可以连接印象笔记,方便内容的管理和组织。马克飞象还支持在线编辑文档的导出,支持 Markdown、HTML、PDF 三种格式。

你给别人传文件最先想到什么格式?当然是PDF!打印到纸上是真正的所见即所得,还能防止文档被修改。虽然 PDF 导出还需要借助 Chrome 的打印功能,但是这个功能还是很赞!

Numpy和matplotlib的安装和使用

最近要写几个数据挖掘的算法,可是由于Java和C#没有比较成熟和知名的可视化类库,所以想到了用Python的Numpy计算,用matplotlib来做结果的可视化。

Numpy与matplotlib

Numpy
NumPy系统是Python的一种开源的数字扩展。这种工具可用来存储和处理大型矩阵,比Python自身的嵌套列表(nested list structure)结构要高效的多(该结构也可以用来表示矩阵matrix)。我用它来进行矩阵的计算,非常便捷。
matplotlib
Matplotlib 可能是 Python 2D- 绘图领域使用最广泛的套件。它能让使用者很轻松地将数据图形化,并且提供多样化的输出格式。

在Windows上安装软件包

在Windows上安装Numpy和matplotlib是一个和痛苦的过程。总体来说,安装这两个包的官方安装程序是远远不够的。总会提示你缺这个缺那个。我的解决办法接单粗暴,提示缺少什么了我就谷歌然后安装这个包。所有的包都可以在UCI的网站上找到。

最后为了安装Nump和matplotlib,我一共安装了6个包:

  • matplotlib-1.4.2.win-amd64-py2.7
  • numpy-MKL-1.9.1.win-amd64-py2.7
  • pyparsing-2.0.3.win-amd64-py2.7
  • python-dateutil-2.2.win-amd64-py2.7
  • scipy-0.15.0b1.win-amd64-py2.7
  • six-1.8.0.win-amd64-py2.7

在Ubuntu Linux上安装

在Ubuntu上安装可就简单多了,软件源里就包括这两个包,一句话搞定:

sudo apt-get install python-numpy python-matplotlib

所有依赖的包都自动安装上了,给个赞!
真心说一句,Ubuntu除了网络问题更新软件不给力之外,装软件真心是很方便、很赞的!

通用方法

其实只要用Python都可以用Python包管理工具pip,两句命令即可搞定:

pip install numpy
pip install matplotlib

而安装pip依赖于setuptools,可以点击setuptoolspip来进行下载安装。

测试代码

安装完成后,可以使用引自此页面的代码进行测试。

import numpy as np
import matplotlib.pyplot as plt

N = 5
menMeans = (20, 35, 30, 35, 27)
menStd =   (2, 3, 4, 1, 2)

ind = np.arange(N)  # the x locations for the groups
width = 0.35       # the width of the bars

fig, ax = plt.subplots()
rects1 = ax.bar(ind, menMeans, width, color='r', yerr=menStd)

womenMeans = (25, 32, 34, 20, 25)
womenStd =   (3, 5, 2, 3, 3)
rects2 = ax.bar(ind+width, womenMeans, width, color='y', yerr=womenStd)

# add some
ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.set_xticks(ind+width)
ax.set_xticklabels( ('G1', 'G2', 'G3', 'G4', 'G5') )

ax.legend( (rects1[0], rects2[0]), ('Men', 'Women') )

def autolabel(rects):
    # attach some text labels
    for rect in rects:
        height = rect.get_height()
        ax.text(rect.get_x()+rect.get_width()/2., 1.05*height, '%d'%int(height),
                ha='center', va='bottom')

autolabel(rects1)
autolabel(rects2)

plt.show()

参考文献

查阅到了几篇不错的博客和网站可以用大家参考一下:

设计模式——六大设计原则

六大设计原则

  1. 单一职责原则
  2. 里氏替换原则
  3. 依赖倒置原则
  4. 接口隔离原则
  5. 迪米特法则
  6. 开闭原则

1 单一职责原则(Single Responsibility Principle)

单一职责,简称SRP。单一职责的定义是:应该有且仅有一个原因引起类的改变。单一职责最难划分的就是职责,一个职责一个接口,但是职责的划分因项目而异。对于接口,我们在设计的时候一定要做到单一,但是对于实现类尽量做到只有一个原因引起变化。实现类生搬硬套单一职责会引起类的剧增。

2 里氏替换原则(Liskov Substitution Principle)

里氏替换原则,简称LSP。通俗来讲,只要父类能出现的地方子类就能出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本不需要知道是父类还是子类。但是有子类出现的地方,父类未必能适应。

里氏替换原则包含四重含义:

1) 子类必须完全实现父类的方法。在类中调用其他类时务必使用父类或接口,如果不能使用父类或接口,则说明违背了LSP原则。

2) 子类可以有自己的个性。

3) 覆盖或实现父类的方法时参数可以被放大。里氏替换原则要求制定一个契约,就是父类或者接口,这种设计方法也叫做Design by Contract (契约设计),与里氏替换原则有着异曲同工之妙。子类中方法的前置条件必须与超类中被覆写的方法的前置条件相同或者更宽松。

4) 覆写或实现父类的方法时输出结果可以被缩小。

3 依赖倒置原则(Dependence Inversion Principle)

依赖倒置原则,简称DIP。其含义为:高层模块不应依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。更加精简的定义就是“面向接口编程”。

两个类之间有依赖关系,只要制定出两者之间的接口(或抽象类)就可以独立开发了,而且项目之间的单元测试也可以独立得运行,而TDD (Test-Driven Development,测试驱动开发) 开发模式就是依赖倒置原则的最高级应用。

抽象是对实现的约束,对依赖者而言,也是一种契约。不仅约束自己,还同时约束自己与外部的关系,其目的是保证所有的细节不脱离契约的范畴,确保约束双方按照既定的契约(抽象)共同发展。

依赖传递的三种方法:

1) 构造函数传递依赖对象。在类中通过构造函数声明依赖对象,按照依赖注入的说法这种方式叫做构造函数注入。

2) Setter方法传递依赖对象。在抽象中设置Setter方法声明依赖关系,也可称为Setter依赖注入。

3) 接口声明依赖对象,也称为接口注入。

依赖倒置原则的本质就是通过抽象(接口或者抽象类)使各个类或模块的实现彼此独立,不相互影响,实现模块间的松耦合。我们可以遵循以下规则:每个类尽量有接口或者抽象类,或者两者都具备;变量的声明类型尽量是接口或者抽象类;任何类都不应从具体类派生;尽量不要覆写基类方法;结合里氏替换原则可以得到如下规则:接口负责定义public属性和方法,并且声明与其他对象的依赖关系,抽象类负责公共构造部分的实现,实现类准确地实现业务逻辑,同时在适当的时候对父类进行细化。

4 接口隔离原则(Interface Segregation Principle)

接口隔离原则,其含义为:客户端应该依赖它需要的接口,仅提供需要的接口,剔除不需要的,细化需要的接口,保证其纯洁性。接口中的方法应该尽量少。

单一职责要求的是类和接口职责单一,注重的是职责,这是逻辑业务上的划分,而接口隔离原则要求接口方法尽量少。

保证接口的纯洁性要求

1) 接口尽量小。根据接口隔离原则拆分接口时,首先必须满足单一职责原则。

2) 接口要高内聚。在接口中尽量少公布public方法,接口是对外的承诺,承诺越少对开发越有利,变更风险越小,同时有利于降低成本。

3) 定制服务。单独为一个个体提供优良的服务,只提供访问者需要的方法。

4) 接口设计是有限度的。接口设计的粒度要适度。

5 迪米特法则(Law of Demeter)

迪米特法则,简称LoD,也被称为最少知识原则(Least Knowledge Principle,LKP)。一个类应该对自己耦合或调用的类知道得最少。

迪米特法则要求尽量不要对外公布太多的public方法和非静态的public方法,多使用private、package-private、protected等访问权限。

如果一个方法放在本类中,既不增加类间关系,也不对本类产生负面影响,那么就放置在本类中。

迪米特法则的核心就是类间解耦,弱耦合。只有弱耦合以后,类的复用率才能提高。其要求的结果就是产生大量的中转或者跳转类,导致系统的复杂度提高,同时也为维护带来难度。

6 开闭原则(Open Closed Principle)

开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

开闭原则对扩展开放,对修改关闭,并不意味着不做任何修改,低层模块修改必然有高层模块耦合,否则就是一段无意义的代码。

变化可以归纳为三种类型:

1) 逻辑变化。只变化一个逻辑,而不涉及其他模块,可以通过修改原有类中的方法来实现。前提条件是所有依赖或者关联类都按照相同的逻辑处理。

2) 子模块变化。低层次模块的变化必然引起高层次模块的变化。因此在通过扩展完成变化时,高层次的模块修改是必然的。

3) 可见视图的变化。

如何使用开闭原则:

1) 抽象约束。通过接口或抽象类可以约束一组可能变化的行为,并且能够实现开放。其包含三层含义:第一,通过接口和抽象类对扩展进行边界的限定,不允许出现在接口或抽象类中不存在的public方法;第二,参数类型、引用对象尽量使用接口或者抽象类而不是实现类;第三,抽象层保持稳定,一旦确定就不允许修改。

2) 元数据(metadata)控制模块行为。

3) 制定项目章程。

4) 封装变化。

《Pro Git》学习笔记

1.Git远程模型示意图

git_model

Remote:远程仓库
Repository:本地仓库
Index:暂存区
workspace:当前工作区

2.取得Git仓库

2.1 初始化新仓库

git init

2.2 从现有仓库克隆

git clone git://github.com/xxx/xxx.git [dirName]

3.记录每次更新到仓库

3.1 文件状态变化周期

lifecircle

3.2 检查当前文件的状态

git status

3.3 跟踪新文件

git add

3.4 更新已放到暂存区但是之后被修改的文件

git add

3.5 查看已暂存和未暂存的更新

git diff 查看工作区与暂存区的差异
git diff –cached 已暂存的文件与上次提交之间的差别

3.6 提交更新

git commit 或者 git commit -m “具体说明”

3.7 跳过暂存区直接更新

git commit -a -m “更新说明”

3.8 删除文件

git rm <文件名>

如果删除之前已经修改过并且放到了暂存区,那么使用-f选项来强制删除暂存区中的文件。该参数用来防止误删文件后丢失修改的内容。

3.9 移除对文件的跟踪但是不删除文件

git rm –cached <文件名>

删除的时候如果在“*”号前面加“\”那么就会递归删除当前目录下所有匹配的文件,例如:git rm *.tmp。

3.10 移动文件

git mv <文件1> <文件2> 相当于先删除文件1,然后增加文件2

4.查看提交的历史

git log

常见用法:

4.1 展开内容差异

git log -p -2 (-p 展开每次提交的内容差异,用-2表示仅显示最近的两次更新)

4.2 仅显示简要的增改行数统计

git log –stat

4.3 指定格式展示提交历史

git log –pretty=oneline (将每个提交放在一行显示,还有short、full、fuller可以用)

4.4 定制记录格式

git log –pretty=format:”%h – %an, %ar : %s” ,常用格式占位符的写法及意义为:

选项 说明
%H 提交对象(commit)的完整哈希字串
%h 提交对象的简短哈希字串
%T 树对象(tree)的完整哈希字串
%t 树对象的简短哈希字串
%P 父对象(parent)的完整哈希字串
%p 父对象的简短哈希字串
%an 作者(author)的名字
%ae 作者的电子邮件地址
%ad 作者修订日期(可以用 -date= 选项定制格式)
%ar 作者修订日期,按多久以前的方式显示
%cn 提交者(committer)的名字
%ce 提交者的电子邮件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式显示
%s 提交说明
4.5 限制筛选条件

git log –[n|since|after|until|author|committer] ,选项说明:

选项 说明
-(n) 仅显示最近的 n 条提交
–since, –after 仅显示指定时间之后的提交
–until, –before 仅显示指定时间之前的提交
–author 仅显示指定作者相关的提交
–committer 仅显示指定提交者相关的提交

5、撤销操作

5.1 修改最后一次提交

git commit -m “initial commit”
git add forgotten_file
git commit –amend

5.2 取消已暂存的文件

git reset HEAD <文件名>

5.3 取消对文件的修改

git checktout — <文件名>

6.远程仓库

6.1 查看当前远程仓库

git remote [-v]

6.2 添加远程仓库

git remote add <远程仓库名> <远程仓库地址>

6.3 从远程仓库抓取数据

git fetch <远程仓库名>

如果是克隆了一个仓库,此命令会自动将远程仓库归于 origin 名下。所以,git fetch origin 会抓取从你上次克隆以来别人上传到此远程仓库中的所有更新(或是上次 fetch 以来别人提交的更新)。有一点很重要,需要记住,fetch 命令只是将远端的数据拉到本地仓库,并不自动合并到当前工作分支,只有当你确实准备好了,才能手工合并。

如果设置了某个分支用于跟踪某个远端仓库的分支(参见下节及第三章的内容),可以使用 git pull 命令自动抓取数据下来,然后将远端分支自动合并到本地仓库中当前分支。在日常工作中我们经常这么用,既快且好。实际上,默认情况下git clone 命令本质上就是自动创建了本地的 master 分支用于跟踪远程仓库中的 master 分支(假设远程仓库确实有 master 分支)。所以一般我们运行git pull,目的都是要从原始克隆的远端仓库中抓取数据后,合并到工作目录中的当前分支。

6.4 推送数据到远程仓库

git push [远程仓库名] [分支名]

6.5 查看远程仓库信息

git remote show [远程仓库名]

6.6 远程仓库的删除和重命名

git remote rename <旧仓库名> <新仓库名>

7.打标签

在发布某个软件版本的时候使用Git对某一时间点上的版本打上标签。

7.1 查看已有标签

git tag [-l <标签模式>]

例如:git tag -l ‘v1.4.2.*’

7.2 新建标签

Git 使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated)。轻量级标签就像是个不会变化的分支,实际上它就是个指向特 定提交对象的引用。而含附注标签,实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,标签本身也允许使用 GNU Privacy Guard (GPG) 来签署或验证。一般我们都建议使用含附注型的标签,以便保留相关信息;当然,如果只是临时性加注标签,或者不需要旁注额外信息,用轻量级标签也没问题。

含附注的标签:
git tag -a <标签名> [-m <标签说明>]

-a选项指定含附注类型,-m选项指定标签说明。

轻量级标签:
git tag <标签名>

7.3 签署标签

利用私钥和GPG来签署标签。
git tag -s <签名> [-m <标签说明>]

7.4 验证标签

git tag -v <标签名>

需要有签署者的公钥存放在keyring中。

7.5 后期加注标签

git tag -v <标签名> <校验和前几位>

7.6 分享标签

git push <远程仓库名> <标签名>

8.分支理论

commit对象指向包含各个文件blob对象索引的tree对象。Git分支的本质是个指向commit对象的可变指针,Git使用master作为分支的默认名字。Git通过创建一个新的分支指针来创建新的分支:git branch <分支名>。

HEAD是一个指向正在工作中的本地分支的指针,可以将其当做当前分支的别名。

8.1 将HEAD切换到其他分支

git checktout <分支名>

切换分支的时候最好保持一个清洁的工作区域。

8.2 分支的新建与切换

git checkout -b <新分支名>
相当于:
git branch <新分支名>
git checkout <新分支名>

8.3 分支的合并

假设要将分支hotfix合并到分支master,首先检出master分支,然后合并分支。
git checkout master
git merge hotfix

8.4 删除分支

git branch -d <分支名>

8.5 查看所有分支

git branch [-v|–merged|–on-merged]
-v选项用来查看各分支最后一个commit的信息,–merged用来查看哪些分支已经并入当前分支。

8.6 利用分支来进行开发工作

长期分支(master):例如master分支,保留完全稳定的代码,稳定的分支总是比较老旧。
开发分支(develop):与master平行的专门用于后续开发或者稳定性测试的分支。
特性分支(topic):短期的用来实现单一特性的分支。
branches

8.7 远程分支

远程分支(remote branch)是对远程仓库中分支的索引。它们是无法移动的本地分支,只有在Git进行网络交互时才会更新。远程分支一般用<远程仓库名>/<分支名>这样的形式来表示。

一次Git克隆会建立本地分支master和远程分支origin/master,它们都指向origin/master分支的最后一次提交。

(1)同步远程服务器上的数据:git fetch origin。该命令首先找到origin服务器,从上面获取数据然后把origin/master的指针移动到最新的位置。

(2)推送本地分支:git push <远程仓库名> <本地分支名>[:<远程分支名>]。如果不指定<远程分支名>,那么会使用与本地分支相同的名字。

(3)值得注意的是,即使用fetch操作获取了新的远程分支,任然无法在本地编辑远程仓库的分支,如果要把远程分支的内容合并到当前分支,可以使用:git merge <远程仓库名>/<远程分支名>。

(4)如果想要自己的可编辑分支,可以在远程分支的基础上分化出一个新的分支来:git checkout -b <新分支名> <远程仓库名>/<远程分支名>。从远程分支中checkout出来的本地分支称为跟踪分支,跟踪分支是一种和某个远程分支有直接联系的本地分支。在跟踪分支里输入 git push,Git会自行推断该向哪个服务器的哪个分支推送数据。同样在跟踪分支里运行 git pull 会获取远程索引并把它们的数据都合并到本地分支中来。

(5)删除远程分支:git push <远程仓库名> :<远程分支名>

8.8 分支的衍合

把一个分支整合到另一个分支的办法有两种:merge 和 rebase(暂译为衍合)。merge的原理是将两个分支最新的快照以及二者最新的共同祖先进行三方合并,然后生成一个新的提交对象。rebase的原理是:假设有两个分支 experiment 和 master,experiment是我们要衍合的分支。先回到两者的共同祖先,依据 experiment 后续的历次提交产生一系列补丁,然后以基底分支 master 的最后一个提交对象为新的出发点,逐个应用之前准备好的补丁文件,最后会产生一个新的合并提交对象,改写experiment的提交历史。其命令表示为:

git checkout experiment
git rebase master
experiment

rebase 和 merge 最后得到的快照内容是相同的,但 rebase 能够提供更为简洁的提交历史。一般我们使用衍合的目的,是想要得到一个能在远程分支上干净应用的补丁 — 比如某些项目你不是维护者,但想帮点忙的话,最好用衍合:先在自己的一个分支里进行开发,当准备向主项目提交补丁的时候,根据最新的 origin/master 进行一次衍合操作然后再提交,这样维护者就不需要做任何整合工作(译注:实际上是把解决分支补丁同最新主干代码之间冲突的责任,化转为由提交补丁的人来解决),只需根据你提供的仓库地址作一次快进合并,或者直接采纳你提交的补丁。

衍合也可以放到其他分支进行,并不一定非得根据分化之前的分支。以图 3-31 的历史为例,我们为了给服务器端代码添加一些功能而创建了特性分支 server,然后提交 C3 和 C4。然后又从 C3 的地方再增加一个 client 分支来对客户端代码进行一些相应修改,所以提交了 C8 和 C9。最后,又回到 server 分支提交了 C10。
3_31
图 3-31. 从一个特性分支里再分出一个特性分支的历史。

假设在接下来的一次软件发布中,我们决定先把客户端的修改并到主线中,而暂缓并入服务端软件的修改(因为还需要进一步测试)。这个时候,我们就可以把基于 server 分支而非 master 分支的改变(即 C8 和 C9),跳过 server 直接放到 master 分支中重演一遍,但这需要用 git rebase 的 –onto 选项指定新的基底分支 master:

$ git rebase –onto master server client
这好比在说:“取出 client 分支,找出 client 分支和 server 分支的共同祖先之后的变化,然后把它们在 master 上重演一遍”。是不是有点复杂?不过它的结果如图 3-32 所示,非常酷(译注:虽然 client 里的 C8, C9 在 C3 之后,但这仅表明时间上的先后,而非在 C3 修改的基础上进一步改动,因为 server 和 client 这两个分支对应的代码应该是两套文件,虽然这么说不是很严格,但应理解为在 C3 时间点之后,对另外的文件所做的 C8,C9 修改,放到主干重演。):
3_32
图 3-32. 将特性分支上的另一个特性分支衍合到其他分支。

现在可以快进 master 分支了(见图 3-33):

$ git checkout master
$ git merge client
3_33

图 3-33. 快进 master 分支,使之包含 client 分支的变化。

现在我们决定把 server 分支的变化也包含进来。我们可以直接把 server 分支衍合到 master,而不用手工切换到 server 分支后再执行衍合操作 — git rebase [主分支] [特性分支] 命令会先取出特性分支 server,然后在主分支 master 上重演:

$ git rebase master server
于是,server 的进度应用到 master 的基础上,如图 3-34 所示:
3_34
图 3-34. 在 master 分支上衍合 server 分支。

然后就可以快进主干分支 master 了:

$ git checkout master
$ git merge server
现在 client 和 server 分支的变化都已经集成到主干分支来了,可以删掉它们了。最终我们的提交历史会变成图 3-35 的样子:

$ git branch -d client
$ git branch -d server
3_35

图 3-35. 最终的提交历史

rebase的风险:一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行rebase操作。