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


Posted in Python onAugust 30, 2015

我一直使用 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

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

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

之后我发现,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

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

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

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

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

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

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

Python 相关文章推荐
python使用xauth方式登录饭否网然后发消息
Apr 11 Python
详解python的webrtc库实现语音端点检测
May 31 Python
使用Python快速搭建HTTP服务和文件共享服务的实例讲解
Jun 04 Python
Python3+django2.0+apache2+ubuntu14部署网站上线的方法
Jul 07 Python
linux安装Python3.4.2的操作方法
Sep 28 Python
python用WxPython库实现无边框窗体和透明窗体实现方法详解
Feb 21 Python
Python字典fromkeys()方法使用代码实例
Jul 20 Python
如何利用Python动态模拟太阳系运转
Sep 04 Python
python利用xlsxwriter模块 操作 Excel
Oct 14 Python
python切片作为占位符使用实例讲解
Feb 17 Python
Python基础之条件语句详解
Jun 16 Python
python数字图像处理实现图像的形变与缩放
Jun 28 Python
使用Python脚本将文字转换为图片的实例分享
Aug 29 #Python
Python中常见的数据类型小结
Aug 29 #Python
深入解析Python中的lambda表达式的用法
Aug 28 #Python
两个使用Python脚本操作文件的小示例分享
Aug 27 #Python
简介二分查找算法与相关的Python实现示例
Aug 26 #Python
使用Python的Bottle框架写一个简单的服务接口的示例
Aug 25 #Python
栈和队列数据结构的基本概念及其相关的Python实现
Aug 24 #Python
You might like
Mysql中limit的用法方法详解与注意事项
2008/04/19 PHP
thinkphp3.x中cookie方法的用法分析
2016/05/19 PHP
php 从一个数组中随机的取出若干个不同的数实例
2016/12/31 PHP
PHP操作路由器实现方法示例
2019/04/27 PHP
基于jquery的图片轮播 tab切换组件
2012/07/19 Javascript
利用JS进行图片的切换即特效展示图片
2013/12/03 Javascript
js调试工具console.log()方法查看js代码的执行情况
2014/08/08 Javascript
JavaScript中发布/订阅模式的简单实例
2014/11/05 Javascript
javascript作用域链(Scope Chain)用法实例解析
2015/11/30 Javascript
第二次聊一聊JS require.js模块化工具的基础知识
2016/04/17 Javascript
如何使用angularJs
2017/05/08 Javascript
mui 打开新窗口的方式总结及注意事项
2017/08/20 Javascript
详解Vue微信公众号开发踩坑全记录
2017/08/21 Javascript
mescroll.js上拉加载下拉刷新组件使用详解
2017/11/13 Javascript
使用vue-route 的 beforeEach 实现导航守卫(路由跳转前验证登录)功能
2018/03/22 Javascript
初学node.js中实现删除用户路由
2019/05/27 Javascript
Fiddler如何抓取手机APP数据包
2016/01/22 Python
python中matplotlib的颜色及线条控制的示例
2018/03/16 Python
python 找出list中最大或者最小几个数的索引方法
2018/10/30 Python
python 进程的几种创建方式详解
2019/08/29 Python
Python函数基本使用原理详解
2020/03/19 Python
Python如何获取文件指定行的内容
2020/05/27 Python
浅谈pycharm导入pandas包遇到的问题及解决
2020/06/01 Python
约瑟夫·特纳男装:Joseph Turner
2017/10/10 全球购物
世界顶级足球门票网站:Live Football Tickets
2017/10/14 全球购物
马来西亚奢侈品牌购物商城:Valiram 247
2020/09/29 全球购物
英文版销售经理个人求职信
2013/11/20 职场文书
优秀实习自我鉴定
2013/12/04 职场文书
就业协议书怎么填
2014/09/15 职场文书
劳模事迹材料范文
2014/12/24 职场文书
银行保安拾金不昧表扬稿
2015/05/05 职场文书
2015年街道除四害工作总结
2015/05/15 职场文书
篮球赛闭幕式主持词
2015/07/03 职场文书
特种设备安全管理制度
2015/08/06 职场文书
导游词之贵州百里杜鹃
2019/10/29 职场文书
V Rising 服务器搭建图文教程
2022/06/16 Servers