通过实例浅析Python对比C语言的编程思想差异

我一直使用 Python,用它处理各种数据科学项目。 Python
以易用闻名。有编码经验者学习数天就能上手(或有效使用它)。

听起来很不错,不过,如果你既用 Python,同时也是用其他语言,比如说 C 的话,或许会存在一些问题。

给你举个我自己经历的例子吧。 我精通命令式语言,如 C 和 C 。对古老经典的语言如 Lisp 和 Prolog
能熟练使用。另外,我也用过 Java,Javascript 和 PHP 一段时间。(那么,学习) Python
对我来讲不是很简单吗?事实上,只是看起来容易,我给自己挖了个坑:我像用 C 一样去用 Python。

具体情况,请向下看。

一个最近的项目中,需要处理地理空间数据。给出(任务)是 gps 追踪 25,000
个左右位置点,需要根据给定的经纬度,重复定位距离最短的点。我第一反应是,翻查(已经实现的)计算已知经纬度两点间距离的代码片段。代码可以在
John D. Cook 写的这篇 code available in the public domain 中找得到。

万事俱备! 只要写一段 Python 函数,返回与输入坐标距离最短的点索引(25,000
点数组中的索引),就万事大吉了:  
 

def closest_distance(lat,lon,trkpts):

  d = 100000.0

  best = -1

  r = trkpts.index

  for i in r:

    lati =
trkpts.ix[i,'Lat']

    loni =
trkpts.ix[i,'Lon']

    md =
distance_on_unit_sphere(lat, lon, lati, loni)

    if d
> md

     
best = i

     
d = md

  return best

其中, distance_on_unit_sphere 是 John D. Cook's 书中的函数,trkpts 是数组,包含
gps 追踪的点坐标(实际上,是 pandas 中的数据帧,注,pandas 是 python 第三方数据分析扩展包)。

上述函数与我以前用 C 实现的函数基本相同。 它遍历(迭代)trkpts
数组,将迄今为止(距离给定坐标位置)的距离最短的点索引值,保存到本地变量 best 中。

目前为止,情况还不错,虽然 Python 语法与 C 有很多差别,但写这段代码,并没有花去我太多时间。

代码写起来快,但执行起来却很慢。例如,我指定428
个点,命名为waypoints(导航点,路点,导航路线中的关键点)。导航时,我要为每个导航点 waypoint 找出距离最短的点。为
428 个导航点 waypoint 查找距离最短点的程序,在我的笔记本上运行了 3 分 6 秒。

之后,我改为查询计算曼哈坦距离,这是近似值。我不再计算两点间的精确距离,而是计算东西轴距离和南北轴距离。计算曼哈坦距离的函数如下:  
 

def manhattan_distance(lat1, lon1, lat2, lon2):

  lat = (lat1 lat2)/2.0

  return abs(lat1-lat2)
abs(math.cos(math.radians(lat))*(lon1-lon2))



实际上,我用了一个更简化的函数,忽略一个因素,即维度曲线上 1 度差距比经度曲线上的 1
度差距要大得多。简化函数如下:  
 

def manhattan_distance1(lat1, lon1, lat2, lon2):

  return abs(lat1-lat2) abs(lon1-lon2)



closest 函数修改为:  
 

def closest_manhattan_distance1(lat,lon,trkpts):

  d = 100000.0

  best = -1

  r = trkpts.index

  for i in r:

    lati =
trkpts.ix[i,'Lat']

    loni =
trkpts.ix[i,'Lon']

    md =
manhattan_distance1(lat, lon, lati, loni)

    if d
> md

     
best = i

     
d = md

  return best

如果将 Manhattan_distance
函数体换进来,速度还可以快些:  
 

def closest_manhattan_distance2(lat,lon,trkpts):

  d = 100000.0

  best = -1

  r = trkpts.index

  for i in r:

    lati =
trkpts.ix[i,'Lat']

    loni =
trkpts.ix[i,'Lon']

    md =
abs(lat-lati) abs(lon-loni)

    if d
> md

     
best = i

     
d = md

  return best

在计算的最短距离点上,用这个函数与用 John's 的函数效果相同。我希望我的直觉是对的。越简单就越快。现在这个程序用了 2 分 37
秒。提速了 18%。 很好,但还不够激动人心。

我决定正确使用 Python。这意味着要利用 pandas 支持的数组运算。这些数组运算操作源于 numpy
包。通过调用这些数组操作,代码实现更简练:  
 

