热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

在Python中实现Horner方法的问题

如何解决《在Python中实现Horner方法的问题》经验,为你挑选了2个好方法。

所以我用三种不同的方法写下了用于评估多项式的​​代码.霍纳的方法应该是最快的,而天真的方法应该是最慢的,对吗?但是,为什么计算它的时间不是我所期望的呢?对于itera和naive方法,计算时间有时会变得完全相同.它出什么问题了?

import numpy.random as npr
import time

def Horner(c,x):
    p=0
    for i in c[-1::-1]:
        p = p*x+i
    return p

def naive(c,x):
    n = len(c)
    p = 0
    for i in range(len(c)):
        p += c[i]*x**i 
    return p

def itera(c,x):
    p = 0
    xi = 1
    for i in range(len(c)):
        p += c[i]*xi
        xi *= x 
    return p

c=npr.uniform(size=(500,1))
x=-1.34

start_time=time.time()
print Horner(c,x)
print time.time()-start_time

start_time=time.time()
print itera(c,x)
print time.time()-start_time

start_time=time.time()
print naive(c,x)
print time.time()-start_time

以下是一些结果:

[  2.58646959e+69]
0.00699996948242
[  2.58646959e+69]
0.00600004196167
[  2.58646959e+69]
0.00600004196167

[ -3.30717922e+69]
0.00899982452393
[ -3.30717922e+69]
0.00600004196167
[ -3.30717922e+69]
0.00600004196167

[ -2.83469309e+69]
0.00999999046326
[ -2.83469309e+69]
0.00999999046326
[ -2.83469309e+69]
0.0120000839233

Paul Draper.. 16

您的分析可以大大改进.此外,我们可以使您的代码运行速度提高200-500倍.


(1)冲洗并重复

由于两个原因,您无法仅运行性能测试的一次迭代.

    你的时间分辨率可能不够好.这就是为什么你有时会为两个实现获得相同的时间:一次运行的时间接近你的计时机制的分辨率,所以你只记录了一个"tick".

    各种因素会影响性能.对于有意义的比较而言,最​​好的选择是进行大量的迭代.

你不需要进行大量的运行(当然,这并没有伤害),但你估计并调整迭代次数,直到方差在你的目的可接受的水平之内.

timeit 是一个很好的小模块,用于分析Python代码.

我将其添加到脚本的底部.

import timeit

n = 1000

print 'Horner', timeit.timeit(
    number = n,
    setup='from __main__ import Horner, c, x',
    stmt='Horner(c,x)'
)
print 'naive', timeit.timeit(
    number = n,
    setup='from __main__ import naive, c, x',
    stmt='naive(c,x)', 
)
print 'itera', timeit.timeit(
    number = n,
    setup='from __main__ import itera, c, x',
    stmt='itera(c,x)', 
)

哪个产生

Horner 1.8656351566314697
naive 2.2408010959625244
itera 1.9751169681549072

霍纳是最快的,但它并没有完全打破其他两个门.


(2)仔细看看发生了什么......

Python有运算符重载,所以很容易错过这个.

npr.uniform(size=(500,1)) 给你一个500 x 1 numpy结构的随机数.

所以呢?

好吧,c[i]不是一个数字.这是一个有一个元素的numpy数组.Numpy会重载运算符,因此您可以执行诸如使用标量乘以数组之类的操作.

这很好,但是为每个元素使用数组会产生大量开销,因此很难看出算法之间的差异.

相反,让我们尝试一个简单的Python列表:

import random
c = [random.random() for _ in range(500)]

现在,

Horner 0.034661054611206055
naive 0.12771987915039062
itera 0.07331395149230957

哇! 所有的时间都变得更快(10-60倍).按比例,霍纳的实施比其他两个更快.我们删除了所有三个的开销,现在可以看到"裸骨"的差异.

Horner比天真快4倍,比itera快2倍.


(3)备用运行时

你正在使用Python 2.我假设2.7.

让我们看看Python 3.4的票价.(语法调整:你需要在参数列表周围添加括号print.)

Horner 0.03298933599944576
naive 0.13706714100044337
itera 0.06771054599812487

