我需要填写一个文件,其中包含许多由数字标识的记录(测试数据)。记录数量非常大,id应该是唯一的,记录的顺序应该是随机的(或伪随机的)。
我试过了:
# coding: utf-8
import random
COUNT = 100000000
random.seed(0)
file_1 = open('file1', 'w')
for i in random.sample(xrange(COUNT), COUNT):
file_1.write('ID{0},A{0}\n'.format(i))
file_1.close()
但它正在吃掉我所有的记忆。
有没有办法生成一个连续的大洗牌序列(不一定但它会很好,否则是唯一的)整数?使用生成器而不是将所有序列保存在RAM中?
答案 0 :(得分:9)
如果问题中有1亿个数字,那么这实际上是可以在内存中管理的(大概需要0.5 GB)。
正如DSM指出的那样,这可以通过标准模块以有效的方式完成:
>>> import array
>>> a = array.array('I', xrange(10**8)) # a.itemsize indicates 4 bytes per element => about 0.5 GB
>>> import random
>>> random.shuffle(a)
也可以使用第三方NumPy软件包,它是用于以有效方式管理数组的标准Python工具:
>>> import numpy
>>> ids = numpy.arange(100000000, dtype='uint32') # 32 bits is enough for numbers up to about 4 billion
>>> numpy.random.shuffle(ids)
(这仅在您的程序已经使用NumPy时才有用,因为标准模块方法效率很高)。
这两种方法在我的机器上花费大约相同的时间(可能是1分钟的洗牌),但是它们使用的0.5 GB对于当前的计算机来说并不是太大。
PS :有太多的元素让重排变得非常随机,因为与使用的随机生成器的周期相比,可能存在太多的排列。换句话说,Python shuffle的数量少于可能的shuffle数量!
答案 1 :(得分:4)
也许类似的东西(不会是连续的,但会是唯一的):
from uuid import uuid4
def unique_nums(): # Not strictly unique, but *practically* unique
while True:
yield int(uuid4().hex, 16)
# alternative yield uuid4().int
unique_num = unique_nums()
next(unique_num)
next(unique_num) # etc...
答案 2 :(得分:0)
您可以通过阅读(在Linux上)/dev/urandom
或使用os.urandom()
和struct.unpack()
轻松获取随机int:
返回一串适合加密使用的n个随机字节。
此函数返回来自OS特定随机源的随机字节。对于加密应用程序,返回的数据应该是不可预测的,尽管其确切的质量取决于操作系统的实现。在类UNIX系统上,这将查询 / dev / urandom ,在Windows上,它将使用 CryptGenRandom 。如果未找到随机源,则会引发 NotImplementedError 。
>>> for i in range(4): print( hex( struct.unpack('<L', os.urandom(4))[0]))
...
0xbd7b6def
0xd3ecf2e6
0xf570b955
0xe30babb6
另一方面random
包裹:
但是,完全确定性,它并不适用于所有目的,并且完全不适合加密目的。
如果您真的需要唯一记录,则应使用this或answer provided by EOL。
但是假设真的是随机源,可能重复的字符,你会1/N
(N = 2 ** sizeof(int)*8 = 2 ** 32
)在第一次猜测时击中项目的机会,因此你可以获得(2**32) ** length
个可能的输出。
另一方面,当using just unique results you'll have max:
时product from i = 0 to length {2*32 - i}
= n! / (n-length)!
= (2**32)! / (2**32-length)!
!
是阶乘的,而非逻辑否定。所以你只会减少结果的随机性。
答案 3 :(得分:0)
这个会让你的记忆保持正常,但可能会杀死你的磁盘:)
它生成一个文件,其序列号为0到100000000,然后随机选择其中的位置并写入另一个文件。必须在第一个文件中重新组织这些数字,以“删除”已经选择的数字。
import random
COUNT = 100000000
# Feed the file
with open('file1','w') as f:
i = 0
while i <= COUNT:
f.write("{0:08d}".format(i))
i += 1
with open('file1','r+') as f1:
i = COUNT
with open('file2','w') as f2:
while i >= 0:
f1.seek(i*8)
# Read the last val
last_val = f1.read(8)
random_pos = random.randint(0, i)
# Read random pos
f1.seek(random_pos*8)
random_val = f1.read(8)
f2.write('ID{0},A{0}\n'.format(random_val))
# Write the last value to this position
f1.seek(random_pos*8)
f1.write(last_val)
i -= 1
print "Done"