簡體   English   中英

為什么python numpy很慢?

[英]Why python numpy is slowly?

例如,對於gr = np.array([5, 4, 3, 5, 2])genx = np.array(["femy_gen_m", "my_gen_m", "my_gen_m", "femy_gen_m", "my_gen_m"]) ,輸出為{'my_gen_m': 3.0, 'femy_gen_m': 5.0} 暗示。 使用numpy平均值。

我為老師已經寫好的單元測試編寫了函數,但面臨函數處理緩慢的問題。

下面附上我的代碼。

from timeit import timeit
import numpy as np


#mycode
def mean_by_redneg(gr, genx):
    result = {}
    my_gen_m_sum, femy_gen_m_sum = [], []
    for index, element in enumerate(genx):
        if element == 'my_gen_m':
            my_gen_m_sum.append(gr[index])
        if element == 'femy_gen_m':
            femy_gen_m_sum.append(gr[index])
    result['my_gen_m'] = np.asarray(my_gen_m_sum).mean()
    result['femy_gen_m'] = np.asarray(femy_gen_m_sum).mean()
    return result

#check the function
def test(gr, genx, outp):
    ret = mean_by_redneg(np.array(gr), np.array(genx))
    assert np.isclose(ret['femy_gen_m'], outp['femy_gen_m'])
    assert np.isclose(ret['my_gen_m'], outp['my_gen_m'])


test([5, 4, 3, 5, 2], ["femy_gen_m", "my_gen_m", "my_gen_m", "femy_gen_m", "my_gen_m"], {'my_gen_m': 3.0, 'femy_gen_m': 5.0})
test([1, 0] * 10, ['femy_gen_m', 'my_gen_m'] * 10, {'femy_gen_m': 1, 'my_gen_m': 0})
test(range(100), ['femy_gen_m', 'my_gen_m'] * 50, {'femy_gen_m': 49.0, 'my_gen_m': 50.0})
test(list(range(100)) + [100], ['my_gen_m'] * 100 + ['femy_gen_m'], {'my_gen_m': 49.5, 'femy_gen_m': 100.0})


def bm_test(a, b):
    xx = 0
    yy = 0
    im = 0
    fi = 0
    for x, y in zip(a, b):
        if x != y:
            xx += x
            yy += x
            im += 1
            fi += 1
    return xx + yy


N = int(1E5)

gr = np.array([1.1] * N + [2.2] * N)
genx = np.array(['my_gen_m'] * N + ['femy_gen_m'] * N)

bm = timeit("assert np.isclose(mean_by_redneg(gr, genx)['my_gen_m'], 1.1)",
                   "from __main__ import np, mean_by_redneg, gr, genx",
                   number=1)
reference_bm = timeit("bm_test(gr, genx)",
                             "from __main__ import bm_test, gr, genx",
                             number=1)

assert reference_bm > bm * 10, "too slow"

你知道如何更快地完成這項工作嗎? ps謝謝你的時間

numpy執行此操作的矢量化方法比您的循環代碼簡單得多。 它的核心是這樣的:

out = {}
for gen in ['Male', 'Female']:
    out[gen] = grades[genders == gen].mean()

這是如何工作的:

genders == gen解析為一個TrueFalse數組,稱為“布爾索引”。 grades被它索引時,它返回與索引中為True的位置對應的grades值。 因此,當gen'Male'grades[genders == gen]對應於對應於'Male'的成績。 一旦你解析了這個數組,你就可以使用它的.mean()方法來計算平均值,並將它分配給字典。

這明顯更快,因為迭代/索引部分是在作為numpy后端的編譯的c代碼中完成的,而不是解釋的python代碼。

使用以下函數:

def mean_by_gender2(grades, genders):
    return { g: grades[genders == g].mean() for g in np.unique(genders) }

執行時間的比較(使用%timeit )顯示:

  1. 誠然,對於非常短的測試數據(每個數組中有 5 個項目),您的解決方案更快(您的:36 µs,我的:52.9 µs)。

  2. 但是,如果您采用更長的測試數據(每個數組中有 100 個項目),那么我的解決方案會更好(您的:99.5 µs,我的:62.6 µs)。

對於更長的源數據,我的解決方案的優勢應該更加明顯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM