我需要一些帮助来优化 python 代码

Posted

技术标签:

【中文标题】我需要一些帮助来优化 python 代码【英文标题】:I need some help to optimize a python code 【发布时间】:2014-12-23 04:55:46 【问题描述】:

我正在使用 Python 开发 KNN 分类器,但我遇到了一些问题。 以下代码需要 7.5s-9.0s 才能完成,我必须运行 60.000 次。

        for fold in folds:  
            for dot2 in fold:
                """
                distances[x][0] = Class of the dot2
                distances[x][1] = distance between dot1 and dot2
                """
                distances.append([dot2[0], calc_distance(dot1[1:], dot2[1:], method)])

“folds”变量是一个包含 10 个折叠的列表,总和包含 60.000 个 .csv 格式的图像输入。每个点的第一个值是它所属的类。所有值都是整数。 有没有办法让这条线跑得更快?

这里是calc_distance函数

def calc_distancia(dot1, dot2, distance):

if distance == "manhanttan":
    total = 0
    #for each coord, take the absolute difference
    for x in range(0, len(dot1)):
        total = total + abs(dot1[x] - dot2[x])
    return total

elif distance == "euclidiana":
    total = 0
    for x in range(0, len(dot1)):
        total = total + (dot1[x] - dot2[x])**2
    return math.sqrt(total)

elif distance == "supremum":
    total = 0
    for x in range(0, len(dot1)):
        if abs(dot1[x] - dot2[x]) > total:
            total = abs(dot1[x] - dot2[x])
    return total

elif distance == "cosseno":
    dist = 0
    p1_p2_mul = 0
    p1_sum = 0
    p2_sum = 0
    for x in range(0, len(dot1)):
        p1_p2_mul = p1_p2_mul + dot1[x]*dot2[x]
        p1_sum = p1_sum + dot1[x]**2
        p2_sum = p2_sum + dot2[x]**2
    p1_sum = math.sqrt(p1_sum)
    p2_sum = math.sqrt(p2_sum)
    quociente = p1_sum*p2_sum
    dist = p1_p2_mul/quociente

    return dist

编辑: 至少对于“manhanttan”方法,找到了一种使其更快的方法。而不是:

    if distance == "manhanttan":
    total = 0
    #for each coord, take the absolute difference
    for x in range(0, len(dot1)):
        total = total + abs(dot1[x] - dot2[x])
    return total

我放了

    if distance == "manhanttan":
    totalp1 = 0
    totalp2 = 0
    #for each coord, take the absolute difference
    for x in range(0, len(dot1)):
        totalp1 += dot1[x]
        totalp2 += dot2[x]

    return abs(totalp1-totalp2)

abs() 调用很重

【问题讨论】:

这里有几个链接可能会有所帮助:wiki.python.org/moin/PythonSpeed/PerformanceTipsnbviewer.ipython.org/github/rasbt/python_reference/blob/master/… 请编辑您的答案以包含整个代码。还包括输入(或至少部分输入)。 “优化python代码的一些帮助”不是这里的主题问题。 稍后我将不得不发布代码。我不确定我是否可以发布所有这些,因为这是一项学校作业。我得问问我的老师我能不能做到。他使用一个程序来验证抄袭。 同时,您是否考虑过(a)使用 NumPy 并重组您的程序,以便它可以在数组上按元素广播操作而不是循环,(b)在 PyPy 或其他一些 JIT 下运行基于实现而不是 CPython,或者 (c) 使用 Cython 编译内部循环? 【参考方案1】:

“分析python”有很多指南;您应该搜索一些、阅读它们并完成分析过程,以确保您知道您的工作的哪些部分花费的时间最多。

但如果这真的是您工作的核心,那么可以肯定calc_distance 是消耗大部分运行时间的地方。

深度优化可能需要使用NumPy 加速数学或类似的低级方法。

作为一种需要较少侵入性分析和重写的快速而肮脏的方法,请尝试安装 Python 的 PyPy 实现并在其下运行。与标准 (CPython) 实现相比,我已经看到了 2 倍或更多的简单加速。

【讨论】:

【参考方案2】:

我很困惑。您是否尝试过探查器?

 python -m cProfile myscript.py

它将向您显示大部分时间都在哪里消耗,并提供可使用的硬数据。例如。重构以减少调用次数,重构输入数据,用这个函数代替那个,等等。

https://docs.python.org/3/library/profile.html

【讨论】:

我和我的老师谈过,他说时机成熟了。这需要很多时间。我使用了这些论点,它们对我有很大帮助。函数“calc_distance”需要大量时间来处理。我会努力让它更快。 你可以用 numpy array/s 改进很多。【参考方案3】:

首先,您应该避免使用单个calc_distance 函数,该函数在每次调用时在字符串列表中执行线性搜索。定义独立的距离函数并调用正确的函数。正如 Lee Daniel Crocker 建议的那样,不要使用切片,只需从 1 开始循环范围即可。

对于余弦距离,我建议对所有点向量进行一次归一化。这样距离计算就减少到点积了。

这些微优化可以为您带来一些加速。但是通过切换到更好的算法应该可以获得更好的收益:kNN 分类器调用kD-tree,这将允许您快速从考虑中删除大部分点。

这更难实现(您必须稍微适应不同的距离;余弦距离会使它变得棘手。)

【讨论】:

以上是关于我需要一些帮助来优化 python 代码的主要内容,如果未能解决你的问题,请参考以下文章

在python中尝试使用mapreduce的程序,并需要一些帮助

Python快速数据读入和切片

Python:优化循环

我需要一些帮助来纠正我在 php 中的代码 - 如何从 YouTube URL 获取视频 ID [重复]

优化boggle算法

用vscode编写Python