webdancer's Blog

python科学计算——numpy

numpy是python进行科学计算的一个基础包,它的核心功能是提供ndarray对象,一个实现了n维数组的对象,与python自带的list相比,数组大小初始化时候确定,而且是单一类型(当然也可以使用 对象,这样也能包含多种对象),速度更快,大多数科学计算的程序可能都是基于numpy的。

1.基本的思想有两个:vectorization和broadcasting.

  • vectorization:说的是可以不适用for,而像线性代数里面提供的操作一样进行计算;
  • broadcasting:指的是对于element-by-element的计算,可以自动进行;

2.数据类型:支持丰富的数值类型,如下:

Data type Description
bool_ Boolean (True or False) stored as a byte
int_ Default integer type (same as C long; normally either int64 or int32)
intc Identical to C int (normally int32 or int64)
intp Integer used for indexing (same as C ssize_t; normally either int32 or int64)
int8 Byte (-128 to 127)
int16 Integer (-32768 to 32767)
int32 Integer (-2147483648 to 2147483647)
int64 Integer (-9223372036854775808 to 9223372036854775807)
uint8 Unsigned integer (0 to 255)
uint16 Unsigned integer (0 to 65535)
uint32 Unsigned integer (0 to 4294967295)
uint64 Unsigned integer (0 to 18446744073709551615)
float_ Shorthand for float64.
float16 Half precision float: sign bit, 5 bits exponent, 10 bits mantissa
float32 Single precision float: sign bit, 8 bits exponent, 23 bits mantissa
float64 Double precision float: sign bit, 11 bits exponent, 52 bits mantissa
complex_ Shorthand for complex128.
complex64 Complex number, represented by two 32-bit floats (real and imaginary components)
complex128 Complex number, represented by two 64-bit floats (real and imaginary components)

3.创建数组:有5中基本的方式:

  1. Conversion from other Python structures (e.g., lists, tuples)
  2. Intrinsic numpy array array creation objects (e.g., arange, ones, zeros, etc.)
  3. Reading arrays from disk, either from standard or custom formats: genfromtxt
  4. Creating arrays from raw bytes through the use of strings or buffers
  5. Use of special library functions (e.g., random)

4.索引:

import numpy as np

x = np.arange(10)

x[0]  ##从零开始索引,返回0

x.shape = (2,5)

x[1,2] ##这是与python的list,tuple不同的地方,支持多维的索引,返回7

x[0]等价于x[0,:]

x.shape=(10)

x[2:5] #与python的list一样,支持切片操作;

5.broadcasting:描述的是在进行算术操作时,Array的大小不一致的情况,numpy如何处理;将短的进行扩展,然后进行处理。

>>> a = np.array([1.0, 2.0, 3.0])
>>> b = 2.0
>>> a * b
array([ 2.,  4.,  6.])

When operating on two arrays, NumPy compares their shapes element-wise. It starts with the trailing dimensions, and works its way forward. Two dimensions are compatible when

  1. they are equal, or
  2. one of them is 1

 

python的namespace问题

1.问题

写程序的时候,出现了一个bug,看了很久也没有发现问题。程序的逻辑模样大致如下所示:

for i in range(4):
    x = [ e**i for i, e in enumerate(range(5))] 
    y = 2 * i
    print y

如果对python很熟悉的,一眼就可以看出问题的所在。程序的原意是:y = 2 * i 这条语句中i与第一行中的i一致的,但是却使用了第二行中的i值,但是程序依然循环了四次。打印的结果是:

8
8
8
8 

这令人非常的疑惑,主要是在python 2,x中,list comprehension中的变量的scope没有仅限于‘[ ]’中,而是漏了出来。这的确有点不太符合逻辑,因为在理解上,‘[ ]’中的变量的scope仅限于里面,更加符合直观的感觉。

2.解决

解决的方法:

  1. 避免名字冲突就行了,比如把第二行的i换成j。
  2. 升级python的版本。在python 3.x中,这个问题就不存在了,list comprehension表达式有了自己的scope.(是不是应该升级到python 3了??但是好像一些包还是支持3.x不太好呀,囧。。。)

3.python 的namespace和scope