差不多.

让我们试试PyPy,一个Python的JIT实现.("普通"Python实现称为CPython.)

Horner 0.006507158279418945
naive 0.07541298866271973
itera 0.005059003829956055

太好了!现在每个实现的运行速度提高了2-5倍.霍纳现在是天真的速度的10倍,但比itera略慢.

JIT运行时比解释器更难以分析.让我们将迭代次数增加到50000,并尝试确保它.

Horner 0.12749004364013672
naive 3.2823100090026855
itera 0.06546688079833984

(请注意,我们有50倍的迭代次数,但只有20倍的时间...... JIT在前1000次运行中的许多次都没有完全生效.)相同的结论,但差异更加明显.

当然,JIT的想法是在运行时分析,分析和重写程序,所以如果你的目标是比较算法,这将增加许多非显而易见的实现细节.

尽管如此,比较运行时可能有助于提供更广泛的视角.


还有一些事情.例如,您的天真实现计算它从未使用过的变量.你用range而不是xrange.您可以尝试使用索引而不是反向切片向后迭代.等等.

这些都没有改变我的结果,但他们值得考虑.



1> Paul Draper..:

您的分析可以大大改进.此外,我们可以使您的代码运行速度提高200-500倍.


(1)冲洗并重复

由于两个原因,您无法仅运行性能测试的一次迭代.

    你的时间分辨率可能不够好.这就是为什么你有时会为两个实现获得相同的时间:一次运行的时间接近你的计时机制的分辨率,所以你只记录了一个"tick".

    各种因素会影响性能.对于有意义的比较而言,最​​好的选择是进行大量的迭代.

你不需要进行大量的运行(当然,这并没有伤害),但你估计并调整迭代次数,直到方差在你的目的可接受的水平之内.

timeit 是一个很好的小模块,用于分析Python代码.

我将其添加到脚本的底部.

import timeit

n = 1000

print 'Horner', timeit.timeit(
    number = n,
    setup='from __main__ import Horner, c, x',
    stmt='Horner(c,x)'
)
print 'naive', timeit.timeit(
    number = n,
    setup='from __main__ import naive, c, x',
    stmt='naive(c,x)', 
)
print 'itera', timeit.timeit(
    number = n,
    setup='from __main__ import itera, c, x',
    stmt='itera(c,x)', 
)

哪个产生

Horner 1.8656351566314697
naive 2.2408010959625244
itera 1.9751169681549072

霍纳是最快的,但它并没有完全打破其他两个门.


(2)仔细看看发生了什么......

Python有运算符重载,所以很容易错过这个.

npr.uniform(size=(500,1)) 给你一个500 x 1 numpy结构的随机数.

所以呢?

好吧,c[i]不是一个数字.这是一个有一个元素的numpy数组.Numpy会重载运算符,因此您可以执行诸如使用标量乘以数组之类的操作.

这很好,但是为每个元素使用数组会产生大量开销,因此很难看出算法之间的差异.

相反,让我们尝试一个简单的Python列表:

import random
c = [random.random() for _ in range(500)]

现在,

Horner 0.034661054611206055
naive 0.12771987915039062
itera 0.07331395149230957

哇! 所有的时间都变得更快(10-60倍).按比例,霍纳的实施比其他两个更快.我们删除了所有三个的开销,现在可以看到"裸骨"的差异.

Horner比天真快4倍,比itera快2倍.


(3)备用运行时

你正在使用Python 2.我假设2.7.

让我们看看Python 3.4的票价.(语法调整:你需要在参数列表周围添加括号print.)

Horner 0.03298933599944576
naive 0.13706714100044337
itera 0.06771054599812487

差不多.

让我们试试PyPy,一个Python的JIT实现.("普通"Python实现称为CPython.)

Horner 0.006507158279418945
naive 0.07541298866271973
itera 0.005059003829956055

太好了!现在每个实现的运行速度提高了2-5倍.霍纳现在是天真的速度的10倍,但比itera略慢.

JIT运行时比解释器更难以分析.让我们将迭代次数增加到50000,并尝试确保它.