def closest(lat,lon,trkpts):

  cl = numpy.abs(trkpts.Lat - lat)
numpy.abs(trkpts.Lon - lon)

  return cl.idxmin()

该函数与之前函数的返回结果相同。在我的笔记本上运行时间花费了 0.5 秒。整整快了 300 倍! 300 倍,,也即30,000
%。不可思议。 提速的原因是 numpy 数组操作运算用 C 实现。因此, 我们将最好的两面结合起来了: 我们得到 C 的速度和
Python 的简洁性。

教训很明确:别用 C 的方式写 Python 代码。用 numpy 数组运算,不要用数组遍历。对我来说,这是思维上的转变。

Update on July 2, 2015。文章讨论在Hacker News。一些评论没有注意到(missed )我用到了
pandas 数据帧的情况。主要是它在数据分析中很常用。如果我只是要快速的查询最短距离点,且我时间充分,我可以使用 C 或 C
编写四叉树(实现)。

Second update on July 2, 2015。有个评论提到 numba 也能对代码提速。我就试了一下。

这是我的做法,与你的情况不一定相同。 首先,要说明的是,不同的 python 安装版,实验的结果不一定相同。我的实验环境是
windows 系统上安装 Anaconda,同时也安装了一些扩展包。可能这些包和 numba 存在干扰。.

首先,输入下面的安装命令,安装 numba:  
 

$ conda install numba

这是我命令行界面上的反馈:

之后我发现,numba 在 anaconda 安装套件中已存在。 也可能安装指令有变更也说不定。

推荐的 numba 用法:  
 

@jit

def closest_func(lat,lon,trkpts,func):

  d = 100000.0

  best = -1

  r = trkpts.index

  for i in r:

    lati =
trkpts.ix[i,'Lat']

    loni =
trkpts.ix[i,'Lon']

    md = abs(lat
- lati) abs(lon - loni)

    if d
> md:

     
#print d, dlat, dlon, lati, loni

     
best = i

     
d = md

  return best



我没有发现运行时间提高。我也尝试了更积极的编译参数设置:  
 

@jit(nopython=True)

def closest_func(lat,lon,trkpts,func):

  d = 100000.0

  best = -1

  r = trkpts.index

  for i in r:

    lati =
trkpts.ix[i,'Lat']

    loni =
trkpts.ix[i,'Lon']

    md = abs(lat
- lati) abs(lon - loni)

    if d
> md:

     
#print d, dlat, dlon, lati, loni

     
best = i

     
d = md

  return best

这次运行代码时,出现一个错误:




看来,pandas 比 numba 处理代码更智能。

当然,我也能花时间修改数据结构,使 numba 能正确编译(compile)。可是,我为什么要这么干呢? 用 numpy
写的代码运行的足够快了。反正,我一直在用 numpy 和 pandas 。为什么不继续用呢?

也有建议我用pypy。这当然有意义,不过…我用的是托管服务器上的 Jupyter notebooks(注,在线浏览器的 python
交互式开发环境)。我用的是它提供的 python 内核,也即,官方的(regular)Python 2.7.x 内核。并没有提供
Pypy 选择。

也有建议用 Cython。好吧,如果我回头要编译代码 ,那我干脆直接用 C 和 C 就好了。我用 python,是因为,它提供了基于
notebooks(注:网页版在线开发环境)的交互式特性,可以快速原型实现。这却不是 Cython 的设计目标。

