既然倒霉与蛋疼的事情有时候真·无能为力,写点东西能舒缓心情,就小写一篇。
其中有两个轮子,
轮子1:生成维数任意的索引组合的遍历,每个维度长度可指定;(有一说一,实现方式还是很dirty)
轮子2:基于轮子1的一个抽样方法,支持放回/不放回的抽样,比较适用于各种蒙特卡洛过程。
说件比较舒适的事情,本人喜欢造各种轮子,但如果造完没有继续使用/重构优化再使用,那么其实没啥意义。轮子1呢是我大约半年前就造出来了,当时似乎是为了解决深度学习中构造一种更通用的onehot编码,通用其实除了维度可扩展之外而且也不是onehot了(这块轮子内容后面有空再表吧)。于是最近写图像检测相关的算法时居然又需要这个轮子1以及在其基础上造的轮子2(关于这个图像检测的轮子也以后再说)。然后顺利的找到了之前的方法,这个感觉就很不错了。
这件舒适的事情就发生在昨天,同样是在昨天丢了东西,但是今天才发现。
如果仅仅只是有用的时候才想起,那么当你再想起的时候找不见的机会会更大。 ----丢东西和丢人都适用这个特性
下面废话不多说,上轮子,只有短短几行,活用eval,实现了不俗的功能。其实光听轮子名和演示结果,就应该很好理解:
import random
def nd_inx_li(nd_shape):
"""
产生任意维度的shape下的所有索引的组合
:param nd_shape: 维度信息 如 (5,4)
:return: 输出为所有索引组合的列表,可直接迭代,列表元素为tuple,每个tuple的长度等于维度数
"""
iter_li = ['for x%s in range(%s)' % (ix, nd_shape[ix]) for ix in range(len(nd_shape))]
iter_ss = ' '.join(iter_li)
tuple_ss = '(%s,)' % ','.join(['x%s' % ix for ix in range(len(nd_shape))])
return eval('[%s %s]' % (tuple_ss, iter_ss)) # pix 索引的-1维度的位置
def random_arrange_nd(nd_shape, length=10, with_playback=False):
"""
任意维度所有排列的随机抽取输出,注意不是组合
:param nd_shape: 维度信息 如 (5,4)
:param length: 抽取次数
:param with_playback: 是否有放回
:return: 和 nd_inx_li的输出格式一致
"""
inx_li = nd_inx_li(nd_shape)
if with_playback:
return [random.choice(inx_li) for _ in range(length)]
else:
random.shuffle(inx_li)
return inx_li[:length]
轮子1就是nd_inx_li方法,看下使用它的效果:
是不是很好理解,输出列表的元素个数即输入的所有维度取值数的乘积。
接下来是轮子2,它可以对轮子1的结果样本进行随机采样,用在(多通)图像中做像素点随机采样还是很合适的:
其实也很好理解,第一个输入参数(2,4)指定了第一维度有两个元素,第二维度有4个元素,所有的排列是8种情况。
1.所以无放回的采样就只有8个
2.有放回的 with_playback=True 无论排列数够不够都可以取到参数 length 个
3.由于是蒙特卡洛过程,实际基于random模块实现,故每次的输出都不一样。
最后,欢迎关注我的github对应部分代码