Horner 0.12749004364013672
naive 3.2823100090026855
itera 0.06546688079833984

(请注意,我们有50倍的迭代次数,但只有20倍的时间...... JIT在前1000次运行中的许多次都没有完全生效.)相同的结论,但差异更加明显.

当然,JIT的想法是在运行时分析,分析和重写程序,所以如果你的目标是比较算法,这将增加许多非显而易见的实现细节.

尽管如此,比较运行时可能有助于提供更广泛的视角.


还有一些事情.例如,您的天真实现计算它从未使用过的变量.你用range而不是xrange.您可以尝试使用索引而不是反向切片向后迭代.等等.

这些都没有改变我的结果,但他们值得考虑.



2> Sylvain Lero..:

通过测量这样的事情,你无法获得准确的结果:

start_time=time.time()
print Horner(c,x)
print time.time()-start_time

据推测,大部分时间都花在功能所涉及的IO print功能上.此外,为了获得重要的东西,您应该在大量迭代中执行度量以平滑错误.在一般情况下,您可能还希望对各种输入数据执行测试 - 根据您的算法,某些情况可能会巧合地解决,而不是其他情况.

你应该明确地看看timeit模块.这样的事情,也许:

import timeit
print 'Horner',timeit.timeit(stmt='Horner(c,x)', 
                  setup='from __main__ import Horner, c, x',
                  number = 10000)
#                          ^^^^^
#                probably not enough. Increase that once you will
#                be confident

print 'naive',timeit.timeit(stmt='naive(c,x)', 
                  setup='from __main__ import naive, c, x',
                  number = 10000)
print 'itera',timeit.timeit(stmt='itera(c,x)', 
                  setup='from __main__ import itera, c, x',
                  number = 10000)

在我的系统上生成这个:

Horner 23.3317809105
naive 28.305519104
itera 24.385917902

但是仍然有从运行到另一个的可变结果:

Horner 21.1151690483
naive 23.4374330044
itera 21.305426836

正如我之前所说,要获得更有意义的结果,您应该明确增加测试数量,并在几个测试用例上运行,以便平滑结果.


