我有一个60k行的数据文件,其中每行有〜1k个逗号分隔的Ints(我想立即变成Doubles)。
我要遍历32行的随机“批次”序列,其中批次是所有行的随机子集,并且没有批次共享相同的行。由于每批次有6万条生产线和32条生产线,因此应该有1875批。
我愿意在必要时进行更改,但是我希望它们以延迟评估的(批次)列表的形式出现。需要此代码的是foldM
,在这里我像这样使用它:
resulting_struct <- foldM fold_fn my_struct batch_list
,以便它对当前累加器fold_fn
和my_struct
的下一个元素的结果重复调用batch_list
。
我很困惑。当我不需要洗牌时,这很容易。我只是读入它们并将它们分块,然后对它们进行了懒惰的评估,因此我没有任何问题。现在我完全被困住了,觉得自己一定缺少一些简单的东西。
我尝试了以下操作:
-
将文件读入行列表并天真地对输入进行改组。这是行不通的,因为
readFile
的计算是延迟的,但是它需要将整个文件读入内存以随机地对其进行随机排序,并且它很快会耗尽我所有的〜8 GB RAM。 -
获取文件的长度,然后创建从0到60k的混洗的索引的批次列表,这些批次与将被选择以形成批次的行号相对应。然后,当我想实际获取数据批处理时,我会做:
ind_batches <- get_shuffled_ind_batches_from_file fname
batch_list <- mapM (get_data_batch_from_ind_batch fname) ind_batches
其中:
get_shuffled_ind_batches_from_file :: String -> IO [[Int]]
get_shuffled_ind_batches_from_file fname = do
contents <- get_contents_from_file fname -- uses readFile,returns [[Double]]
let n_samps = length contents
ind = [0..(n_samps-1)]
shuffled_indices <- shuffle_list ind
let shuffled_ind_chunks = take 1800 $ chunksOf 32 shuffled_indices
return shuffled_ind_chunks
get_data_batch_from_ind_batch :: String -> [Int] -> IO [[Double]]
get_data_batch_from_ind_batch fname ind_chunk = do
contents <- get_contents_from_file fname
let data_batch = get_elems_at_indices contents ind_chunk
return data_batch
shuffle_list :: [a] -> IO [a]
shuffle_list xs = do
ar <- newArray n xs
forM [1..n] $ \i -> do
j <- randomRIO (i,n)
vi <- readArray ar i
vj <- readArray ar j
writeArray ar j vi
return vj
where
n = length xs
newArray :: Int -> [a] -> IO (IOArray Int a)
newArray n xs = newListArray (1,n) xs
get_elems_at_indices :: [a] -> [Int] -> [a]
get_elems_at_indices my_list ind_list = (map . (!!)) my_list ind_list
但是,似乎mapM
会立即求值,然后尝试反复读取文件内容(我认为RAM仍然会耗尽)。
- 更多搜索告诉我,我可以尝试使用
unsafeInterleaveIO
使其变得懒惰地评估动作,因此我尝试将其粘贴如下:
get_data_batch_from_ind_batch :: String -> [Int] -> IO [[Double]]
get_data_batch_from_ind_batch fname ind_chunk = unsafeInterleaveIO $ do
contents <- get_contents_from_file fname
let data_batch = get_elems_at_indices contents ind_chunk
return data_batch
但是没有运气,和上面一样。
我觉得我的头一直撞在这里的墙上,肯定缺少一些非常简单的东西。有人建议改为使用流或管道,但是当我查看它们的文档时,对我来说还不清楚如何使用它们来解决此问题。
如何在不消耗全部内存的情况下读取大型数据文件并对其进行随机播放?