http://www.cda.cn/view/25735.html的更多相关文章

  1. SQL面试题-行列互换-if、【case when】

    http://www.cda.cn/view/21469.html tb_lemon_grade中,表中字段id,student_name,course,score分别表示成绩id,学生姓名,课程名称 ...

  2. 产品运营数据分析—SPSS数据分组案例

    产品运营数据分析-SPSS数据分组案例 当我们的样本量过大,譬如以前讲过的,EXCEL2010最大只支持1048576行.16384列,尤其是当行数大于30万,一般的办公电脑处理都比较吃力,所以推荐数 ...

  3. 在Excel多个工作表间快速切换的绝招

    在Excel多个工作表间快速切换的绝招 几乎每个Excel用户"数据分析师"都应该知道,如果一个Excel工作簿中包括许多个工作表,我们"数据分析师"可以通过单 ...

  4. SaaS领域如何分析收入增长?

    SaaS领域如何分析收入增长? 今天我们试着将其模式运用到收入增长上进行分析.这对常规收入的计算会极有帮助,例如企业级应用软件(SaaS)或消费者订阅业务. 列举某公司通过月度订阅获得营收为例,为了更 ...

  5. 如何不让Excel图表随源数据改变而改变

    如何不让Excel图表随源数据改变而改变 一般我们在用Excel时,经常会碰到一些问题,比如,如何才能不让Excel图表随源数据改变而改变呢,下面就谈一下,一般在默认情况下,Excel的图表在一个区域 ...

  6. 用Excel如何将文本转换为数字的七种方法

    用Excel如何将文本转换为数字的七种方法 当下,很多工作都会用到Excel,下面本文分步介绍了如何将包含文本的Excel单元格转换为包含数字的单元格. 概述: 当导入在另一程序(如 dBASE 或  ...

  7. 实时更新Excel文档外部数据源的数据

    实时更新Excel文档外部数据源的数据 单元格区域.Excel 表.数据透视表或数据透视图均可以连接到外部数据源(数据源:用于连接数据库的一组存储的"源"信息.数据源包含数据库服务 ...

  8. 数据分析电子商务B2C全流程_数据分析师

    数据分析电子商务B2C全流程_数据分析师 目前,绝大多数B2C的转化率都在1%以下,做的最好的也只能到3.5%左右(比如以卖图书为主的当当) 我想,所有的B2C都会关心三个问题:究竟那97%去了哪里? ...

  9. C2B电商三种主要模式的分析_数据分析师

    C2B电商三种主要模式的分析_数据分析师 在过去的一年中电商领域血雨腥风,尤其是天猫.京东.苏宁.当当.易讯等B2C电商打得不亦乐乎.而随着B2C领域竞争进入白热化阶段,C2B模式也在天猫" ...

随机推荐

  1. PaaS容器集群优化之路

    1. 性能优化面对的挑战 以下是整个PaaS平台的架构 其中主要包括这些子系统: 微服务治理框架:为应用提供自动注册.发现.治理.隔离.调用分析等一系列分布式/微服务治理能力,屏蔽分布式系统的复杂度. ...

  2. mongodb索引 过期索引

    过期索引,指的是一段时间后会过期的索引,在索引过期后,相应的数据会被删除,这适合存储一些在一段时间之后会失效的数据,比如用户的登录信息,想要用户登录信息2天后失效,需要用户重新登录,或者存储的日志,希 ...

  3. 使用java中的反射获得object对象的属性值

    知识点:使用java中的反射获得object对象的属性值 一:场景 这两天开发代码时,调用别人的后台接口,返回值为Object对象(json形式的),我想获得object中指定的属性值,没有对应的ge ...

  4. Java基础 static限定符的使用 以及【 static实现的 singleton(单例)设计模式】

    static实现的 singleton(单例)设计模式 /** static实现的 singleton设计模式 , 使得一个类只能够创建一个static对象 */ 模板设计结构: package Co ...

  5. TCP/UDP Socket调试工具提供了TCP Server,TCP Client,UDP Server,UDP Client,UDP Group 五种Socket调试方案。

    一.TCP通信测试: 1)   创建TCP Server: 选中左方的TCP Server, 然后点击”创建”按钮,软件弹出监听端口输入框 输入监听端口后,即创建了一个在指定端口上进行监听的TCP S ...

  6. nginx中ngx_http_access_module模块

    实现基于IP的访问控制功能指令:4.1 allow允许访问指定的⽹网络或地址Syntax: allow address | CIDR | unix:| all;Default: —Context: h ...

  7. vue前端项目优化策略

    vue前端项目有什么优化策略? .生成打包报告.(可以发现一些问题,并进行解决)2.使用第三方库启用CDN加载3.使用Element-ui的话,按需加载组件4.使用路由懒加载 生成打包报告: .生成打 ...

  8. 设置了msconfig处理器个数和内存开不了机终极解决办法

    1.进入 启动修复 的 命令提示符(最好是使用有管理员权限的,不过普通用户我也每试过), 使用 bcdedit 命令来查看. 2.可以查看到你的启动参数. 确认 truncatememory 是否为 ...

  9. [Google Guava] 3-缓存

    原文地址  译文地址    译者:许巧辉  校对:沈义扬 范例 01 LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder() ...

  10. 10、组件注册-@Import-使用ImportBeanDefinitionRegistrar

    10.组件注册-@Import-使用ImportBeanDefinitionRegistrar public interface ImportBeanDefinitionRegistrar { /** ...