推荐阅读
  • 每年,意甲、德甲、英超和西甲等各大足球联赛的赛程表都是球迷们关注的焦点。本文通过 Python 编程实现了一种生成赛程表的方法,该方法基于蛇形环算法。具体而言,将所有球队排列成两列的环形结构,左侧球队对阵右侧球队,首支队伍固定不动,其余队伍按顺时针方向循环移动,从而确保每场比赛不重复。此算法不仅高效,而且易于实现,为赛程安排提供了可靠的解决方案。 ... [详细]
  • 本文探讨了基于点集估算图像区域的Alpha形状算法在Python中的应用。通过改进传统的Delaunay三角剖分方法,该算法能够生成更加灵活和精确的形状轮廓,避免了单纯使用Delaunay三角剖分时可能出现的过大三角形问题。这种“模糊Delaunay三角剖分”技术不仅提高了形状的准确性,还增强了对复杂图像区域的适应能力。 ... [详细]
  • Python错误重试让多少开发者头疼?高效解决方案出炉
    ### 优化后的摘要在处理 Python 开发中的错误重试问题时,许多开发者常常感到困扰。为了应对这一挑战,`tenacity` 库提供了一种高效的解决方案。首先,通过 `pip install tenacity` 安装该库。使用时,可以通过简单的规则配置重试策略。例如,可以设置多个重试条件,使用 `|`(或)和 `&`(与)操作符组合不同的参数,从而实现灵活的错误重试机制。此外,`tenacity` 还支持自定义等待时间、重试次数和异常处理,为开发者提供了强大的工具来提高代码的健壮性和可靠性。 ... [详细]
  • 利用 Python Socket 实现 ICMP 协议下的网络通信
    在计算机网络课程的2.1实验中,学生需要通过Python Socket编程实现一种基于ICMP协议的网络通信功能。与操作系统自带的Ping命令类似,该实验要求学生开发一个简化的、非标准的ICMP通信程序,以加深对ICMP协议及其在网络通信中的应用的理解。通过这一实验,学生将掌握如何使用Python Socket库来构建和解析ICMP数据包,并实现基本的网络探测功能。 ... [详细]
  • 本文介绍了UUID(通用唯一标识符)的概念及其在JavaScript中生成Java兼容UUID的代码实现与优化技巧。UUID是一个128位的唯一标识符,广泛应用于分布式系统中以确保唯一性。文章详细探讨了如何利用JavaScript生成符合Java标准的UUID,并提供了多种优化方法,以提高生成效率和兼容性。 ... [详细]
  • 探索聚类分析中的K-Means与DBSCAN算法及其应用
    聚类分析是一种用于解决样本或特征分类问题的统计分析方法,也是数据挖掘领域的重要算法之一。本文主要探讨了K-Means和DBSCAN两种聚类算法的原理及其应用场景。K-Means算法通过迭代优化簇中心来实现数据点的划分,适用于球形分布的数据集;而DBSCAN算法则基于密度进行聚类,能够有效识别任意形状的簇,并且对噪声数据具有较好的鲁棒性。通过对这两种算法的对比分析,本文旨在为实际应用中选择合适的聚类方法提供参考。 ... [详细]
  • 在处理大规模并发请求时,传统的多线程或多进程模型往往无法有效解决性能瓶颈问题。尽管它们在处理小规模任务时能提升效率,但在高并发场景下,系统资源的过度消耗和上下文切换的开销会显著降低整体性能。相比之下,Python 的 `asyncio` 模块通过协程提供了一种轻量级且高效的并发解决方案。本文将深入解析 `asyncio` 模块的原理及其在实际应用中的优化技巧,帮助开发者更好地利用协程技术提升程序性能。 ... [详细]
  • Pyhotn3基础笔记(上卷)吉多范罗苏姆(GuidovanRossum)一.解释器Python的解释器如今有多个语言的实现,包括&#x ... [详细]
  • 为什么python是动态类型语言_Python 3.7.0 面向对象的动态类型语言
    代表Python开发社区和Python3.7发布团队,我们很高兴地宣布https:www.python.orgdownloadsreleasepython-370 ... [详细]
  • 假设我有两个数组A和B,其中A和B都是mxn.我现在的目标是,对于A和B的每一行,找到我应该在B的相应行中插入A的第i行元素的位置.也就是说,我希望将np.digitize或np. ... [详细]
  • 开发笔记:python协程的理解
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了python协程的理解相关的知识,希望对你有一定的参考价值。一、介绍什么是并发?并发的本质就是 ... [详细]
  • 【原创】利用Python进行河流遥感处理的PyRIS软件开发
    今天开始着手改造pyris1.0.文章地址:https:doi.org10.1016J.ENVSOFT.2018.03.028Monegaglia,2 ... [详细]
  • 似乎有两种不同的方法可以将字符串转换为字节,如对typeerror的回答所示:str不支持缓冲区接口。这些方法中哪一种比较好或更适合用Python& ... [详细]
  • 通过使用 `pandas` 库中的 `scatter_matrix` 函数,可以有效地绘制出多个特征之间的两两关系。该函数不仅能够生成散点图矩阵,还能通过参数如 `frame`、`alpha`、`c`、`figsize` 和 `ax` 等进行自定义设置,以满足不同的可视化需求。此外,`diagonal` 参数允许用户选择对角线上的图表类型,例如直方图或密度图,从而提供更多的数据洞察。 ... [详细]
  • 分享一款基于Java开发的经典贪吃蛇游戏实现
    本文介绍了一款使用Java语言开发的经典贪吃蛇游戏的实现。游戏主要由两个核心类组成:`GameFrame` 和 `GamePanel`。`GameFrame` 类负责设置游戏窗口的标题、关闭按钮以及是否允许调整窗口大小,并初始化数据模型以支持绘制操作。`GamePanel` 类则负责管理游戏中的蛇和苹果的逻辑与渲染,确保游戏的流畅运行和良好的用户体验。 ... [详细]
author-avatar
KING树林_944
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有