namespace就是一个从名字到对象的映射,现在的python好像就是用字典数据结构实现的。对于namespace注意的就是生命周期(lifetime)和作用域(scope)。所谓生命周期就是实现namespace的对象在内存中存在的时间,而作用域(scope)就是namespace在程序中起作用的文本区域。

生成毕业论文清单的python脚本

快乐的大学生活就要结束了,到了毕业季,大家在兴奋中有充满了伤感,不知道何时才能再度重逢,再像这样一起生活四年是不可能了。我们应该珍惜自己身边的朋友,也许有各种毛病,但是,是人就有毛病,没有的话,那就成神了。

闲话不说了,今天早上整理同学的论文,可能是自己没做好通知,大多数同学的文件名都有问题,非常蛋疼的一个一个的帮同学修改文件名。然后去教务处交上了,但是忘了做论文的清单了,难道又要一个一个的输吗?想了想,用python写个脚本吧。因为我已经手动的帮把文件名都改成了:学号_姓名的格式,刚开始的思路,只是将文件名和学号处理一下,让程序自动的把这学号和姓名写入xls文件;但是还有论文题目,指导老师,这两项还是要一个一个的输,看了看论文,尽管有的同学的首页有问题,但是大多数同学的首页都包含了这四种信息,那就不如直接处理word文件了,把信息提取出来,直接写入xls文件。

程序的思路:

  1. 使用win32com把word转为txt文件;
  2. 读取txt文件,在前30行中搜索姓名,学号,题目,导师信息;
  3. 把提取的信息写入xls文件。

思路比较简单,程序写了一下午,主要是对win32com不熟悉,还有让人窒息的汉字编码问题,耗费了大多数时间。跑了一下,程序的效果还是比较好的,只有几个同学的文档没有按照学校给的模版写,没有抓到信息,其他的都搜到了。

 

# -*- coding: utf-8 -*-
import fnmatch, os, sys, win32com.client  
from tempfile import TemporaryFile
from xlwt import Workbook
# prepare xls file
book = Workbook(encoding='utf-8')
sheet1 = book.add_sheet('Sheet 1')
sheet1.write(0,0,'学号')
sheet1.write(0,1,'姓名')
sheet1.write(0,2,'论文题目')
sheet1.write(0,3,'专业')
sheet1.write(0,4,'指导老师')
sheet1.col(0).width = 5000
sheet1.col(1).width = 5000
sheet1.col(2).width = 10000
sheet1.col(3).width = 5000
sheet1.col(4).width = 5000

# retrive informatio from doc
index=1
wordapp = win32com.client.gencache.EnsureDispatch("Word.Application")  
try:  
      for path, dirs, files in os.walk(sys.argv[1]):  
            for filename in files:  
                  if fnmatch.fnmatch(filename, '*.doc'):
                      filetype=1
                  elif fnmatch.fnmatch(filename, '*.docx'): 
                      filetype=2
                  else:
                      continue
                  doc = os.path.abspath(os.path.join(path, filename))  
                  print "processing %s" % doc  
                  wordapp.Documents.Open(doc)  
                  if filetype==1:
                      docastxt = doc[:-3] + 'txt'  
                  else:
                      docastxt =doc[:-4]+'txt'
                  wordapp.ActiveDocument.SaveAs(docastxt,FileFormat=win32com.client.constants.wdFormatText)  
                  wordapp.ActiveDocument.Close( )  
                  f=open(docastxt,'r')
                  namefound=False
                  numberfound=False
                  titlefound=False
                  adfound=False
                  i=0
                  metadata=[u'prob']*5
                  for line in f:
                      line=unicode(line,'gbk')
                      i=i+1
                      if i>30:
                          break
                      if namefound and numberfound and adfound:
                          break
                      if titlefound:
                          metadata[2]=line.lstrip().rstrip()
                          titlefound=False
                          pass
                      if line.find(u'号')!=-1:
                          metadata[0]=line.split()[-1]
                          namefound=True
                      elif line.find(u'姓')!=-1:
                          metadata[1]=line.split()[-1]
                          numberfound=True
                      elif line.find(u'题目')!=-1:
                          titlefound=True
                      elif line.find(u'师')!=-1:
                          metadata[4]=line.split()[-1]
                          adfound=True
                  metadata[3]=u'计算机科学与技术'        
                  print 'number: %s, name: %s, title: %s,dap: %s, ad: %s'%(metadata[0],metadata[1],metadata[2],metadata[3],metadata[4])
                  for meta in range(5):
                      print index,meta
                      sheet1.write(index,meta,metadata[meta])
                  index+=1
                  f.close()
                  os.remove(docastxt)

      book.save('08_1_auto.xls')
      book.save(TemporaryFile())

