Каков наиболее эффективный способ чтения файла CSV в массив ускорения (или Repa)?

Я заинтересован в игре с библиотекой Accelerate и хотел бы выполнить некоторые операции с данными, хранящимися в CSV-файле. Я прочитал это прекрасное введение в Accelerate, но я не уверен, как мне эффективно читать CSVs в Accelerate. Я думал об этом, и единственное, что я могу придумать, - это разобрать весь CSV-файл в один длинный список, а затем передать весь список в Accelerate.

Мои наборы данных будут довольно большими, и не представляется эффективным считывать файл объемом 1 ГБ + в память только для копирования в другое место. Я заметил, что на Hackage был пакет CSV Enumerator, но я не уверен, как использовать его с функцией генерирования Accelerate. Другое ограничение заключается в том, что кажется, что размеры массива или, по крайней мере, количество элементов должны быть известны до генерации массива с использованием Accelerate.

Кто-нибудь имел дело с такой проблемой раньше?

Спасибо!

2 ответа

Я не пробовал читать файлы CSV в repa, но я рекомендую использовать кассаву ( http://hackage.haskell.org/package/cassava). Iirc У меня был файл 1.5G, который я использовал для создания моей статистики. С кассавой моя программа работала на удивительно небольшом объеме памяти. Вот расширенный пример использования:

http://idontgetoutmuch.wordpress.com/2013/10/23/parking-in-westminster-an-analysis-in-haskell/

В случае repa, если вы добавляете строки в массив постепенно (что звучит так, как вы хотите), то можно надеяться, что использование пространства также будет увеличиваться постепенно. Это, безусловно, стоит эксперимента. И, возможно, также связаться с репа. Пожалуйста, сообщите о ваших результатах:-)

Я не уверен, что это на 100% применимо к accelerate или же repa, но вот один из способов, которыми я занимался для Vector в прошлом:

-- | A hopefully-efficient sink that incrementally grows a vector from the input stream
sinkVector :: (PrimMonad m, GV.Vector v a) => Int -> ConduitM a o m (Int, v a)
sinkVector by = do
    v <- lift $ GMV.new by
    go 0 v
  where
    -- i is the index of the next element to be written by go
    -- also exactly the number of elements in v so far
    go i v = do
        res <- await
        case res of
          Nothing -> do
            v' <- lift $ GV.freeze $ GMV.slice 0 i v
            return $! (i, v')
          Just x -> do
            v' <- case GMV.length v == i of
                    True -> lift $ GMV.grow v by
                    False -> return v
            lift $ GMV.write v' i x
            go (i+1) v'

Это в основном выделяет by пустые слоты и приступает к их заполнению. Как только он достигает потолка, он снова увеличивает основной вектор. Я ничего не тестировал, но на практике все работает нормально. Мне любопытно посмотреть, будут ли здесь другие более эффективные ответы.

Надеюсь, это поможет каким-то образом. Я вижу, что есть fromVector функция в repa и, возможно, это ваш золотой билет в сочетании с этим методом.

Другие вопросы по тегам