我需要生成一个包含重复元素的大型数组,我的代码是:
np.repeat(xrange(x,y), data)
但是,数据是一个类型为float64的numpy数组(但它表示integeres,没有2.1),我得到错误
TypeError: Cannot cast array data from dtype('float64') to dtype('int64') according to the rule 'safe'
例:
In [35]: x
Out[35]: 26
In [36]: y
Out[36]: 50
In [37]: data
Out[37]:
array([ 3269., 106., 5533., 317., 1512., 208., 502., 919.,
406., 421., 1690., 2236., 705., 505., 230., 213.,
307., 1628., 4389., 1491., 355., 103., 854., 424.])
In [38]: np.repeat(xrange(x,y), data)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-38-105860821359> in <module>()
----> 1 np.repeat(xrange(x,y), data)
/home/pcadmin/anaconda2/lib/python2.7/site-packages/numpy /core/fromnumeric.pyc in repeat(a, repeats, axis)
394 repeat = a.repeat
395 except AttributeError:
--> 396 return _wrapit(a, 'repeat', repeats, axis)
397 return repeat(repeats, axis)
398
/home/pcadmin/anaconda2/lib/python2.7/site-packages/numpy /core/fromnumeric.pyc in _wrapit(obj, method, *args, **kwds)
46 except AttributeError:
47 wrap = None
---> 48 result = getattr(asarray(obj), method)(*args, **kwds)
49 if wrap:
50 if not isinstance(result, mu.ndarray):
TypeError: Cannot cast array data from dtype('float64') to dtype('int64') according to the rule 'safe'
我通过将代码更改为
来解决它np.repeat(xrange(x,y), data.astype('int64'))
然而,这是我的代码中最昂贵的行之一!!还有另一种选择吗?
顺便说一句,我在里面使用了这个
np.random.choice(np.repeat(xrange(x,y), data.astype('int64')), z)
为了获得样本而不用x和y之间的整数的大小z替换,并且在数据中给出每个的数量。我想这也是最好的方法呢?
答案 0 :(得分:4)
这一个非常有趣的问题!只是为了让读者在不涉及次要数据转换问题的情况下了解问题,我们有一系列的值,让我们说a = np.arange(5)
,即
a = np.array([0,1,2,3,4])
现在,让我们说我们有另一个数组,列出了5
中每个a
数字的重复次数。那么,让那些:
reps = np.array([2,4,6,2,2])
接下来,我们正在执行这些重复:
In [32]: rep_nums = np.repeat(a,reps)
In [33]: rep_nums
Out[33]: array([0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4])
最后,我们希望使用z
并且无需替换,从这些重复数字中选择np.random.choice()
个元素。
让我们说z = 7
选择7
元素,所以np.random.choice()
,我们会:{/ p>
In [34]: np.random.choice(rep_nums,7,replace=False)
Out[34]: array([2, 4, 0, 2, 4, 1, 2])
现在,这个without replacement
这个术语可能听起来很混乱,因为我们已经在rep_nums
中重复了这些数字。但是,它本质上意味着,np.random.choice()
的输出不能包含例如4's
。超过两个rep_nums
,因为4's
有两个np.repeat
。
所以,问题是我们想要摆脱rep_nums
部分,这可能是真正巨大数组的瓶颈。
查看z = 7
的输出,一个想法是生成rep_nums
范围内的In [44]: np.random.choice(rep_nums.size,7,replace=False)
Out[44]: array([ 7, 2, 4, 10, 13, 8, 3])
个唯一元素:
5
这些数字代表该长度的指数。因此,我们只需要在rep_nums
中查找7
个分区中的bin(np.searchsorted
个分区),其中每个x
数字都会进入。为此,我们可以使用{{ 1}}。因此,我们将有一个实现来处理泛型y
,# Get the intervals of those bins
intervals = data.astype(int).cumsum()
# Decide length of array if we had repeated with `np.repeat`
max_num = intervals[-1]
# Get unique numbers (indices in this case)
ids = np.random.choice(max_num,z,replace=False)
# Use searchsorted to get bin IDs and add in `x` offset
out = x+np.searchsorted(intervals,ids,'right')
,就像这样 -
def org_app(x,y,z,data):
rep_nums = np.repeat(range(x,y), data.astype('int64'))
out = np.random.choice(rep_nums, z,replace=False)
return out
def optimized_v1(x,y,z,data):
intervals = data.astype(int).cumsum()
max_num = intervals[-1]
ids = np.random.choice(max_num,z,replace=False)
out = x+np.searchsorted(intervals,ids,'right')
return out
运行时测试
功能:
In [79]: # Setup inputs
...: x = 100
...: y = 10010
...: z = 1000
...: data = np.random.randint(100,5000,(y-x)).astype(float)
...:
In [80]: %timeit org_app(x,y,z,data)
1 loop, best of 3: 7.17 s per loop
In [81]: %timeit optimized_v1(x,y,z,data)
1 loop, best of 3: 6.92 s per loop
关于全部职能的时间 -
np.repeat
看起来我们的速度并不快。让我们深入挖掘一下,找出我们在替换In [82]: %timeit np.repeat(range(x,y), data.astype('int64'))
1 loop, best of 3: 227 ms per loop
时节省了多少钱!
首先关闭原始方法 -
np.random.choice()
让我们看看我们采用所提出的方法对此有多大改进。所以,让我们在提议的方法中除In [83]: intervals = data.astype(int).cumsum()
...: max_num = intervals[-1]
...: ids = np.random.choice(max_num,z,replace=False)
...: out = x+np.searchsorted(intervals,ids,'right')
...:
In [84]: %timeit data.astype(int).cumsum()
10000 loops, best of 3: 36.6 µs per loop
In [85]: %timeit intervals[-1]
10000000 loops, best of 3: 142 ns per loop
In [86]: %timeit x+np.searchsorted(intervals,ids,'right')
10000 loops, best of 3: 127 µs per loop
之外的所有内容 -
227ms
这比np.repeat
的{{1}}要好得多!!
所以,我们希望在真正庞大的数组中,删除np.repeat
的好处真的会大放异彩,否则np.random.choice()
本身就会成为瓶颈。
答案 1 :(得分:4)
潜伏在问题中的是multivariate hypergeometric distribution。在Numpy drawing from urn中,我实现了一个从此分布中提取样本的函数。我怀疑它与答案中描述的@DiogoSantos解决方案非常相似。 Diogo说使用这种方法很慢,但我发现以下内容比Divakar optmized_v1
要快。
这是一个函数,它使用链接答案中的sample(n, colors)
来实现与Divakar函数具有相同签名的函数。
def hypergeom_version(x, y, z, data):
s = sample(z, data)
result = np.repeat(np.arange(x, y), s)
return result
(这将返回排序顺序中的值。如果您需要以随机顺序排列值,请在return语句之前添加np.random.shuffle(result)
。它不会显着改变执行时间。 )
比较:
In [153]: x = 100
In [154]: y = 100100
In [155]: z = 10000
In [156]: data = np.random.randint(1, 125, (y-x)).astype(float)
Divakar的optimized_v1
:
In [157]: %timeit optimized_v1(x, y, z, data)
1 loop, best of 3: 520 ms per loop
hypergeom_version
:
In [158]: %timeit hypergeom_version(x, y, z, data)
1 loop, best of 3: 244 ms per loop
如果data
中的值较大,则相对性能会更好:
In [164]: data = np.random.randint(100, 500, (y-x)).astype(float)
In [165]: %timeit optimized_v1(x, y, z, data)
1 loop, best of 3: 2.91 s per loop
In [166]: %timeit hypergeom_version(x, y, z, data)
1 loop, best of 3: 246 ms per loop
答案 2 :(得分:1)
为了完成,我还有一个替代实现。鉴于我们有value_unit
,我们可以为每个类使用超几何采样:
data
data.cumsum()
然而,当我们有很多班级,每个班级都很少,这需要很长时间。