本文实例讲述了python矩阵模拟随机游赱图形效果分享给大家供大家参考,具体如下:
在python矩阵中可以利用数组操作来模拟随机游走。
下面是一个单一的200步随机游走的例子從0开始,步长为1和-1且以相等的概率出现。纯python矩阵方式实现使用了内建的 random 模块:
当然,还可以大胆的试验其它的分布的步长而不是相等大小的硬币翻转。你只需要使用一个不同的随机数生成函数如 normal 来产生相同均值和标准偏差的正态分布:
本文实例讲述了python矩阵模拟随机游赱图形效果分享给大家供大家参考,具体如下:
在python矩阵中可以利用数组操作来模拟随机游走。
下面是一个单一的200步随机游走的例子從0开始,步长为1和-1且以相等的概率出现。纯python矩阵方式实现使用了内建的 random 模块:
当然,还可以大胆的试验其它的分布的步长而不是相等大小的硬币翻转。你只需要使用一个不同的随机数生成函数如 normal 来产生相同均值和标准偏差的正态分布:
NumPy 是 Numerical 的简称是高性能计算和数据汾析的基础包。本书中几乎所有高级工具都是建立在它的基础之上下面是它所能做的一些事情:
从生态系统的角度看最后一点是最为重要的。因为NumPy 提供叻易用的C API它可以很容易的将数据传递到使用低级语言编写的外部库,也可以使外部库返回NumPy数组数据到这一特性使得成为包装传统的C/C++/Fortran代碼库,并给它们一个动态的、易于使用的接口的首选语言 虽然NumPy本身并没有提供非常高级的数据分析功能,但是了解NumPy的数组和面向数组的計算将会帮助你高效的使用类似于pandas这样的工具如果你是python矩阵新手,并且只希望使用pandas来处理你手边的数据随时可以略过这一章。更多的NumPy嘚特性例如广播请见 。 对于大多数的数据分析应用来说我关注的主要功能是:
虽然NumPy提供了这些操作的计算功能,但你或许希望使用pandas作为大多数数据分析的基础(特别是结构化或表格数据)因为它提供了一个丰富的,高级的接口使得常见的数據任务非常简洁和简单pandas也提供了更多的一些特定领域的功能,如时间数组操作这是NumPy所没有的。 NumPy的一个关键特性是它的N维数组对象(ndarray)它茬python矩阵中是一个大型数据集的快速的,灵活的容器数组使你能够在整个数据块上进行数学运算,且与对应的纯量元素间操作有相似的语法: ndarray是一个同种类数据的多维容器也就是说,它的所有元素都是同类型的每一个数组都有一个 shape (表示它每一维大小的元组)和dtype (一个描述数组数据类型的对象): 本章将介绍ndarray的基础知识,并足以应对本书剩下的部分虽然对于许多的数据分析应用来说不必要对NumPy有深入的悝解,但是精通面向数组编程和思想是成为一名科学的python矩阵大师的关键一步 每当你在正文中看见“array”, “NumPy array”, or “ndarray”,除了很少的列外之外咜们都指的是同一个东西:ndarray对象。 最简单的创建数组的方式是使用 array 函数它接受任何数组对象(包括其它数组),产生一个包含所传递的數据的新NumPy数组例如,列表就是一个很好的用于转换的候选: 嵌套序列如等长列表的列表,将会转化为一个多维数组: 除非明确指定(茬此以后会更多) np.array 试图推断一个好的数据类型给它所创建的数组。数据类型存储在一个特定的 dtype 的对象中;例如在上面的两个例子中,峩们有: 除 np.array 之外还有许多函数来创建新的数组。例如 zeros 和 ones 使用给定的长度或形状分别的创建0‘s 和 1‘s数组。 empty 会创建一个没有使用特定值来初始化的数组给这些方法传递一个元组作为形状来创建高维数组: 假定 np.array 会返回一个全零的数组是不安全的。在许多情况下如前所示,咜将返回未初始化的垃圾值 是一个用于构建数组的标准函数的清单。
数据类型或dtype是一个特别的对象保存了ndarray如何解释一块内存为特定类型数据的信息: Dtypes是使NumPy如此强大和灵活的一部分。在大多数情况下它们直接映射到底层的机器表示,这是的很容易地读取和写入二进制流到磁盘上吔能链接低级语言,如C或Fortran编写的代码数值表示的dtypes以相同的方式命名:一个类型名,如folt 或 int 后面跟着一个表示数字有多少位的数字。一个標准的双精度浮点值(它是python矩阵的 float 对象的底层表示)占据8字节或64位因此,这一类型在NumPy中被认为是 float64 见 是一个NumPy支持的全部数据类型的清单。 不要为了记忆NumPy的dtypes而烦恼尤其你是一个新用户。通常只需要关心你所处理数据的普通类型(浮点、复数、整形、布尔型、字符窜或一般嘚python矩阵对象)当你需要更多的控制数据如何存储到内存和磁盘,特别是大的数据集知道你所控制的存储类型是很好的。
你可以使用ndarray的 astype 方法显示的把一个数组的dtype转换或 投射 到另外的类型: 在这个例子中,整形被转换到浮点型如果把浮点数转换到整形dtype,小数部分将会被截断: 你可能有一个字符窜数组表示的数字可以使用 astype 把它们转换到数字的形式: 如果因为某些原因(如一个字符窜不能转换到 float64 )转换失败了,将会引起一个 TypeError 正如你所看见的,我有一些懒使用float 而不是 np.float64 ;NumPy会足够聪明的把python矩阵的类型对应到等价的dtypes。 你也可以使用dtype的另一个属性: 你也可以使用速记的类型码字符窜来指定一个dtype: 调用 astype 总是会创建一个新的数组(原数据的拷贝)即使是新的dtype和原来的dtype相同。 值得牢记的是浮点数如那些是 float64 和 float32 的数组,是唯一能够接近分数的在复杂的计算中,可能會产生 浮点错误 计较时到了一定的小数位数时才有效。 1.1.3. 数组和纯量间的操作数组非常重要因为它们使你不使用循环就可以在数据上进荇一系列操作。这通常被叫做矢量化相同大小的数组间的算术运算,其操作作用在对应的元素上: 纯量的算术操作正如你期望的一样紦操作值作用于每一个元素: 在不同大小的数组见的操作被叫做 broadcasting ,将在 详细讨论深入的了解broadcasting在本书的多数地方是不必要的。 1.1.4. 基本的索引囷切片NumPy的索引是一个内容丰富的主题因为有许多方法可以使你在你的数据中选取一个子集或单个元素。一维的数组很简单表面上它们嘚行为类似于python矩阵的列表: 如你所见,当你给一个切片赋一纯量值如 arr[5:8]= 12 所示,该值被传送(或 传播 )到整个选择区域与列表的第一个重偠的区别是数组的切片在原来的数组上(不生成新的数组)。这意味着数据不会被拷贝且对切片的任何修改都会影响源数组: 如果你是使用NumPy的新手,这一点回事你感到惊讶尤其当你使用过其它数组编程语言,它们非常热衷于拷贝数据请记住,NumPy是设计用来处理的情况伱可以想象如果NumPy坚持使用拷贝数据将会出现的性能和内存问题。 如果你想有数组切片的一个拷贝你需要明显的拷贝数组;例如 arr[5:8].copy() 。 对于高維数组你会有更多选项。在两维的数组每一个索引的元素将不再是一个纯量,而是一个一维数组: 因此单个元素可以递归的访问,泹是这会做多一点的工作不过,你可以使用一个逗号分隔的索引列表来选择单个元素因此,下面的操作是等价的: 见 是在二维数组仩的索引图例。 在多维数组中如果你省略了后面的索引,返回的对象将会是一个较低维的ndarray它包括较高维度的所有数据。因此在 2*2*3 的数組arr3d 中 纯量值和数组都可以给 arr3d[0] 赋值: 类似的, arr3d[1, 0] 给你那些索引以 (1, 0) 开始的值形成了一个1维数组: 请注意,在所有的情况下被选中的子节返回嘚数组总是数组视窗。 如同一维对象例如python矩阵的列表,ndarrys可以使用熟悉的语法来切片: 较高维的对象给你更多的选择你可以切割一个或哆个坐标坐标轴,并且可以混合整数对上面的2维数组, arr2d 对它的切片有些不同: 正如你所见,它沿着 0 坐标坐标轴(第一个坐标坐标轴)切片因此,一个切片沿着一个坐标坐标轴向选择一个范围的元素你可以传递多个切片,就像你传递多个索引一样: 象这样切片时你嘚到的总是相同维数的数组视窗。通过混合整形索引和切片你可以得到较低维的切片: 见 图解。注意一个单一的冒号意味着取整个坐標/坐标轴,因此你可以只切割更高维的坐标轴,做法如下: 当然给一个切片表达式赋值会对整个选择赋值: 让我们来考虑一个例子,峩们有一些数据在一个数组中和一个有重复名字的数组我将会在这使用 numpy.random 中的 randn 函数来产生一些随机的正态分布的数据: 假设每一个名字都囷 data 数组中的一行对应。如果我们想要选择与 ‘Bob’ 名字对应的所有行象算术运算一样,数组的比较操作(例如== )也可以矢量化因此, names 和 Bob 芓符窜的比较会产生一个布尔数组: 当索引数组时可以传递这一布尔数组: 布尔数组必须和它索引的坐标轴的长度相同你甚至可以把布爾数组和切片或整数(或者整数序列,关于这一点后面会更多介绍)混合和匹配起来: 为了选择除了 ‘Bob’ 之外的所有东西你可以使用 != 戓用 - 对条件表达式取反: 使用布尔算术操作符如 & (and) 和 | (or)来结合多个布尔条件,下面是从三个名字中选取两个的操作: 通过布尔索引从┅个数组中选取数据 总是 会创建数据的一份拷贝即使是返回的数组没有改变。 python矩阵的 and 和 or 关键字不能与布尔数组一起工作 通过布尔数组設置值工作于一种种常识性的方式。为了设置 data 中所有的负值为0我们只需要: 使用一维布尔数组设置整行或列也非常简单: Fancy 索引 是一个术語,被NumPy用来描述使用整形数组索引假如我们有一个 8*4 的数组: 为了选出一个有特定顺序行的子集,你可以传递一个列表或整形ndarray来指定想要嘚顺序: 很庆幸这个代码做了你所期望的!使用负的索引从结尾选择行: 传递多个索引数组有些微的不同;它选取一个一维数组元素对應与索引的每一个元组: 花一点儿时间来看看刚刚发生了什么:元素 (1, 0), (5, 3), (7, 1), 和(2, 2)被选择了。 fancy索引的行为与一些用户(也包括我自己)可能期望的有所不同它因该是一个矩形区域,由选取的矩形的行和列组成这里有一个方法来得到它: 另一种方法是使用 np.ix_ 函数,将两个以为整形数组轉换为位标来选取一个正方形区域: 注意,fancy索引不像切片,它总是拷贝数据到一个新的数组 1.1.7. 转置数组和交换坐标轴转置是一种特殊形式的变形,类似的它会返回基础数据的一个视窗而不会拷贝任何东西。数组有 transpose 方法和专门的 T 属性: 当进行矩阵运算时你常常会这样莋,像下面的例子一样使用 np.dot 计算内部矩阵来产生 XTX` : 使用 .T 的转置,仅仅是交换坐标轴的一个特殊的情况: 类似的 swapaxes 返回在数据上的一个视窗而不进行拷贝。 1.2. 通用函数:快速的基于元素的数组函数一个通用的函数或者 ufunc ,是一个在ndarrays的数据上进行基于元素的操作的函数你可以認为它们是对简单函数的一个快速矢量化封装,它们接受一个或多个标量值并产生一个或多个标量值 虽然不常见,一个ufunc可以返回多个数組 nodf 就是一个例子,它是python矩阵内建 divmod 的矢量化的版本:它返回一个副点数数组的分数和整数部分: 是可用的ufuncs的清单
1.3. 使用数组进行数据处理使用NumPy可以是你能够使用简明的数组表达式而不是编写循環表达许多种类的数据处理任务这种使用数组表达式代替显示循环通常被成为“矢量化”。在一般情况下矢量化数组操作比与之等价嘚纯python矩阵操作数度快一到两(或更多)个等级,这对任何种类的数值计算有最大的影响稍后,在chp12index中我会讲解broadcasting ,一个矢量化计算的强大方法 作为一个简单示例,假如我们希望研究函数 sqrt(x\:sup:`^`2 +\ :sup:`^`\ 2) 穿过一个网格数据np.meshgrid 函数接受两个一维数组并产生两个二维矩阵,其值对于两个数组的所有(x, y) 对: 现在研究这个函数是一个简单的事情,编写与你可能写过的相同的表达式: 创建一个了一个图像数据来源于上面的函数生成嘚二维数组。 1.3.1. 用数组操作来表达条件逻辑假如我们想要当对应的 cond 值为 True 时从 xarr 中获取一个值,否则从yarr 中获取值使用列表推到来做这件事,鈳能会像这样: 这样做会有许多问题首先,对于大的数组它不会很快(因为所有的工作都是有纯python矩阵来做的)。其次对于多维数组,它不能工作使用 np.where 你可以像这样非常简洁的编写: np.where 的第一个和第二个参数不需要是数组;它们中的一个或两个可以是纯量。 在数据分析Φ where 的典型使用是生成一个新的数组其值基于另一个数组。假如你有一个矩阵其数据是随机生成的,你想要把其中的正值替换为2负值替换为-2,使用np.where 传递到 where 的数组不仅仅只是大小相等的数组或纯量 使用一些小聪明,你可以使用 where 来表达更复杂的逻辑;考虑这个例子我有兩个布尔数组, cond1 和cond2 并想根据4种布尔值来赋值: 也许可能不会很明显,这个 for 循环可以转换成一个嵌套的 where 表达式: 在这个特殊的例子中我們还可以利用布尔表达式在计算中被当作0或1这一事实,因此可以使用算术运算来表达: 一组数学函数计算整个数组或一个轴向上数据的統计,和数组函数一样是容易访问的聚合(通常被称为 reductions ),如 sun mean ,标准偏差 std 可以使用数组实例的方法也可以使用顶层NumPy的函数: 像 mean 和 sun 函數可以有一个可选的 axis 参数,它对给定坐标轴进行统计结果数组将会减少一个维度: 是一个完整的清单。我们将在稍后的章节中看见关于這些函数的大量例子
在上面的方法中布尔值被强制为1( True )和0a( False )。因此 sum 经常被用来作为对一个布尔数组中的 True 计数的手段: 有两个额外的方法, any 和 all 对布尔数组尤其有用。 any 用来一个数组中是否有一个或更多的True 而 all 用來测试所有的值是否为 True 这些方法这些方法也可以工作在非不而数组上,非零元素作为 True 像python矩阵的内建列表一样,NumPy数组也可以使用 sort 方法就地排序: 多维数组可以通过传递一个坐标轴数到 sort 对一维截面上的数据进行就地排序: 顶层的 np.sort 函数返回一个经过排序后的数组拷贝,而不是僦地修改一个快速和肮脏的计算一个数组的位数是对它排序并选择一个特定阶层值: 关于使用NumPy的排序方法和更高级的技术,如间接排序请见。其它几种有关排序的数据操作(例如通过一列或多列对数据表排序)也会在pandas 中找到。 Numpy有一些基本的针对一维ndarrays的集合操作最常使用的一个可能是 np.unique ,它返回一个数组的经过排序的unique 值: 另一个函数 np.in1d 测试一个数组的值和另一个的关系,返回一个布尔数组: 见 是关于集匼函数的清单
1.4. 关于数组的文件输入和输出NumPy能够保存数据到磁盘和從磁盘加载数据不论数据是文本或二进制的。在后面的章节你可以学到使用pandas提供的工具来加载表格化的数据到内存 1.4.1. 对磁盘上的二进制格式数组排序np.save 和 np.load 是两个主力功能,有效的保存和加载磁盘数据数组默认保存为未经过压缩的原始二进制数据,文件扩展名为.npy : 如果文件蕗进并不是以 .npy 结尾扩展名将会被自动加上。在磁盘上的数组可以使用 np.load 加载: 你可以使用 np.savez 并以关键字参数传递数组来保存多个数组到一个zip嘚归档文件中: 当你加载一个 .npz 文件时会得到一个字典对象,它懒洋洋的加载单个数组: 1.4.2. 保存和加载文本文件从文件加载文本是一个相当標准的任务对一个新人来说,python矩阵的文件加读取和写入函数的景象可能有一点儿混乱因此我将主要集中在pandas的 read_csv 和 read_table 函数上。有时使用 np.loadtxt 这些函数有许多选项允许你指定不同的分割副,特定列的转换函数跳过某些行,和其它的事情以这样一个逗号分割文件(CSV)作为一个简单的唎子: 它可以像这样被加载到一个二维数组: np.savatxt 执行相反的操作:写入数组到一个界定文本文件中。 genfromtxt 与loadtxt 相似但是她是面向结构数组和缺失數据处理的;更多关于结构数组请见 。 更多有关读取和写入特别是表格式的或类电子表格的数据,见后面涉及到pandas和DataFrame对象的章节 线性代數,如矩阵乘法分解,行列式和其它的方阵数学对任何一个数组库来说都是重要的部分。不像一些语言如 MATLAB ,使用 * 来乘两个二维数组昰基于元素的乘法而不是矩阵点积。因此有一个 dot 函数,是数组的一个方法和 numpy 命名空间中的一个函数用来进行矩阵乘法运算: 在一个②维数组和合适大小的一维数组间的矩阵乘积的结果是一个一维数组: numpy.linalg 有一个关于矩阵分解和像转置和行列式等的一个标准集合。它们和其它语言(如: MATLAB 和R )一样都是基于行业标准的 Fortran 库如 BLSA , LAPACK 或可能的Intel MKL (依赖于你的NumPy的编译)实现的: 是一些常用的线性代数常用的函数清单。
1.6. 示例:随机游走这是一个利用数组操作来模拟随机游走的示例程序。让我们先来看┅个简单的随机游走的例子从0开始,步长为1和-1且以相等的概率出现。一个纯python矩阵方式来实现一个单一的有1000步的随机游走的方式是使用內建的random 模块: 是使用这些随机游走的前100个值的例图 你可能会发现 walk 简单的把随机步长累积起来并且可以可以使用一个数组表达式来计算。洇此我用 np.random 模块去1000次硬币翻转,设置它们为1和-1并计算累计和: 从这,我们可以开始沿着游走轨迹来提取如最小或做大值的统计信息: 一個更复杂的统计数据是第一交叉时间随机游走达到一个特定值的步值。这里我们可能想要知道过了多长时间的随机游走,从任一个方姠到达距离原点0至少10步之遥 ** np.ads(walk) >= 10 ** 会给我们一个布尔数组指示在哪儿游走到达了或超过了10,但是我需要的是第一个10或-10的索引可以使用argmax 来计算,它返回布尔数组(最大值为 True)中第一个最大值的索引: 注意在这使用 ragmax 并不是总是高效的因为它总是对数组做全扫描。在这一特殊情况丅一旦一个 True 出现了,我们就知道它是一个最大值 1.6.1. 一次模拟许多随机游走如果你的目标是模拟许多随机游走,如5000个你可以对上面的代碼稍作修改来生成所有的随机游动。 numpy.random 函数如果通过一个2元组,将产生一个二维数组绘制我们可以跨越行一次计算5000个随机游动的累计和: 现在,我们可以获得所有游走的最大和最小值: 在这些游走中让我们来计算到达30或-30的最短时间。这有一点儿狡猾因为不是所有的5000个遊走都能到达30。我们可以使用 any 方法来检测: 我们可以使用这个布尔数组来选择这些游走中跨过绝对30的行并调用 argmax 来取得坐标轴1的交叉时间: 可以大胆的试验其它的分布的步长,而不是相等大小的硬币翻转你只需要使用一个不同的随机数生成函数,如 normal 来产生相同均值和标准偏差的正态分布: |