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中基本的方式:
- Conversion from other Python structures (e.g., lists, tuples)
- Intrinsic numpy array array creation objects (e.g., arange, ones, zeros, etc.)
- Reading arrays from disk, either from standard or custom formats: genfromtxt
- Creating arrays from raw bytes through the use of strings or buffers
- 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
- they are equal, or
- 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.解决
解决的方法:
- 避免名字冲突就行了,比如把第二行的i换成j。
- 升级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文件。
程序的思路:
- 使用win32com把word转为txt文件;
- 读取txt文件,在前30行中搜索姓名,学号,题目,导师信息;
- 把提取的信息写入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.注意的问题:
- 像列表这种序列类型的对象,我们可以通过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还是用列表的内容用来散列,都是符合散列函数的定义的(不同的散列值,不同的键值)。但是这两种方式都存在一些问题:
- 用id散列时,在用不同的键值(id不同),但是内容相同的列表查找时,尽管散列值不同,但是在用列表却相同(满足__equal__)。此外,还有就是列表时一个容器,如果用id散列,意义到底有多大呢?
- 用列表内容散列时,列表内容该更改后,我们会计算出不同的散列值,就会有不同的bucket。
总之,在python中,选择了列表不能做键的策略。我感觉就是既然tuple类型可以用内容来散列,那么我们就不用列表了,列表修改特性会使散列的维护变得很复杂(想想如果我们使用列表的内容散列了,而后我们修改了,我们自己都不知道以前是什么了?如果想要保存以前的内容,不是又做了copy,这样就不如直接用tuple类型了),从而使得这种常用的数据类型的性能出现问题。
注意:用户自定义类型都可以用作键。只要用对象id散列,比较函数用id进行比较。为什么在列表中不可以,但是在自定义类型中就行?一个主要的原因就是对放在字典中的自定义类型来说,id重要,有了id就可以找到内容了。
#转帖#成为Python高手
本文是从 How to become a proficient Python programmer 这篇文章翻译而来。
- 函数式编程
- 性能
- 测试
- 编码规范
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'