作者ccwang002 (亮)
看板Python
标题Re: [问题]不用for回圈寻找阵列中只出现过一次的资料
时间Mon May 12 03:22:31 2014
※ 引述《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
--
PyCon APAC 2014/TW is coming! May 17-18 @中研院人社馆
More info on
https://tw.pycon.org/2014apac/zh/
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 140.112.217.22
※ 文章网址: http://webptt.com/cn.aspx?n=bbs/Python/M.1399836156.A.6F6.html
1F:推 timTan:赞 05/12 11:09
2F:推 apua:关於记忆体用量, 笔记中有些地方我不懂 05/12 11:22
3F:→ apua:为什麽用 numpy 做出 A 之後, 记忆体用量还不大; 做出 A.list 05/12 11:23
4F:→ apua:之後, A.nbytes 就随之暴增了? A.nbytes 是 A 物件的大小对吗 05/12 11:24
5F:→ apua:所以可以理解成 A (numpy obj) 会在被操作时多做些事情? 05/12 11:24
喔喔,我的猜测是 tracemalloc 它是在 python 分配记忆体的时候多加一个 hook
来记录每行程式记忆体的增减,但 numpy 在 malloc 的时候不是用 python 的版本
所以 tracemalloc 里会看不到 A (numpy obj) 的大小。
如果要看的话就要使用 numpy API 的 A.nbytes。
不过这个问题可能在 Py 3.5 + numpy 1.9(2.0?) 就会被解决了,python mail list
已经在讨论相关的可行性
http://bugs.python.org/issue21233
http://mail.scipy.org/pipermail/numpy-discussion/2014-April/069935.html
但我蛮意外的是两者的大小竟然差不多
我以为 numpy 的实作记忆体用量会小 list 的不少,是不是我搞错什麽了 @@
6F:→ ya790206:python set 的实作是用 C 写的,使用 hash 演算法 05/12 21:30
7F:→ ya790206:python list 所占用的记忆体大小是 header + 05/12 21:30
8F:→ ya790206:指标大小*预留空间大小,所以也不算太占空间 05/12 21:31
感谢分享!
※ 编辑: ccwang002 (140.112.129.20), 05/14/2014 11:34:06