a = 10
type(a) # int
# 调用 blt_length 方法, 获得表现 int 对象所需的位数
a.bit_length() # 4
a = 100000
# 对象所赋的整数值越大, 需要的位数越多
a.bit_length() # 17
googol = 10 ** 100
googol.bit_length() # 333
type(1 / 4) # float
b = 0.35
type(b) # float
b + 0.1 # 0.44999999999999996
出现以上结果的原因是浮点数在内部以二进制形式表:也就是说. 十进制数 n ( O
c = 0.5
c.as_integer_ratio() # (1, 2)
as_integer_ratio()将一个float用分数表示出来,返回的是一个二元元组
0.5可以精确保存. 因为它具备精确(有限)的二进制表示:0.5=1/2。但是. b=0.35和预期的实数0.35=7/20不同:
b.as_integer_ratio() # (3152519739159347, 9007199254740992)
精度取决于表示数值所用的位数。 一般说, Python运行的所有平台使用IEEE 754双精度标准( 64 位)作为内部表示。这相当于 15 位数字的相对精度。由于这个主题在多个金融应用领域中都很重要。有时候必须确保数值的精确(至少尽可能达到最佳)。例如,在加总一组数量很多的数值时, 这个问题就可能很重要。在这种情况下。某个种类或者幅度的表示误差可能汇聚起,造成和基准值的显著偏差。
decimal 模块为浮点数提供了任意精确度的对象,以及使用这些数值时处理精度问题的多个选项:
import decimal
from decimal import Decimal
decimal.getcontext()
# context(prec:2a, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999,999, capitals=l, flags=[], traps=[Overflow, InvalidOperation, DivisionsyZero])
d = Decimal(1) / Decimal(11) # Decimal('0.09090909090909090909090909091')
decimal.getcontext().prec = 4 # lower precision tha.n default
e = Decimal(1) / Decimal(11) # Decimal('0.09091')
decimal.getcontext().prec = 50 # higher precision than default
f = Decimal(1) / Decimal(11) # Decimal('0.090909090909090909090909090909090909090909090909091')
g = d + e + f # Decimal('0.27272818181818181818181818181909090909090909090909')
t = 'this is a string object'
t.capitalize() # 'This is a string object'
t.split() # ['this', 'is', 'a', 'string', 'object']
t.find('string') # 10
t.find('Python') # -1
t.replace(' ', '|') # 'this|is|a|string|object'
'http://www.python.org'.strip('htp:/') # 'www.python.org'
精选字符串方法
方法 | 参数 | 返回/结果 |
---|---|---|
cpitalize | () | 复制字符串,将第一个字符改成大写 |
count | sub[,star[,end]]) | 计算子字符串出现的次数 |
decode | [encoding[,errors]]) | 用encoding指定的编码方式(例如UTF-8)解码字将串 |
encode | ([encoding[,errors]]) | 字符串编码形式 |
find | (sub[,start[,end]]) | 找到的子字符串(最低)索引 |
join | (seq) | 连接seq序列中的字符串 |
replace | (old,new[,count]) 用new替换前count个old | |
split | ([sep[,maxsplit]]) | 字符串中的单词列表,以sep作为分隔符 |
splitlines | ([keepends]) | 如果keepends为真,以行结束符/换行符分隔的行 |
strip | (chars) | 从字符串首/尾删除chars中的字符 |
upper | () | 复制字符串 , 所有字母政为大写 |
正则表达式
import re
series = """
'01/18/2014 13:00:00',100,'1st;
'01/18/2014 13:30:00',110,'snd;
'01/18/2014 14:00:00',120,'3rd;
"""
dt = re.compile("'[0-9/:\s]+'") # 正则两边的单引号必须有,不然匹配的结果都散了
result = dt.findall(series)
# ["'01/18/2014 13:00:00'", "'01/18/2014 13:30:00'", "'01/18/2014 14:00:00'"]
from datetime import datetime
pydt = datetime.strptime(result[0].replace("'", ""), '%m/%d/%Y %H:%M:%S')
print(pydt) # 2014-01-18 13:00:00
元组(tple)是一种高级的数据结构,但是其应用仍然相当简单有限, 通过在圆括号
t = (1, 2.5, 'data')
type(t) # tuple
t = 1, 2.5, 'data' # 可以去掉括号
type(t) # tuple
# Python使用零起点编号,元组的第3个元素在索引位置2上
t[2] # 'data'
type(t[2]) # str
t.count('data') # 1
t.index('data') # 2
与元组对象相比,列表(list)类型的对象更灵活、更强大。从金融角度看,许多工作只能用列表对象完成,例如存储股票报价和附加新数据。列表对象通过方括号定义。基本功能和行为与元组类似:
l = [1, 2.5, 'data']
l.append([4, 3]) # [1, 2.5, 'data', [4, 3]]
l.extend([4, 3]) # [1, 2.5, 'data', [4, 3], 4, 3]
l.insert(1, 'insert') # [1, 'insert', 2.5, 'data', [4, 3], 4, 3]
l.append('data') # [1, 'insert', 2.5, 'data', [4, 3], 4, 3, 'data']
l.remove('data') # [1, 'insert', 2.5, [4, 3], 4, 3, 'data'] 移除了第一个匹配的,如果不存在会报错
p = l.pop(3)
print(l, p) # [1, 'insert', 2.5, 4, 3, 'data'] [4, 3]
del l[0] # ['insert', 2.5, 4, 3, 'data']
切片操作也很容易实现。这里的切片(Slicing)指的是将数据集分解为(感兴趣的)较小部分:
l = [1, 'insert', 2.5, 1.0, 1.5, 2.0]
l[2:5] # 3rd to 5th elements ['data', [4, 3], 4]
# [2.5, 1.0, 1.5]
精选的列表对象操作和方法
方法 | 参数 | 返回/结果 |
---|---|---|
l[i]=x | [i] | 用x代替第i个元素 |
l[i:j:k]=s | [i:j:k] | 用s代替从i到j-1号元素中的每第k个元素 |
append | (x) | 在对象后附加x |
count | (x) | 对象x出现的次数 |
del l[i:j:k] | [i:j:k] | 删除索引值从i到j-1号元素的每第k个元素 |
extend | (s) | 将s的所有元素附加到对象 |
index | (x[,i[,j]]) | 元素i和j-1之间第一个x的索引 |
insert | (i,x)++ | 在索引i之前插入x |
remove | (i) | 删除索引为i的元素 |
pop | (i) | 删除索引为i的元素并返回 |
reverse | () | 颠倒所有项目的顺序 |
sort | (cmp,[,key[,reverse]]) | 排序所有项目 |
l = [1, 'insert', 2.5, 1.0, 1.5, 2.0]
for element in l[2:5]:
print(element ** 2)
# 6.25
# 1.0
# 2.25
r = range(0, 8, 1) # start, end, step width
type(r) # range
list(r) # [0, 1, 2, 3, 4, 5, 6, 7]
for i in range(2, 5):
print(l[i] ** 2)
# 6.25
# 1.0
# 2.25
for i in range(1, 10):
if i % 2 == 0:
print('%d is even' % i)
elif i % 3 == 0:
print('%d is multiple of 3' % i)
else:
print('%d is odd' % i)
# 1 is odd
# 2 is even
# 3 is multiple of 3
# 4 is even
# 5 is odd
# 6 is even
# 7 is odd
# 8 is even
# 9 is multiple of 3
total = 0
while total < 100:
total += 1
print(total) # 100
m = [i ** 2 for i in range(5)] # [0, 1, 4, 9, 16]
Python也提供一些用于函数编程支持的工具一一即在一整组输入(在我们的例子中是列表对象)上应用某个函数。这些工具是过滤(filter)、映射(map)和归纳(reduce )。但是, 我们首先需要个函数定义。从简单的功能出发, 考虑返回输入 x 的平方数的函数 f:
def f(x):
return x ** 2
f(2) # 4
def even(x):
return x % 2 == 0
even(3) # False
m = map(even, range(10))
list(m) # [True, False, True, False, True, False, True, False, True, False]
m = map(lambda x: x ** 2, range(10))
list(m) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
f = filter(even, range(15))
list(f) # [0, 2, 4, 6, 8, 10, 12, 14]
# 在Python 3里,reduce()函数已经被从全局名字空间里移除了,它现在被放置在fucntools模块里用的话要 先引入
# from functools import reduce
from functools import reduce
reduce(lambda x, y: x + y, range(10)) # 45
# 下面是非函数式实现:
def cumsum(l):
total = 0
for elem in l:
total += elem
return total
cumsum(range(10)) # 45
字典(dict)对象就是可以按照键码(可能是字符串对象)读取的数据字典 , 也是一种可变序列. 是所谓的籍道存储。 列表对象是有序且可排序的. 而字典对象是元序 、 不可排序的。 示例最能够说明和列表对象的不同之处。 花括号是字典对象定义:
d = {
'Name': 'Angela Merkel',
'Country': 'Germany',
'Profession': 'Chancelor',
'Age': 60
}
type(d) # dict
print(d['Name'], d['Age']) # Angela Merkel 60
d.items()
# dict_items([('Name', 'Angela Merkel'), ('Country', 'Germany'), ('Profession', 'Chancelor'), ('Age', 60)])
birthday = True
if birthday is True:
d['Age'] += 1
print(d['Age']) # 61
for item in d.items():
print(item)
# ('Name', 'Angela Merkel')
# ('Country', 'Germany')
# ('Profession', 'Chancelor')
# ('Age', 61)
for value in d.values():
print(type(value))
# <class 'str'>
# <class 'str'>
# <class 'str'>
# <class 'int'>
字典对象精选操作和方法
方法 | 参数 | 返回/结果 |
---|---|---|
d[k] | [k] | d中键码为k的项目 |
d[k]=x | [k] | 将键码为k的项目设置为x |
del d[k] | [k] | 删除键码为k的项目 |
clear | () | 删除所有项目 |
copy | () | 创建一个拷贝 |
has_key | (k) | 如果k是一个键码,为真 |
items | () | 所有键-值对的拷贝 |
keys | () | 所有键码的拷贝 |
popitem | (k) | 返回并删除键码为k的项目 |
update | ([e]) | 用来自e的项目更新字典项目 |
values | () | 所有值得拷贝 |
这种对象是其他对象的无序集合, 每个元素只包含一次:
s = set(['u', 'd', 'ud', 'du', 'd', 'du']) # {'d', 'du', 'u', 'ud'}
t = set(['d', 'dd', 'uu', 'u'])
s.union(t) # all of s and t {'d', 'dd', 'du', 'u', 'ud', 'uu'}
s.intersection(t) # both in s and t {'d', 'u'}
s.difference(t) # in s but not t {'du', 'ud'}
t.difference(s) # {'dd', 'uu'}
s.symmetric_difference(t) # in either one but not both {'dd', 'du', 'ud', 'uu'}
from random import randint
l = [randint(0, 10) for i in range(1000)]
l[:20] # [6, 5, 4, 10, 1, 1, 6, 0, 2, 0, 5, 3, 3, 4, 6, 7, 2, 0, 3, 2]
s = set(l)
s # {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
v = [0.5, 0, 75, 1, 0, 1.5, 2.0] # vector of numbers
m = [v, v, v] # matrix of numbers
# [[0.5, 0, 75, 1, 0, 1.5, 2.0],
# [0.5, 0, 75, 1, 0, 1.5, 2.0],
# [0.5, 0, 75, 1, 0, 1.5, 2.0]]
m[1] # [0.5, 0, 75, 1, 0, 1.5, 2.0]
m[1][0] # 0.5
v1 = [0.5, 1.5]
v2 = [1, 2]
m = [v1, v2] # [[0.5, 1.5], [1, 2]]
c = [m, m] # cube of numbers [[[0.5, 1.5], [1, 2]], [[0.5, 1.5], [1, 2]]]
c[1][1][0] # 1
v = [0.5, 0, 75, 1, 0, 1.5, 2.0] # vector of numbers
m = [v, v, v] # matrix of numbers
# [[0.5, 0, 75, 1, 0, 1.5, 2.0],
# [0.5, 0, 75, 1, 0, 1.5, 2.0],
# [0.5, 0, 75, 1, 0, 1.5, 2.0]]
v[0] = 'Python'
m
# [['Python', 0, 75, 1, 0, 1.5, 2.0],
# ['Python', 0, 75, 1, 0, 1.5, 2.0],
# ['Python', 0, 75, 1, 0, 1.5, 2.0]]
# 使用copy模块的deepcopy函数可以避免这一现象
from copy import deepcopy
v = [0.5, 0.75, 1.0, 1.5, 2.0]
m = 3 * [deepcopy(v)]
m
# [[0.5, 0.75, 1.0, 1.5, 2.0],
# [0.5, 0.75, 1.0, 1.5, 2.0],
# [0.5, 0.75, 1.0, 1.5, 2.0]]
v[0] = 'Python'
m
# [[0.5, 0.75, 1.0, 1.5, 2.0],
# [0.5, 0.75, 1.0, 1.5, 2.0],
# [0.5, 0.75, 1.0, 1.5, 2.0]]
import numpy as np
a = np.array([0, 0.5, 1.0, 1.5, 2.0])
type(a) # numpy.ndarray
a[:2] # indexing as with list objects in 1 dimension
# array([ 0. , 0.5])
a.sum() # sum of all elements
# 5.0
a.std() # standard deviation
# 0.70710678118654757
a.cumsum() # running cumulative sum
# array([ e. , 0.5, 1.5, 3. , 5. ])
a * 2
# array([ 0., 1., 2., 3., 4.])
a ** 2
# array([ 0. , 0.25, 1. , 2.25, 4. ])
np.sqrt(a)
# array([ 0. , 0.70710678, 1. , 1.22474487, 1.41421356])
b = np.array([a, a * 2])
# array([[ 0. , 0.5, 1. , 1.5, 2. ],
# [ 0. , 1. , 2. , 3. , 4. ]])
b[0]
# array([ 0. , 0.5, 1. , 1.5, 2. ])
b[0, 2] # third element of first row
# 1.0
b.sum()
# 15.0
b.sum(axis=0)
# sum along axis 0, i.e. column-wise sum
# array([ 0. , 1.5, 3. , 4.5, 6. ])
b.sum(axis=1)
# sum along axis 11 i.e. row-wise sum
# array([ 5., 10.])
c = np.zeros((2, 3, 4), dtype='i', order='C')
# array([[[0, 0, 0, 0],
# [0, 0, 0, 0],
# [0, 0, 0, 0]],
# [[0, 0, 0, 0],
# [0, 0, 0, 0],
# [0, 0, 0, 0]]], dtype=int32)
d = np.ones_like(c, dtype='float16', order='C')
# array([[[ 1., 1., 1., 1.],
# [ 1., 1., 1., 1.],
# [ 1., 1., 1., 1.]],
# [[ 1., 1., 1., 1.],
# [ 1., 1., 1., 1.],
# [ 1., 1., 1., 1.]]], dtype=float16)
Numpy dtype 对象
dtype | 描述 | 示例 |
---|---|---|
t | 位域 | t4(4位) |
b | 布尔值 | b(true 或者 false) |
I | 整数 | i8(64位) |
u | 无符号整数 | u8(64位) |
f | 浮点数 | f8(64位) |
c | 浮点负数 | c16(128位) |
o | 对象 | O(指向对象的指针) |
S,a | 字符串 | S24(24个字符串) |
U | Unicode | U24(24个Unicode字符) |
V | 其他 | V12(12字节数据块) |
练习
import random
I = 5000
% time mat = [[random.gauss(0, 1) for j in range(I)] for i in range(I)]
# Wall time: 35.4 s
from functools import reduce
% time reduce(lambda x, y: x + y, \
[reduce(lambda x, y: x + y, row) \
for row in mat])
# Wall time: 3.48 s
import numpy as np
% time mat = np.random.standard_normal((I, I))
# Wall time: 1.13 s
%time mat.sum()
# Wall time: 88 ms
dt = np.dtype([('Name', 'S10'), ('Age', 'i4'), ('Height', 'f'), ('Children/Pets', 'i4', 2)])
s = np.array([('Smith', 45, 1.83, (0, 1)),
('Jones', 53, 1.72, (2, 2))], dtype=dt)
s
# array([(b'Smith', 45, 1.83000004, [0, 1]),
# (b'Jones', 53, 1.72000003, [2, 2])],
# dtype=[('Name', 'S10'), ('Age', '), ('Height', '), ('Children/Pets', ', (2,))])
s['Name']
# array([b'Smith', b'Jones'],
# dtype='|S10')
s['Height'].mean()
# 1.7750001
s[1]['Age']
# 53
代码的向量化是获得执行速度更快、更紧凑代码的一种策略。 基本思路是 “一次 ” 在一个复杂对象上进行操作,或者向其应用某个函数, 而不是通过在对象的单个元素上循环来进行。在Python中,函数式编程工具map、 filter 和 reduce 提供了向量化的手段。在某种意义上,NumPy的向最化探植于其核心之中。
r = np.random.standard_normal((4, 3))
r
# array([[-0.86142195, -1.10576948, -1.72895607],
# [-0.52694343, 0.885586 , 2.09117311],
# [ 1.17578779, -0.81735752, -0.79021266],
# [-0.16469963, 2.31507942, 0.17910542]])
s = np.random.standard_normal((4, 3))
s
# array([[-0.40514995, 0.21406042, -0.89967644],
# [ 1.98133139, -2.29530214, 0.23899185],
# [-1.5984521 , -0.37488275, 1.52037602],
# [ 0.53853487, 0.79409684, -1.07606899]])
r + s
# array([[-1.2665719 , -0.89170906, -2.62863251],
# [ 1.45438796, -1.40971615, 2.33016495],
# [-0.42266431, -1.19224027, 0.73016336],
# [ 0.37383524, 3.10917626, -0.89696358]])
# NuinPy还支持所谓的广播
2 * r + 3
# array([[ 1.2771561 , 0.78846104, -0.45791214],
# [ 1.94611314, 4.77117199, 7.18234622],
# [ 5.35157558, 1.36528496, 1.41957468],
# [ 2.67060074, 7.63015885, 3.35821083]])
s=np.random.standard_normal(3)
# array([-0.97683636, 0.26286729, -1.17060774])
r
# array([[-0.86142195, -1.10576948, -1.72895607],
# [-0.52694343, 0.885586 , 2.09117311],
# [ 1.17578779, -0.81735752, -0.79021266],
# [-0.16469963, 2.31507942, 0.17910542]])
r + s
# array([[-0.86142195, -1.10576948, -1.72895607],
# [-0.52694343, 0.885586 , 2.09117311],
# [ 1.17578779, -0.81735752, -0.79021266],
# [-0.16469963, 2.31507942, 0.17910542]])
# r和s的第一行相加
r.transpose() # 转置
# array([[-0.86142195, -0.52694343, 1.17578779, -0.16469963],
# [-1.10576948, 0.885586 , -0.81735752, 2.31507942],
# [-1.72895607, 2.09117311, -0.79021266, 0.17910542]])
np.shape(r.T) # (3, 4)
def f(x):
return 3 * x + 5
f(0.5) # 6.5
f(r)
# array([[ 2.41573416, 1.68269156, -0.1868682 ],
# [ 3.41916971, 7.65675799, 11.27351933],
# [ 8.52736337, 2.54792744, 2.62936202],
# [ 4.50590111, 11.94523827, 5.53731625]])
x = np.random.standard_normal((5, 10000000))
y = 2 * x + 3
C = np.array((x, y), order='C') # 类 C 语言内存布局(行优先)
F = np.array((x, y), order='F') # 类 Fortran 内存布局(列优先)
x = 0.0
y = 0.0 # memory cleanup
%timeit C.sum()
# 1 loop, best of 3: 146 ms per loop
%timeit F.sum()
# 1 loop, best of 3: 145 ms per loop
%timeit C[0].sum(axis=0) # 对每列元素求和
# 10 loops, best of 3: 130 ms per loop
%timeit C[0].sum(axis=1) # 对每行元素求和
# 10 loops, best of 3: 73.5 ms per loop
行元素求和速度更快,这是因为每行元素都在相邻的存储位置上
使用类Fortran内存布局:
%timeit F[0].sum(axis=0) # 对每列元素求和
# 1 loop, best of 3: 282 ms per loop
%timeit F[0].sum(axis=1) # 对每行元素求和
# 1 loop, best of 3: 241 ms per loop
按道理来说使用类Fortran内存布局,对每列元素求和比对每行元素求和的时间应该短,因为类 Fortran 内存布局是列优先
但是实际测试的时候还是对每行元素求和时间短-_-||
与类 C 语言变种相比,整体操作绝对要慢得多。