numpy教程:Universal Functions 通用函数 伪随机数

文章目录

  • 4.2 Universal Functions: Fast Element-Wise Array Functions(通用函数:快速点对点数组函数)
  • 4.4 File Input and Output with Arrays(通过数组来进行文件的输入和输出)
  • 4.5 Linear Algebra (线性代数)
  • 4.6 Pseudorandom Number Generation(伪随机数生成)

4.2 Universal Functions: Fast Element-Wise Array Functions(通用函数:快速点对点数组函数)

universal function, 或 ufunc, 是用来在ndarray中实现element-wise操作的。

可以认为这个ufunc可以把一些简单的函数做快速的向量化封装,输入时一个以上的标量,输出也是一个以上的标量。

很多ufuncs都是点对点的变换,像sqrtexp

import numpy as np
arr = np.arange(10)
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.sqrt(arr)
array([ 0.        ,  1.        ,  1.41421356,  1.73205081,  2.        ,
        2.23606798,  2.44948974,  2.64575131,  2.82842712,  3.        ])
np.exp(arr)
array([  1.00000000e+00,   2.71828183e+00,   7.38905610e+00,
         2.00855369e+01,   5.45981500e+01,   1.48413159e+02,
         4.03428793e+02,   1.09663316e+03,   2.98095799e+03,
         8.10308393e+03])

这些函数叫做一元通用函数(unary ufuncs)。其他一些函数,比如addmaximum,需要两个数组(binary ufuncs),并返回一个数组作为结果:

x = np.random.randn(8)
y = np.random.randn(8)
x
array([ 0.18373557, -1.82728347, -0.11149882, -1.34286776, -1.09016986,
        1.63308   ,  1.05205535, -0.32746706])
y
array([-0.42410809,  1.89603273, -1.13649816, -0.98559379, -0.16827718,
        0.52828569,  1.57543351,  1.50045399])
np.maximum(x, y)
array([ 0.18373557,  1.89603273, -0.11149882, -0.98559379, -0.16827718,
        1.63308   ,  1.57543351,  1.50045399])

这里mamimum点对点的比较x和y中的元素。

尽管不常见,但ufunc也能返回多个数组。例如modf,这是一个向量版的divmodpython内建函数),modf会返回小数部分和整数部分:

本函数是实现a除以b,然后返回商与余数的元组。如果两个参数a,b都是整数,那么会采用整数除法,结果相当于(a//b, a % b)。如果a或b是浮点数,相当于(math.floor(a/b), a%b)。

arr = np.random.randn(7) * 5
arr
array([ 1.51538382, -0.75054846,  0.02863286,  8.74026861, -3.44529124,
       -9.18401768, -0.68469611])
remainder, whole_part = np.modf(arr)
remainder
array([ 0.51538382, -0.75054846,  0.02863286,  0.74026861, -0.44529124,
       -0.18401768, -0.68469611])
whole_part
array([ 1., -0.,  0.,  8., -3., -9., -0.])

ufunc能接受一个可选参数作为输出,这样可以直接更改原有的数组:

arr
array([ 1.51538382, -0.75054846,  0.02863286,  8.74026861, -3.44529124,
       -9.18401768, -0.68469611])
np.sqrt(arr) # 没有改变原有的arr
/Users/xu/anaconda/envs/py35/lib/python3.5/site-packages/ipykernel/__main__.py:1: RuntimeWarning: invalid value encountered in sqrt
  if __name__ == '__main__':





array([ 1.23100927,         nan,  0.16921248,  2.95639453,         nan,
               nan,         nan])
np.sqrt(arr, arr) # 改变了原有的arr
/Users/xu/anaconda/envs/py35/lib/python3.5/site-packages/ipykernel/__main__.py:1: RuntimeWarning: invalid value encountered in sqrt
  if __name__ == '__main__':

array([ 1.23100927,         nan,  0.16921248,  2.95639453,         nan,
               nan,         nan])
arr
array([ 1.23100927,         nan,  0.16921248,  2.95639453,         nan,
               nan,         nan])

4.4 File Input and Output with Arrays(通过数组来进行文件的输入和输出)

Numpy能从磁盘直接存储和加载数据,不论是文本格式还是二进制模式。这里我们只考虑Numpy的二进制模式,因为大多数用户更喜欢用pandas或其他工具来加载texttabular数据。

np.savenp.load。数组会以未压缩的原始二进制模式被保存,后缀为.npy:

import numpy as np

arr = np.arange(10)
np.save('../examples/some_array', arr)

即使保存的时候没有加后缀,也会被自动加上。可以用np.load来加载数组:

np.load('../examples/some_array.npy')
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

np.savez能保存多个数组,还可以指定数组对应的关键字,不过是未压缩的npz格式:

np.savez('../examples/array_archive.npz', a=arr, b=arr)

加载.npz文件的时候,得到一个dict object

arch = np.load('../examples/array_archive.npz')
arch['b']
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

可以用np.savez_compressed来压缩文件:

np.savez_compressed('../examples/array_compressed.npz', a=arr, b=arr)

4.5 Linear Algebra (线性代数)

MATLAB里,* 代表矩阵乘法。但是在numpy里,*表示element-wise prodct。要想做到矩阵乘法,要用多函数dot:

import numpy as np
x = np.array([[1., 2., 3.], [4., 5., 6.]])

y = np.array([[6., 23.], [-1, 7], [8, 9]])
x
array([[ 1.,  2.,  3.],
       [ 4.,  5.,  6.]])
y
array([[  6.,  23.],
       [ -1.,   7.],
       [  8.,   9.]])
x.dot(y)
array([[  28.,   64.],
       [  67.,  181.]])

x.dot(y)等同于np.dot(x, y):

np.dot(x, y)
array([[  28.,   64.],
       [  67.,  181.]])

一个二维数据和一个一维数组的矩阵乘法,得到一个一维数组:

np.dot(x, np.ones(3))  
# 这里应该是用狂了boradcasting,x中的每一行与[1, 1, 1]点对点乘积后求和
array([  6.,  15.])

@作为一个中缀计算符(鬼知道这是什么东西),也能实现矩阵乘法:

x @ np.ones(3)
array([  6.,  15.])

np.linalg能用来做矩阵分解,以及比如转置和求秩之类的事情:

from numpy.linalg import inv, qr
# X = np.round(np.random.randn(5, 5), 3) # 这里我们用np.round控制小数点后的位数,看起来更舒服一些
X = np.random.randn(5, 5)
X
array([[ 0.0761557 , -0.34138565, -0.56325926,  1.7854    ,  1.23440008],
       [ 1.46787829,  1.73130465,  1.03519282,  1.11137573, -0.05928319],
       [-0.95508009, -1.35350494, -1.43415583, -0.28499706,  0.32739284],
       [ 0.83307271,  1.89349058,  0.94116452,  0.32347353,  0.22236912],
       [-1.20661273,  0.4531822 ,  0.47635565, -1.69312137, -0.34497803]])
mat = X.T.dot(X)
np.round(mat, 2)
array([[ 5.22,  4.84,  3.06,  4.35,  0.3 ],
       [ 4.84,  8.74,  5.92,  1.55, -0.7 ],
       [ 3.06,  5.92,  4.56,  0.05, -1.18],
       [ 4.35,  1.55,  0.05,  7.48,  2.7 ],
       [ 0.3 , -0.7 , -1.18,  2.7 ,  1.8 ]])
np.round(inv(mat), 2)
array([[ 12.14,  -6.15,   3.85, -11.22,  14.95],
       [ -6.15,   4.85,  -4.47,   5.7 ,  -8.57],
       [  3.85,  -4.47,   5.23,  -3.78,   6.71],
       [-11.22,   5.7 ,  -3.78,  10.77, -14.55],
       [ 14.95,  -8.57,   6.71, -14.55,  20.95]])
np.round(mat.dot(inv(mat)), 2)
array([[ 1.,  0.,  0.,  0., -0.],
       [-0.,  1.,  0., -0., -0.],
       [ 0., -0.,  1., -0.,  0.],
       [-0.,  0.,  0.,  1.,  0.],
       [ 0.,  0., -0.,  0.,  1.]])
q, r = qr(mat)
np.round(r, 2)
array([[ -8.89, -10.37,  -6.57,  -7.16,  -0.77],
       [  0.  ,  -5.5 ,  -4.79,   5.41,   3.04],
       [  0.  ,   0.  ,  -0.71,   1.85,   1.54],
       [  0.  ,   0.  ,   0.  ,  -0.75,  -0.53],
       [  0.  ,   0.  ,   0.  ,   0.  ,   0.03]])

X.T.dot(X)计算的是X和X的转置的矩阵乘法。

4.6 Pseudorandom Number Generation(伪随机数生成)

numpy.random提供了很多生成随机数的函数,可以选择生成符合某种概率分布的随机数。比如我们可以用normal得到一个4 x 4的,符合标准正态分布的数组:

import numpy as np
samples = np.random.normal(size=(4, 4))
samples
array([[ 0.5382462 , -0.79452471, -0.07993797,  0.72243531],
       [ 0.87180676,  1.61663011, -0.62169955,  1.73880636],
       [ 1.88294218,  0.07432438,  1.63474848,  0.23519213],
       [ 0.92847885, -0.45791646,  0.63965317, -0.23654448]])

相对的,python内建的random模块一次只能生成一个样本。在生成大量样本方法,numpy.random是非常快的:

from random import normalvariate

N = 1000000
%timeit sample = [normalvariate(0, 1) for _ in range(N)]
1 loop, best of 3: 1.25 s per loop
%timeit np.random.normal(size=N)
10 loops, best of 3: 49.1 ms per loop

之所以称之为伪随机数,是因为随机数生成算法是根据seed来生成的。也就是说,只要seed设置一样,每次生成的随机数是相同的:

np.random.seed(1234)

当然,这个seed是全局的,如果想要避免全局状态,可以用numpy.random.RandomState来创建一个独立的生成器:

rng = np.random.RandomState(1234)
rng.randn(10)
array([ 0.47143516, -1.19097569,  1.43270697, -0.3126519 , -0.72058873,
        0.88716294,  0.85958841, -0.6365235 ,  0.01569637, -2.24268495])

你可能感兴趣的:(pandas使用教程,numpy,pandas,前端,数据库,python,开发语言)