如何在Haskell中重复读取大数据文件的随机行?

我有一个60k行的数据文件,其中每行有〜1k个逗号分隔的Ints(我想立即变成Doubles)。

我要遍历32行的随机“批次”序列,其中批次是所有行的随机子集,并且没有批次共享相同的行。由于每批次有6万条生产线和32条生产线,因此应该有1875批。

我愿意在必要时进行更改,但是我希望它们以延迟评估的(批次)列表的形式出现。需要此代码的是foldM,在这里我像这样使用它:

resulting_struct <- foldM fold_fn my_struct batch_list

,以便它对当前累加器fold_fnmy_struct的下一个元素的结果重复调用batch_list

我很困惑。当我不需要洗牌时,这很容易。我只是读入它们并将它们分块,然后对它们进行了懒惰的评估,因此我没有任何问题。现在我完全被困住了,觉得自己一定缺少一些简单的东西。

我尝试了以下操作:

  1. 将文件读入行列表并天真地对输入进行改组。这是行不通的,因为readFile的计算是延迟的,但是它需要将整个文件读入内存以随机地对其进行随机排序,并且它很快会耗尽我所有的〜8 GB RAM。

  2. 获取文件的长度,然后创建从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仍然会耗尽)。

  1. 更多搜索告诉我,我可以尝试使用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

但是没有运气,和上面一样。

我觉得我的头一直撞在这里的墙上,肯定缺少一些非常简单的东西。有人建议改为使用流或管道,但是当我查看它们的文档时,对我来说还不清楚如何使用它们来解决此问题。

如何在不消耗全部内存的情况下读取大型数据文件并对其进行随机播放?

skcheung 回答:如何在Haskell中重复读取大数据文件的随机行?

hGetContents将延迟返回文件的内容,但是如果对结果进行任何操作,您将立即实现整个文件。我建议一次读取文件,然后在文件上扫描换行符,以便您可以建立一个索引,该索引以哪个字节偏移量开始。该索引会很小,因此您可以轻松地对其进行洗牌。然后,您可以遍历索引,每次打开文件并仅读取文件的已定义子范围,然后仅解析该块。

本文链接:https://www.f2er.com/3163069.html

大家都在问