日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

python从数组中随机选择一些元素_numpy.random随机选择数组元素如何更高效

發(fā)布時(shí)間:2024/3/12 python 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python从数组中随机选择一些元素_numpy.random随机选择数组元素如何更高效 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最近在看代碼庫(kù)rlkit時(shí),發(fā)現(xiàn)一句有意思的代碼和注釋(如下所示),大意是從列表中隨機(jī)選擇一個(gè)元素時(shí)使用np.random.randint比np.random.choice更加高效,相關(guān)的解釋是np.random.choice會(huì)進(jìn)行一些不必要的復(fù)制操作,使得效率相較于randint低一些。

possible_future_obs_idxs = self._idx_to_future_obs_idx[i]

# This is generally faster than random.choice.

# Makes you wonder what random.choice is doing

num_options = len(possible_future_obs_idxs)

next_obs_i = int(np.random.randint(0, num_options))

future_obs_idxs.append(possible_future_obs_idxs[next_obs_i])

我做了相關(guān)的實(shí)驗(yàn)進(jìn)行對(duì)比,發(fā)現(xiàn)使用np.random.random的實(shí)現(xiàn)比np.random.randint更快,并且是否使用參數(shù)size=1對(duì)結(jié)果的影響也很大,文末進(jìn)行了總結(jié)。

1. random, randint, choice

生成長(zhǎng)度為1e6的隨機(jī)array,從中隨機(jī)選擇1個(gè)數(shù)和1000個(gè)數(shù),比較兩種情況下運(yùn)行速度,測(cè)試代碼如下:

import numpy as np

import time

N = 1000000

array = np.random.random(N)

def random(N=N): # 使用random隨機(jī)選擇1個(gè)數(shù)

return array[int(np.random.random() * N)]

def random_size1(N=N):# 使用random(size=1)隨機(jī)選擇1個(gè)數(shù)

return array[int(np.random.random(size=1) * N)]

def random_size_n(n, N=N): # 使用random隨機(jī)選擇n個(gè)數(shù)

return array[(np.random.random(n) * N).astype(np.int)]

def randint(N=N):# 使用randint隨機(jī)選擇1個(gè)數(shù)

return array[np.random.randint(N)]

def randint_size1(N=N): # 使用randint(size=1)隨機(jī)選擇1個(gè)數(shù)

return array[np.random.randint(N, size=1)]

def randint_size_n(n, N=N): # 使用randint隨機(jī)選擇n個(gè)數(shù)

return array[np.random.randint(N,size=n)]

def choice(array=array): # 使用choice隨機(jī)選擇1個(gè)數(shù)

return np.random.choice(array)

def choice_size1(array=array): # 使用choice(size=1)隨機(jī)選擇1個(gè)數(shù)

return np.random.choice(array, size=1)

def choice_size_n(n, array=array): # 使用choice隨機(jī)選擇n個(gè)數(shù)

return np.random.choice(array, size=n)

test_funs = [random, random_size1, randint, randint_size1, choice, choice_size1]

test_randn_funs = [random_size_n, randint_size_n, choice_size_n]

def test_main(mode, times=1000000):

test_fun = test_funs[mode]

start = time.time()

for _ in range(times):

test_fun()

end = time.time()

print('test {} {} times using time {} s'.format(test_fun, times, end - start))

def test_randn_main(mode,n=1000, times=1000000):

test_fun = test_randn_funs[mode]

start = time.time()

for _ in range(times):

test_fun(n)

end = time.time()

print('test {} {} times using time {} s'.format(test_fun, times, end - start))

if __name__ == "__main__":

for i in range(6):

test_main(i)

for i in range(3):

test_randn_main(i)

進(jìn)行1e6次的實(shí)驗(yàn)結(jié)果(單位:s):

更直觀(guān)的使用ipython的%timeit的結(jié)果:

import numpy as np

N = 1000

%timeit int(np.random.random() * N)

446 ns ± 3.21 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit np.random.randint(N)

908 ns ± 4.11 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit np.random.randint(N, size=1)

1.29 μs ± 5.42 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

以上實(shí)驗(yàn)結(jié)果在不同環(huán)境中跑會(huì)有些許誤差,但是應(yīng)該能得到以下結(jié)論:隨機(jī)選擇一個(gè)數(shù)時(shí),random最快,速度是randint的2倍;

隨機(jī)選擇一個(gè)數(shù)時(shí),不指定size=1的參數(shù)更快,以random為例,速度差異能到5倍左右;

隨機(jī)選擇n個(gè)數(shù)時(shí),指定size=n,randint最快。

以下是我的猜測(cè)和解釋,如有問(wèn)題歡迎指出:choice會(huì)有內(nèi)存申請(qǐng)和復(fù)制array的操作,通常是最慢的;

