Re: [問題]不用for迴圈尋找陣列中只出現過一次的資料

作者: ccwang002 (亮)   2014-05-12 03:22:31
※ 引述《sariel0322 (sariel)》之銘言:
: 我想要請問一下,如果我有一串數字
: A = [9,5,5,4,7,6,4,1,2,0,10,9,7,....]
: 要如何找出這列資料中只出現一次的數字,但不用到for迴圈的方法
(冏冏,我看成有出現就好…… 明天再補了 > <)
完整檔案見 IPython Notebook
http://nbviewer.ipython.org/gist/ccwang002/bc1b047d0eca2c8f8bdd
這真的要快的話,就不應該自己寫 for loop,所以我想得到最快的方法就是用 set(A)
但有沒有更快的方式呢?其中一個可能是用 Cython, cffi 自己刻一個,
但 numpy.unique() 不知道快不快? 直覺上以為是會快很多的,所以來個實測。
# Test by IPython on Python 3.4
import numpy as np
LEN = 10**7 # 約需要總共 200MB 的記憶體
# 整數
A = np.random.randint(0, 100, LEN) # numpy 陣列 (ndarray)
A_list = A.tolist() # 一般的 list
%timeit -n 5 np.unique(A) # numpy 解法
%timeit -n 5 set(A_list) # set() 解法
%timeit set(A) # 混用,對 numpy 陣列用 set()
# 448ms, 232ms, 1.67s
# 5.18s, 2.31s, - s if LEN = 10**8
結果 set() 跑得比 np.unique() 還快,蠻驚訝的 > < 資料量調大仍舊相同的趨勢。
混用很可怕,這小測試暗示 ndarray 用內建函式的時候,很可能會做非常多轉換,
很容易拖慢速度。而內建的指令其實速度飛快。
但這樣 numpy 哪裡有優勢,是否該洗洗睡?我猜它在浮點數表現就會好很多,
浮點數找相同的數值有點怪,但總之要幫 numpy 平反也不管這麼多了xd
# 浮點數版本,只會有 0.0, 0.1, 0.2, ...
A = np.random.randint(0, 100, LEN) / 10
A_list = A.tolist()
%timeit -n 5 np.unique(A)
%timeit -n 5 set(A_list)
%timeit -n 5 set(A)
# 698ms, 1.55s, 2.23s
果然 numpy 的效率就好很多。
恩…總之蠻好玩的。
PS Py 3.4 中多了 tracemalloc module 可以追蹤程式執行間記憶體用量
https://docs.python.org/3/library/tracemalloc.html
看 Python 物件記憶體用量(?) 可用 sys.getsizeof(obj)
看 Numpy .............. 可用 ndarray_obj.nbytes
作者: timTan (用口頭禪區分年記)   2014-05-12 11:09:00
作者: apua (Apua)   2014-05-12 11:22:00
關於記憶體用量, 筆記中有些地方我不懂為什麼用 numpy 做出 A 之後, 記憶體用量還不大; 做出 A.list之後, A.nbytes 就隨之暴增了? A.nbytes 是 A 物件的大小對嗎所以可以理解成 A (numpy obj) 會在被操作時多做些事情?
作者: ya790206 (殘雲奪月)   2014-05-12 21:30:00
python set 的實作是用 C 寫的,使用 hash 演算法python list 所佔用的記憶體大小是 header +指標大小*預留空間大小,所以也不算太佔空間

Links booklink

Contact Us: admin [ a t ] ucptt.com