numpy:python数据领域的功臣

前言

numpy对python的意义非凡,在数据分析与机器学习领域为python立下了汗马功劳。如今用python搞数据分析或机器学习常用的pandas、matplotlib、sklearn等库,都须要基于numpy构建。绝不夸张地说,没有numpy,python今天在数据分析与机器学习领域只能是捉襟见肘。javascript

什么是一门好的数据分析语言

数据分析面向的数据大多数是二维表。一门好的数据分析语言,首先须要可以直接有个数据结构存下这个二维表,而后要配上一套成熟的类SQL的数据操做接口,最后要有一套好用的可视化工具。R语言就是一个极好的典范:用内置的data.frame结构作数据的存储;data.frame自己提供足够强大的数据操做能力,另有dplyr、tidyr、data.table、plyr、reshape2等库提供更好用更高效的数据操做能力;在绘图上,除了基本的plot功能外,还提供了ggplot2这样一套优雅的绘图语言,还经过htmlwidget库与javascript各类绘图库创建了紧密的联系,让可视化的动态展现效果更进一步。Excel也是一个极好的例子,有单元格这种灵活的结构为数据存储作支撑,有大量的函数实现灵活的操做,也有强大的绘图系统。html

python目前在数据分析领域也已经具有了至关可观的能力,包括pandas库实现的DataFrame结构,pandas自己提供的数据操做能力,matplotlib提供的数据可视化能力,而这一切都离不开numpy库。java

什么是一门好的机器学习语言

通常来说,一门好的机器学习语言在数据分析上也必定很吃得开,由于数据分析每每是机器学习的基础。可是机器学习的要求更高,由于在模型训练阶段每每须要较为复杂的参数估计运算,所以语言须要具有较强的科学计算能力。科学计算能力,最核心的就是矩阵运算能力。关于矩阵运算能力,这篇文章对各类语言有很好的比较。python

若是没有numpy,python内部只能用list或array来表示矩阵。假如用list来表示[1,2,3],因为list的元素能够是任何对象,所以list中所保存的是对象的指针,因此须要有3个指针和三个整数对象,比较浪费内存和CPU计算时间。python的array和list不一样,它直接保存数值,和C语言的一维数组比较相似,可是不支持多维,表达形式很简陋,写科学计算的算法很难受。numpy弥补了这些不足,其提供的ndarray是存储单一数据类型的多维数组,且采用预编译好的C语言代码,性能上的表现也十分不错。算法

python最流行的机器学习库sklearn构建在numpy之上,提供了各类标准机器学习模型的训练与预测接口,其中模型训练接口的内部实现是基于numpy库实现的。好比很常见的线性回归模型,参数估计调用的是numpy.linalg.lstsq函数。编程

numpy的核心结构:ndarray

如下内容摘录自用Python作科学计算segmentfault

a = np.array([[0,1,2],[3,4,5],[6,7,8]], dtype=np.float32)

ndarray是numpy的核心数据结构。咱们来看一下ndarray如何在内存中储存的:关于数组的描述信息保存在一个数据结构中,这个结构引用两个对象,一块用于保存数据的存储区域和一个用于描述元素类型的dtype对象。数组

clipboard.png

数据存储区域保存着数组中全部元素的二进制数据,dtype对象则知道如何将元素的二进制数据转换为可用的值。数组的维数、大小等信息都保存在ndarray数组对象的数据结构中。数据结构

strides中保存的是当每一个轴的下标增长1时,数据存储区中的指针所增长的字节数。例如图中的strides为12,4,即第0轴的下标增长1时,数据的地址增长12个字节:即a[1,0]的地址比a[0,0]的地址要高12个字节,正好是3个单精度浮点数的总字节数;第1轴下标增长1时,数据的地址增长4个字节,正好是单精度浮点数的字节数。机器学习

如下内容总结自Numpy官方文档Numpy basics

关于ndarray的索引方式,有如下几个重点须要记住:

  • 虽然x[0,2] = x0,可是前者效率比后者高,由于后者在应用第一个索引后须要先建立一个temporary array,而后再应用第二个索引,最后找到目标值。

  • 分片操做不会引起copy操做,而是建立原ndarray的view;他们所指向的内存是同一片区域,不管是修改原ndarray仍是修改view,都会同时改变两者的值。

  • index array和boolean index返回的是copy,不是view。

关于上面列举的分片操做不会引起copy操做,咱们来进一步探讨一下。先看一下numpy的例子:

clipboard.png

再来看一下R的例子:

clipboard.png

能够看到numpy和R在矩阵的分片操做有不一样的设计理念:在R里分片操做会引发数据的复制,在numpy里不会。事实上,R的设计理念不少时候能够用一句话来归纳:copy on modify,一旦对数据有修改就会引发内存上的复制操做,这个操做要花很多时间,所以常常会听到人们抱怨R费内存且速度慢。因此,咱们能够看到numpy在处理这件事情上明显要用心不少,根据场景设计了不一样的策略,不是简单地采用R的一刀切方式。固然,这也带来了一些学习成本,须要对numpy足够熟悉才能避免踩坑。R社区里对copy on modify的哲学也有诟病并在努力改变,好比同是data.frame操做库的data.table和dplyr,data.table性能比dplyr高不少,部分缘由也是data.table规避了copy on modify的方式。

Structured Array

根据numpy的官方文档,定义结构化数组有四种方式。本文采用字典方法,经过定义一个dtype对象实现,须要指定的键值有names和formats。

persontype = np.dtype({
        'names': ['name', 'age', 'weight'], 
        'formats': ['S32', 'i', 'f']
    })
a = np.array([("Zhang", 32, 75.5), ("Wang", 24, 65.2)], dtype=persontype)

咱们用IPython的计时函数看一下提取数据的效率:

%timeit a[1]
%timeit a['name']
%timeit a[1]['name']
%timeit a['name'][1]

输出结果以下:

The slowest run took 46.83 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 153 ns per loop
The slowest run took 34.34 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 3: 174 ns per loop
The slowest run took 13.00 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 1.08 µs per loop
The slowest run took 9.84 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 412 ns per loop

从上面的结果,咱们发现,获取相同的数据有多种操做,不一样的操做性能差异很大。我作了一个推测,纯粹是瞎猜:numpy在创建结构化数组时,将整个结构体连续存储在一块儿,即按行存储,所以a[1]的速度最快;可是为了保证提取列的效率,对a['name']创建了索引,所以a['name']的效率也很高;可是这个索引只对整个a起做用,若是输入只有a的一部分,仍然须要遍历整个a,去提取出对应的数据,所以a[1]['name']a['name'][1]的效率差不少。

关于做者:丹追兵:数据分析师一枚,编程语言python和R,使用Spark、Hadoop、Storm、ODPS。本文出自丹追兵的pytrafficR专栏,转载请注明做者与出处:https://segmentfault.com/blog...

相关文章
相关标签/搜索