指定size會(huì)有內(nèi)存申請(qǐng)的操作,并且會(huì)轉(zhuǎn)化為ndarray類(lèi)型,因此產(chǎn)生一個(gè)隨機(jī)數(shù)時(shí)不指定size=1更快;

random的輸出是python的float類(lèi)型,指定size后是ndarray類(lèi)型,乘以N時(shí),float類(lèi)型和N都直接進(jìn)行python的float類(lèi)型運(yùn)算,而ndarray乘以N多進(jìn)行了數(shù)據(jù)轉(zhuǎn)化和傳遞操作(轉(zhuǎn)化為numpy的類(lèi)型并傳入底層進(jìn)行運(yùn)算,可以參考這個(gè)問(wèn)題https://www.zhihu.com/question/24789359/answer/55643155),randint內(nèi)部實(shí)現(xiàn)其實(shí)是一樣的,但是乘以N的操作本身是在numpy的類(lèi)型中進(jìn)行的,減少了兩次數(shù)據(jù)轉(zhuǎn)化和傳遞,速度更快。

>>> x=np.random.random()

>>> type(x)

>>> y=np.random.random(size=1)

>>> type(y)

為了讓大家體會(huì)到數(shù)據(jù)格式轉(zhuǎn)化的耗時(shí),補(bǔ)充一個(gè)實(shí)驗(yàn),注意上面是np.random.random()乘以的是python的常數(shù),均為python內(nèi)置數(shù)據(jù)類(lèi)型的運(yùn)算,而如果乘以的是numpy數(shù)據(jù)類(lèi)型,結(jié)果可能不一樣:

import numpy as np

N = 1000

L = np.random.randint(1, N, size=N)

%timeit [np.random.randint(x) for x in L]

1.12 ms ± 87.9 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit [int(np.random.random() * x) for x in L]

2.68 ms ± 92.4 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)

## 可以看到這里使用np.random.random 反而比randint慢了,這是因?yàn)閤其實(shí)是numpy.int64的格式

# np.random.random()是python數(shù)據(jù)類(lèi)型,又涉及到numpy的數(shù)據(jù)格式轉(zhuǎn)換和數(shù)據(jù)傳遞。

>>>type(L[0])

numpy.int64

>>>type(np.random.random())

float

# 而當(dāng)我們將x轉(zhuǎn)換為int型后,再次得到了我們之前的結(jié)論

%timeit [int(np.random.random() * int(x)) for x in L]

638 μs ± 12.8 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

因?yàn)樯婕暗綌?shù)據(jù)格式轉(zhuǎn)化和向底層代碼的數(shù)據(jù)傳遞,簡(jiǎn)單的python內(nèi)置運(yùn)算可能比numpy更快,當(dāng)運(yùn)算較多時(shí),numpy并行的優(yōu)勢(shì)才能顯示出來(lái)。

2. 案例優(yōu)化

我們以rlkit的這段代碼為例進(jìn)行優(yōu)化,該段代碼的目的是從不等長(zhǎng)的列表組里對(duì)每個(gè)列表隨機(jī)選擇1個(gè)數(shù)據(jù)。這個(gè)案例特殊的地方在于列表組里有N個(gè)不等長(zhǎng)的子列表,還要考慮循環(huán)處理子列表的時(shí)間,使用numpy并行進(jìn)行向量對(duì)應(yīng)位相乘速度更快,選擇random_idx的過(guò)程能夠加速80倍左右。

import numpy as np

N = 1000

L = np.random.randint(1, N, size=N) # 子列表的長(zhǎng)度

%timeit random_idx = (np.random.random(N) * L).astype(np.int)

13 μs ± 419 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit random_idx = [np.random.randint(x) for x in array_len]

1e+03 μs ± 22.1 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

3. Take Awaynumpy的運(yùn)算會(huì)涉及到數(shù)據(jù)格式轉(zhuǎn)化和向底層代碼的數(shù)據(jù)傳遞,當(dāng)運(yùn)算比較少時(shí)python內(nèi)置運(yùn)算可能比numpy更快,所以要注意運(yùn)算量的類(lèi)型,numpy的優(yōu)勢(shì)在于大規(guī)模的并行計(jì)算;

隨機(jī)選擇一個(gè)數(shù)時(shí),盡量避免設(shè)置size=1,不設(shè)置size的運(yùn)行速度從快到慢為:random > randint > choice;

隨機(jī)選擇n個(gè)數(shù)時(shí),由于randint(size=n)內(nèi)置了random(size=n) * N的操作,比外部實(shí)現(xiàn)的random(size=n) * N少了兩次數(shù)據(jù)轉(zhuǎn)化而更快,速度從快到慢為:randint > random > choice。

總結(jié)

以上是生活随笔為你收集整理的python从数组中随机选择一些元素_numpy.random随机选择数组元素如何更高效的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。