finally:  
      # 确保即使有异常发生Word仍能被正常关闭  
      wordapp.Quit( ) 

python中迭代器和生成器


l=[1,2,3,4]

for n in l:
    print n

在看上面这段代码的时候,我们没有显式的控制列表的偏移量,就可以自动的遍历了整个列表对象。那么for 语句是怎么来遍历列表l的呢?要回答这个问题,我们必须首先来看一下迭代器相关的知识。

1.迭代器

迭代器对象要求支持迭代器协议,所谓支持迭代器协议就是对象包含__iter__()和next()方法。其中__iter__()方法返回迭代器对象自己;next()方法返回下一个前进到下一个结果,在结尾时引发StopIteration异常。

列表不是迭代器对象,但是列表通过__iter__()可以得到一个迭代器对象来遍历整个列表的内容,像列表这样的序列对象都属于这种情况;与序列不同,文件对象本身就是一种迭代器对象。

l=[1,2,3,4]
f=open('test.c','r')

iter(l) == l
Out[131]: False

iter (f)== f
Out[132]: True

一个迭代器的例子(来源:python tutorial)

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __iter__(self):
        return self
    def next(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]

2.生成器

生成器使python可以很容易的支持迭代协议。生成器通过生成器函数产生,生成器函数可以通过常规的def语句来定义,但是不用return返回,而是用yeild一次返回一个结果,在每个结果之间挂起和继续它们的状态,来自动实现迭代协议。

一个生成器的例子(来源:python tutorial)

def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]

3.for语句如何工作

在我们最前面的遍历列表的for语句中,for使用了列表支持迭代器的性质,可以每次通过调用迭代器的next()方法,来遍历到列表中的值,直到遇到StopIteration的异常。

4.注意的问题:

  1. 像列表这种序列类型的对象,我们可以通过iter()来产生多个迭代器,在迭代的过程中各个迭代器相互对立;但是迭代器对象没法通过iter()方法来产生多个不同的迭代器,它们都指向了自身,所以没法独立使用。

参考: python tutorial, stackoverflow

 

python的字典类型

前几天复习了hash的相关知识,正好在做udacity的CS101课程用到了python里面的字典,正好复习一下python的字典知识。

1.字典类型基础

python中的字典(dictionary)是一种映射类型,它不同于列表(list)这样的序列类型,它不是以偏移来存取,而是以键来存储,所以字典不支持切片这样的列表操作。

键的类型可以是数字,字符串,不包含可变对象的元组,不能使列表。字典可以被看做一个无序的集合。

常见操作:

1.新建字典;2.添加(键,值)对;3删除(键,值)对;4.由键查找对应的值;5.键,值上循环。

>>> tel = {'jack': 4098, 'sape': 4139}
>>> tel['guido'] = 4127
>>> tel
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>>> tel['jack']
4098
>>> del tel['sape']
>>> tel['irv'] = 4127
>>> tel
{'guido': 4127, 'irv': 4127, 'jack': 4098}
>>> tel.keys()
['guido', 'irv', 'jack']
>>> 'guido' in tel
True

注意问题:序列运算无效;对新键赋值会创建新的项;键值的类型可以不同;避免keyError。

2.为什么列表不能做键

python使用开放散列数据结构实现的。不管是用列表的id还是用列表的内容用来散列,都是符合散列函数的定义的(不同的散列值,不同的键值)。但是这两种方式都存在一些问题:

  1. 用id散列时,在用不同的键值(id不同),但是内容相同的列表查找时,尽管散列值不同,但是在用列表却相同(满足__equal__)。此外,还有就是列表时一个容器,如果用id散列,意义到底有多大呢?
  2. 用列表内容散列时,列表内容该更改后,我们会计算出不同的散列值,就会有不同的bucket。

