通过实例浅析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字符串替换示例
Apr 24 Python
python中pygame模块用法实例
Oct 09 Python
wxPython使用系统剪切板的方法
Jun 16 Python
Python使用django框架实现多人在线匿名聊天的小程序
Nov 29 Python
Python Opencv实现图像轮廓识别功能
Mar 23 Python
python频繁写入文件时提速的方法
Jun 26 Python
pyecharts调整图例与各板块的位置间距实例
May 16 Python
Python中操作各种多媒体,视频、音频到图片的代码详解
Jun 04 Python
pycharm软件实现设置自动保存操作
Jun 08 Python
keras做CNN的训练误差loss的下降操作
Jun 22 Python
python基于爬虫+django,打造个性化API接口
Jan 21 Python
关于的python五子棋的算法
May 02 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
yii操作session实例简介
2014/07/31 PHP
php数组中删除元素之重新索引的方法
2014/09/16 PHP
原型方法的不同写法居然会影响调试的解决方法
2007/03/08 Javascript
js 实现日期灵活格式化的小例子
2013/07/14 Javascript
js判断ie版本号的简单实现代码
2014/03/05 Javascript
php的文件上传入门教程(实例讲解)
2014/04/10 Javascript
JS实现弹出浮动窗口(支持鼠标拖动和关闭)实例详解
2015/08/06 Javascript
深入理解JS DOM事件机制
2016/08/06 Javascript
BootStrap Typeahead自动补全插件实例代码
2016/08/10 Javascript
canvas绘制七巧板
2017/02/03 Javascript
最通俗易懂的javascript变量提升详解
2017/08/05 Javascript
nodejs结合socket.io实现websocket通信功能的方法
2018/01/12 NodeJs
JS实现二维数组元素的排列组合运算简单示例
2019/01/28 Javascript
[03:37]2014DOTA2国际邀请赛 主赛事第一日胜者组TOPPLAY
2014/07/19 DOTA
python矩阵的转置和逆转实例
2018/12/12 Python
浅谈python的输入输出,注释,基本数据类型
2019/04/02 Python
解决Pycharm双击图标启动不了的问题(JetBrains全家桶通用)
2020/08/07 Python
python之openpyxl模块的安装和基本用法(excel管理)
2021/02/03 Python
纯CSS3实现鼠标悬停提示气泡效果
2014/02/28 HTML / CSS
html5音频_动力节点Java学院整理
2018/08/22 HTML / CSS
aden + anais官方网站:婴儿襁褓、毯子、尿布和服装
2017/06/21 全球购物
美国糖果店:Sugarfina
2019/02/21 全球购物
大专应届生个人简历的自我评价
2013/10/15 职场文书
安全检查验收制度
2014/01/12 职场文书
书香家庭事迹材料
2014/05/09 职场文书
最美乡村医生事迹材料
2014/06/02 职场文书
做一个有道德的人活动实施方案
2014/08/23 职场文书
市级绿色学校申报材料
2014/08/25 职场文书
党员教师群众路线对照检查材料思想汇报
2014/09/29 职场文书
资产运营委托书范本
2014/10/16 职场文书
2014年收银工作总结
2014/11/13 职场文书
放弃遗产继承公证书
2015/01/26 职场文书
2015年村计划生育工作总结
2015/04/28 职场文书
归途列车观后感
2015/06/17 职场文书
阿里云服务器部署mongodb的详细过程
2021/09/04 MongoDB
Vue自定义铃声提示音组件的实现
2022/01/22 Vue.js