总之,在python中,选择了列表不能做键的策略。我感觉就是既然tuple类型可以用内容来散列,那么我们就不用列表了,列表修改特性会使散列的维护变得很复杂(想想如果我们使用列表的内容散列了,而后我们修改了,我们自己都不知道以前是什么了?如果想要保存以前的内容,不是又做了copy,这样就不如直接用tuple类型了),从而使得这种常用的数据类型的性能出现问题。

注意:用户自定义类型都可以用作键。只要用对象id散列,比较函数用id进行比较。为什么在列表中不可以,但是在自定义类型中就行?一个主要的原因就是对放在字典中的自定义类型来说,id重要,有了id就可以找到内容了。

#转帖#成为Python高手

本文是从 How to become a proficient Python programmer 这篇文章翻译而来。

这篇文章主要是对我收集的一些文章的摘要。因为已经有很多比我有才华的人写出了大量关于如何成为优秀Python程序员的好文章。
 
我的总结主要集中在四个基本题目上:函数式编程,性能,测试,编码规范。如果一个程序员能将这四个方面的内容知识都吸收消化,那他/她不管怎样都会有巨大的收获。
 
  • 函数式编程
命令式的编程风格已经成为事实上的标准。命令式编程的程序是由一些描述状态转变的语句组成。虽然有时候这种编程方式十分的有效,但有时也不尽如此(比如复杂性)——而且,相对于声明式编程方式,它可能会显得不是很直观。
 
如果你不明白我究竟是在说什么,这很正常。这里有一些文章能让你脑袋开窍。但你要注意,这些文章有点像《骇客帝国》里的红色药丸——一旦你尝试过了函数式编程,你就永远不会回头了。
 
http://www.amk.ca/python/writing/functional
http://www.secnetix.de/olli/Python/lambda_functions.hawk
http://docs.python.org/howto/functional.html
 
  • 性能
你会看到有如此多的讨论都在批评这些“脚本语言”(Python,Ruby)是如何的性能低下,可是你却经常的容易忽略这样的事实:是程序员使用的算法导致了程序这样拙劣的表现。
 
这里有一些非常好的文章,能让你知道Python的运行时性能表现的细节详情,你会发现,通过这些精炼而且有趣的语言,你也能写出高性能的应用 程序。而且,当你的老板质疑Python的性能时,你别忘了告诉他,这世界上第二大的搜索引擎就是用Python写成的——它叫做Youtube(参考Python摘录)
 
http://jaynes.colorado.edu/PythonIdioms.html
http://wiki.python.org/moin/PythonSpeed/PerformanceTips
 
  • 测试
如今在计算机科学界,测试可能是一个最让人不知所措的主题了。有些程序员能真正的理解它,十分重视TDD(测试驱动开发)和它的后继者 BDD(行为驱动开发)。而另外一些根本不接受,认为这是浪费时间。那么,我现在将告诉你:如果你不曾开始使用TDD/BDD,那你错过了很多最好的东 西!
 
这并不只是说引入了一种技术,可以替换你的公司里那种通过愚蠢的手工点击测试应用程序的原始发布管理制度,更重要的是,它是一种能够让你深入理 解你自己的业务领域的工具——真正的你需要的、你想要的攻克问题、处理问题的方式。如果你还没有这样做,请试一下。下面的这些文章将会给你一些提示:
 
http://www.oreillynet.com/lpt/a/5463
http://www.oreillynet.com/lpt/a/5584
http://wiki.cacr.caltech.edu/danse/index.php/Unit_testing_and_Integration_testing
http://docs.python.org/library/unittest.html
 
  • 编码规范
并非所有的代码生来平等。有些代码可以被另外的任何一个好的程序员读懂和修改。但有些却只能被读,而且只能被代码的原始作者修改——而且这也只是在他或她写出了这代码的几小时内可以。为什么会这样?因为没有经过代码测试(上面说的)和缺乏正确的编程规范。
 
下面的文章给你描述了一个最小的应该遵守的规范合集。如果按照这些指导原则,你将能编写出更简洁和漂亮的代码。作为附加效应,你的程序会变得可读性更好,更容易的被你和任何其他人修改。
 
http://www.python.org/dev/peps/pep-0008/
http://www.fantascienza.net/leonardo/ar/python_best_practices.html
 
那就去传阅这这些资料吧。从坐在你身边的人开始。也许在下一次程序员沙龙或编程大会的时候,也已经成为一名Python编程高手了!
 
祝你学习旅途顺利。
 
如果你喜欢这些文章,请在微博上顶一下,让其他人也知道。来自: 外刊IT评论
 
注:本文从丕子学长blog看到的,他的博客里面内容很丰富,大家可以看一下
 

python连接MySQL数据库

python连接MySQL可以使用MySQLdb,数据库API规范可以参考PEP249,描述了类和应具有的属性和方法。MySQL的操作可以参考MySQL tutorial。

1.环境配置。

在Ubuntu11.10下面,自带python,但是没有MySQL,MySQLdb,所以首先安装MySQL,MySQLdb.

sudo apt-get install mysql-server
sudo apt-get install python-mysqldb

2.熟悉MySQL的基本操作。

连接Server:

mysql -h host -u user -p

输入Queries:

select version();

创建,使用database:

create database students;
use students;

查看数据库,表:

show databases;
show tables;

创建表:

create table webgrades(class varchar(10),number varchar(15), name varchar(20),grade int);

向表插入内容:

insert into webgrades values ('1','001','Justin',76);

从表查找内容:

select * from webgrades;

更多的内容参考MySQL tutorial。

3.python使用MySQLdb连接Server。

#! /usr/bin/env python
# -*- coding: utf8 -*-
import MySQLdb

#connect to the server
con=MySQLdb.connect(host='localhost',user='root',passwd='qweqwe',db='students')
#get cursor
cursor=con.cursor()
#execute the sql
operator="""insert into webgrades values (%s,%s,%s,%s)"""
para=[('1','200201000101','王丽',95),
      ('2','200201000201','赵宝刚',88),
      ('3','200201000301','杜玉',92)
      ]
cursor.executemany(operator,para)

#close the connection
con.close()

当然,更多的有关python连接数据库的知识参考python.org。

强连通分支

 

#!/usr/bin/python
class Graph:
	def __init__(self,nv):
		self.v=nv
		self.e=0
		self.adj=[]
		for ele in range(nv):
			self.adj.append([])
			ele+=1
	
	def insert(self,e):
		u=e[0]
		v=e[1]
		self.adj[u].append(v)
		#self.adj[v].append(u) 
		self.e+=1

	def dfs(self):
		global p
		global c
		global d
		global f
		global time
		global t
		p=[]
		c=[]
		d=[]
		f=[]
		t=[]
		for ele in range(self.v):
			ele+=1
			p.append(-1)
			c.append(0)
			d.append(0)
			f.append(0)
			t.append(0)
		time=0
		m=0
		for elev in range(self.v):
			if c[elev] == 0:
				self.dfs_visit(elev,m)
	
	def dfs_visit(self,u,m):
		global time
		c[u]=1
		t[u]=m
		time+=1
		d[u]=time
		for v in self.adj[u]:
			if c[v] == 0:
				p[v]=u
				t[v]=m
				self.dfs_visit(v,m)
		c[u]=2
		time+=1
		f[u]=time

	
	'''def printpath(self,s,v):
		if s==v:
			print s,
		elif p[v]==-1:
			print 'no path',
		else:
			self.printpath(s,p[v])
			print v,'''
def scc(g):
	g.dfs()
	gt=Graph(g.v)
	for u in range(len(g.adj)):
		for v in g.adj[u]:
			gt.adj[v].append(u)
		u+=1
	f1=[]
	for e in f:
		f1.append(e)
	for i in range(gt.v):
		p[i]=-1
		c[i]=0
		d[i]=0
		f[i]=0
		t[i]=0
	print c
	time=0
	global m
	m=0
	for i in range(gt.v):
		v=max(f1)
		fi=f1.index(v)
		if c[fi] == 0:
			m+=1
			gt.dfs_visit(fi,m)
		f1[fi]=-1

if __name__=='__main__':
	g=Graph(8)
	e=[(0,1),(1,2),(1,4),(1,5),(2,3),(2,6),(3,2),(3,7),(4,0),(4,5),(5,6),(6,5),(6,7),(7,7)]
	for each in e:
		g.insert(each)
	scc(g)
	print t
	for i in range(m+1):
		for v in range(g.v):
			if t[v]==i+1:
				print v,
		print '\n'

 




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee